From b7293312bcd8a403bf762a99cb6871bdcf436f3a Mon Sep 17 00:00:00 2001 From: Matej Vela Date: Wed, 10 Feb 2010 10:48:47 +0100 Subject: [PATCH 1/1] Imported Upstream version 2.5.11 --- CHANGES | 702 ++ LICENSE | 281 + MODSECURITY_LICENSING_EXCEPTION | 137 + README.TXT | 17 + apache2/Makefile.in | 127 + apache2/Makefile.win | 73 + apache2/acmp.c | 810 ++ apache2/acmp.h | 125 + apache2/apache2.h | 108 + apache2/apache2_config.c | 2252 ++++++ apache2/apache2_io.c | 823 ++ apache2/apache2_util.c | 433 + apache2/api/README | 76 + apache2/api/mod_op_strstr.c | 171 + apache2/api/mod_tfn_reverse.c | 88 + apache2/api/mod_var_remote_addr_port.c | 99 + apache2/autogen.sh | 6 + apache2/build/apxs-wrapper.in | 15 + apache2/build/find_apr.m4 | 82 + apache2/build/find_apu.m4 | 82 + apache2/build/find_curl.m4 | 100 + apache2/build/find_lua.m4 | 184 + apache2/build/find_pcre.m4 | 81 + apache2/build/find_xml.m4 | 74 + apache2/build/install-sh | 224 + apache2/build/libtool.m4 | 7373 +++++++++++++++++ apache2/build/ltmain.sh | 8412 ++++++++++++++++++++ apache2/configure | 6499 +++++++++++++++ apache2/configure.in | 391 + apache2/mlogc-src/INSTALL | 76 + apache2/mlogc-src/Makefile.in | 70 + apache2/mlogc-src/Makefile.win | 57 + apache2/mlogc-src/mlogc-batch-load.pl.in | 151 + apache2/mlogc-src/mlogc-default.conf | 98 + apache2/mlogc-src/mlogc.c | 2059 +++++ apache2/mod_security2.c | 1158 +++ apache2/mod_security2_config.h.in | 139 + apache2/mod_security2_config.hw | 1 + apache2/modsecurity.c | 609 ++ apache2/modsecurity.h | 563 ++ apache2/modules.mk | 19 + apache2/msc_geo.c | 491 ++ apache2/msc_geo.h | 72 + apache2/msc_logging.c | 983 +++ apache2/msc_logging.h | 54 + apache2/msc_lua.c | 423 + apache2/msc_lua.h | 51 + apache2/msc_multipart.c | 1350 ++++ apache2/msc_multipart.h | 139 + apache2/msc_parsers.c | 334 + apache2/msc_parsers.h | 33 + apache2/msc_pcre.c | 121 + apache2/msc_pcre.h | 50 + apache2/msc_release.c | 42 + apache2/msc_release.h | 68 + apache2/msc_reqbody.c | 760 ++ apache2/msc_test.c | 920 +++ apache2/msc_util.c | 1399 ++++ apache2/msc_util.h | 104 + apache2/msc_xml.c | 139 + apache2/msc_xml.h | 49 + apache2/pdf_protect.c | 498 ++ apache2/pdf_protect.h | 29 + apache2/persist_dbm.c | 671 ++ apache2/persist_dbm.h | 32 + apache2/re.c | 2456 ++++++ apache2/re.h | 387 + apache2/re_actions.c | 2400 ++++++ apache2/re_operators.c | 2108 +++++ apache2/re_tfns.c | 778 ++ apache2/re_variables.c | 3140 ++++++++ apache2/t/csv_rx-pm.pl.in | 21 + apache2/t/gen_rx-pm.pl.in | 99 + apache2/t/op/beginsWith.t | 45 + apache2/t/op/contains.t | 73 + apache2/t/op/containsWord.t | 108 + apache2/t/op/endsWith.t | 52 + apache2/t/op/eq.t | 101 + apache2/t/op/ge.t | 93 + apache2/t/op/geoLookup.t | 44 + apache2/t/op/gt.t | 93 + apache2/t/op/inspectFile.t | 1 + apache2/t/op/le.t | 93 + apache2/t/op/lt.t | 93 + apache2/t/op/m.t | 52 + apache2/t/op/noMatch.t | 23 + apache2/t/op/pm.t | 112 + apache2/t/op/pmFromFile-01.dat | 4 + apache2/t/op/pmFromFile.t | 45 + apache2/t/op/rbl.t | 1 + apache2/t/op/rx.t | 62 + apache2/t/op/streq.t | 52 + apache2/t/op/unconditionalMatch.t | 23 + apache2/t/op/validateByteRange.t | 54 + apache2/t/op/validateDTD.t | 1 + apache2/t/op/validateSchema.t | 1 + apache2/t/op/validateUrlEncoding.t | 101 + apache2/t/op/validateUtf8Encoding.t | 260 + apache2/t/op/verifyCC.t | 514 ++ apache2/t/op/within.t | 52 + .../t/regression/action/00-disruptive-actions.t | 531 ++ apache2/t/regression/action/00-meta.t | 8 + apache2/t/regression/action/00-misc.t | 22 + apache2/t/regression/action/00-transformations.t | 8 + apache2/t/regression/action/10-append-prepend.t | 49 + apache2/t/regression/action/10-ctl.t | 56 + .../t/regression/action/10-detectiononly-actions.t | 545 ++ apache2/t/regression/action/10-logging.t | 246 + apache2/t/regression/config/00-load-modsec.t | 23 + apache2/t/regression/config/10-audit-directives.t | 264 + apache2/t/regression/config/10-debug-directives.t | 278 + apache2/t/regression/config/10-misc-directives.t | 148 + .../t/regression/config/10-request-directives.t | 548 ++ .../t/regression/config/10-response-directives.t | 174 + apache2/t/regression/config/20-chroot.t | 35 + apache2/t/regression/misc/00-multipart-parser.t | 485 ++ apache2/t/regression/misc/00-phases.t | 151 + apache2/t/regression/misc/10-tfn-cache.t | 189 + apache2/t/regression/misc/20-pdf-xss.t | 54 + apache2/t/regression/rule/00-basics.t | 91 + apache2/t/regression/rule/00-inheritance.t | 4 + apache2/t/regression/rule/00-script.t | 63 + apache2/t/regression/rule/10-xml.t | 419 + apache2/t/regression/rule/20-exceptions.t | 176 + .../server_root/conf/SoapEnvelope-bad.dtd | 8 + .../server_root/conf/SoapEnvelope-bad.xsd | 126 + .../t/regression/server_root/conf/SoapEnvelope.dtd | 8 + .../t/regression/server_root/conf/SoapEnvelope.xsd | 126 + .../t/regression/server_root/conf/httpd.conf.in | 37 + apache2/t/regression/server_root/conf/match.lua | 14 + apache2/t/regression/server_root/conf/test.lua | 14 + apache2/t/regression/server_root/htdocs/8k.txt | Bin 0 -> 8192 bytes apache2/t/regression/server_root/htdocs/index.html | 1 + apache2/t/regression/server_root/htdocs/test.pdf | Bin 0 -> 15406 bytes apache2/t/regression/server_root/htdocs/test.txt | 1 + apache2/t/regression/server_root/htdocs/test2.txt | 1 + apache2/t/regression/target/00-targets.t | 577 ++ apache2/t/run-regression-tests.pl.in | 779 ++ apache2/t/run-unit-tests.pl.in | 161 + apache2/t/tfn/base64Decode.t | 51 + apache2/t/tfn/base64Encode.t | 40 + apache2/t/tfn/compressWhitespace.t | 50 + apache2/t/tfn/cssDecode.t | 58 + apache2/t/tfn/escapeSeqDecode.t | 114 + apache2/t/tfn/hexDecode.t | 50 + apache2/t/tfn/hexEncode.t | 26 + apache2/t/tfn/htmlEntityDecode.t | 58 + apache2/t/tfn/jsDecode.t | 129 + apache2/t/tfn/length.t | 44 + apache2/t/tfn/lowercase.t | 40 + apache2/t/tfn/md5.t | 26 + apache2/t/tfn/normalisePath.t | 98 + apache2/t/tfn/normalisePathWin.t | 98 + apache2/t/tfn/parityEven7bit.t | 34 + apache2/t/tfn/parityOdd7bit.t | 34 + apache2/t/tfn/parityZero7bit.t | 33 + apache2/t/tfn/removeNulls.t | 62 + apache2/t/tfn/removeWhitespace.t | 43 + apache2/t/tfn/replaceComments.t | 155 + apache2/t/tfn/replaceNulls.t | 55 + apache2/t/tfn/sha1.t | 26 + apache2/t/tfn/trim.t | 68 + apache2/t/tfn/trimLeft.t | 69 + apache2/t/tfn/trimRight.t | 68 + apache2/t/tfn/urlDecode.t | 143 + apache2/t/tfn/urlDecodeUni.t | 235 + apache2/t/tfn/urlEncode.t | 129 + apache2/utf8tables.h | 818 ++ doc/apache_request_cycle-modsecurity.jpg | Bin 0 -> 92271 bytes doc/breach-logo-small.gif | Bin 0 -> 2389 bytes doc/html-multipage/actions.html | 345 + .../apache_request_cycle-modsecurity.jpg | Bin 0 -> 92271 bytes doc/html-multipage/ar01s02.html | 19 + doc/html-multipage/ar01s10.html | 14 + doc/html-multipage/ar01s11.html | 30 + doc/html-multipage/ar01s12.html | 45 + doc/html-multipage/breach-logo-small.gif | Bin 0 -> 2389 bytes doc/html-multipage/configuration-directives.html | 637 ++ doc/html-multipage/index.html | 6 + doc/html-multipage/installation.html | 65 + doc/html-multipage/introduction.html | 86 + doc/html-multipage/modsecurity-reference.css | 102 + doc/html-multipage/modsecurity.gif | Bin 0 -> 2585 bytes doc/html-multipage/operators.html | 150 + doc/html-multipage/processing-phases.html | 56 + doc/html-multipage/transformation-functions.html | 75 + doc/html-multipage/variables.html | 360 + doc/index.html | 35 + doc/migration-matrix.html | 74 + doc/migration-matrix.xml | 814 ++ doc/modsecurity-reference.css | 102 + doc/modsecurity.gif | Bin 0 -> 2585 bytes doc/modsecurity2-apache-reference.html | 1849 +++++ doc/modsecurity2-apache-reference.pdf | 7855 ++++++++++++++++++ doc/modsecurity2-apache-reference.xml | 6195 ++++++++++++++ doc/modsecurity2-data-formats.html | 315 + doc/modsecurity2-data-formats.pdf | 634 ++ doc/modsecurity2-data-formats.xml | 979 +++ modsecurity.conf-minimal | 60 + rules/CHANGELOG | 419 + rules/LICENSE | 339 + rules/README | 229 + .../base_rules/modsecurity_40_generic_attacks.data | 277 + .../modsecurity_41_sql_injection_attacks.data | 114 + .../modsecurity_46_et_sql_injection.data | 346 + rules/base_rules/modsecurity_46_et_web_rules.data | 55 + rules/base_rules/modsecurity_50_outbound.data | 91 + .../modsecurity_crs_20_protocol_violations.conf | 146 + .../modsecurity_crs_21_protocol_anomalies.conf | 73 + .../modsecurity_crs_23_request_limits.conf | 69 + .../base_rules/modsecurity_crs_30_http_policy.conf | 111 + .../base_rules/modsecurity_crs_35_bad_robots.conf | 31 + .../modsecurity_crs_40_generic_attacks.conf | 389 + .../modsecurity_crs_41_phpids_converter.conf | 54 + .../modsecurity_crs_41_phpids_filters.conf | 150 + .../modsecurity_crs_41_sql_injection_attacks.conf | 438 + .../base_rules/modsecurity_crs_41_xss_attacks.conf | 493 ++ rules/base_rules/modsecurity_crs_45_trojans.conf | 34 + .../modsecurity_crs_46_et_sql_injection.conf | 2346 ++++++ .../modsecurity_crs_46_et_web_rules.conf | 601 ++ .../modsecurity_crs_47_common_exceptions.conf | 28 + .../modsecurity_crs_48_local_exceptions.conf | 58 + .../base_rules/modsecurity_crs_49_enforcement.conf | 45 + rules/base_rules/modsecurity_crs_50_outbound.conf | 306 + .../base_rules/modsecurity_crs_60_correlation.conf | 43 + rules/modsecurity_crs_10_config.conf | 276 + rules/modsecurity_crs_10_global_config.conf | 64 + .../modsecurity_crs_20_protocol_violations.conf | 92 + .../modsecurity_crs_21_protocol_anomalies.conf | 67 + .../modsecurity_crs_40_generic_attacks.conf | 214 + .../modsecurity_crs_42_comment_spam.conf | 42 + .../modsecurity_crs_42_tight_security.conf | 27 + .../modsecurity_crs_55_marketing.conf | 21 + rules/util/httpd-guardian.pl | 518 ++ rules/util/modsec-clamscan.pl | 50 + rules/util/runav.pl | 40 + tools/README | 6 + tools/rules-updater-example.conf | 23 + tools/rules-updater.pl.in | 454 ++ 239 files changed, 96554 insertions(+) create mode 100644 CHANGES create mode 100644 LICENSE create mode 100644 MODSECURITY_LICENSING_EXCEPTION create mode 100644 README.TXT create mode 100644 apache2/.deps create mode 100644 apache2/Makefile.in create mode 100644 apache2/Makefile.win create mode 100644 apache2/acmp.c create mode 100644 apache2/acmp.h create mode 100644 apache2/apache2.h create mode 100644 apache2/apache2_config.c create mode 100644 apache2/apache2_io.c create mode 100644 apache2/apache2_util.c create mode 100644 apache2/api/README create mode 100644 apache2/api/mod_op_strstr.c create mode 100644 apache2/api/mod_tfn_reverse.c create mode 100644 apache2/api/mod_var_remote_addr_port.c create mode 100755 apache2/autogen.sh create mode 100755 apache2/build/apxs-wrapper.in create mode 100644 apache2/build/find_apr.m4 create mode 100644 apache2/build/find_apu.m4 create mode 100644 apache2/build/find_curl.m4 create mode 100644 apache2/build/find_lua.m4 create mode 100644 apache2/build/find_pcre.m4 create mode 100644 apache2/build/find_xml.m4 create mode 100755 apache2/build/install-sh create mode 100644 apache2/build/libtool.m4 create mode 100755 apache2/build/ltmain.sh create mode 100755 apache2/configure create mode 100644 apache2/configure.in create mode 100644 apache2/mlogc-src/INSTALL create mode 100755 apache2/mlogc-src/Makefile.in create mode 100755 apache2/mlogc-src/Makefile.win create mode 100755 apache2/mlogc-src/mlogc-batch-load.pl.in create mode 100644 apache2/mlogc-src/mlogc-default.conf create mode 100644 apache2/mlogc-src/mlogc.c create mode 100644 apache2/mod_security2.c create mode 100644 apache2/mod_security2_config.h.in create mode 100644 apache2/mod_security2_config.hw create mode 100644 apache2/modsecurity.c create mode 100644 apache2/modsecurity.h create mode 100644 apache2/modules.mk create mode 100644 apache2/msc_geo.c create mode 100644 apache2/msc_geo.h create mode 100644 apache2/msc_logging.c create mode 100644 apache2/msc_logging.h create mode 100644 apache2/msc_lua.c create mode 100644 apache2/msc_lua.h create mode 100644 apache2/msc_multipart.c create mode 100644 apache2/msc_multipart.h create mode 100644 apache2/msc_parsers.c create mode 100644 apache2/msc_parsers.h create mode 100644 apache2/msc_pcre.c create mode 100644 apache2/msc_pcre.h create mode 100644 apache2/msc_release.c create mode 100644 apache2/msc_release.h create mode 100644 apache2/msc_reqbody.c create mode 100644 apache2/msc_test.c create mode 100644 apache2/msc_util.c create mode 100644 apache2/msc_util.h create mode 100644 apache2/msc_xml.c create mode 100644 apache2/msc_xml.h create mode 100644 apache2/pdf_protect.c create mode 100644 apache2/pdf_protect.h create mode 100644 apache2/persist_dbm.c create mode 100644 apache2/persist_dbm.h create mode 100644 apache2/re.c create mode 100644 apache2/re.h create mode 100644 apache2/re_actions.c create mode 100644 apache2/re_operators.c create mode 100644 apache2/re_tfns.c create mode 100644 apache2/re_variables.c create mode 100644 apache2/t/action/.empty create mode 100755 apache2/t/csv_rx-pm.pl.in create mode 100755 apache2/t/gen_rx-pm.pl.in create mode 100644 apache2/t/op/beginsWith.t create mode 100644 apache2/t/op/contains.t create mode 100644 apache2/t/op/containsWord.t create mode 100644 apache2/t/op/endsWith.t create mode 100644 apache2/t/op/eq.t create mode 100644 apache2/t/op/ge.t create mode 100644 apache2/t/op/geoLookup.t create mode 100644 apache2/t/op/gt.t create mode 100644 apache2/t/op/inspectFile.t create mode 100644 apache2/t/op/le.t create mode 100644 apache2/t/op/lt.t create mode 100644 apache2/t/op/m.t create mode 100644 apache2/t/op/noMatch.t create mode 100644 apache2/t/op/pm.t create mode 100644 apache2/t/op/pmFromFile-01.dat create mode 100644 apache2/t/op/pmFromFile.t create mode 100644 apache2/t/op/rbl.t create mode 100644 apache2/t/op/rx.t create mode 100644 apache2/t/op/streq.t create mode 100644 apache2/t/op/unconditionalMatch.t create mode 100644 apache2/t/op/validateByteRange.t create mode 100644 apache2/t/op/validateDTD.t create mode 100644 apache2/t/op/validateSchema.t create mode 100644 apache2/t/op/validateUrlEncoding.t create mode 100644 apache2/t/op/validateUtf8Encoding.t create mode 100644 apache2/t/op/verifyCC.t create mode 100644 apache2/t/op/within.t create mode 100644 apache2/t/regression/action/00-disruptive-actions.t create mode 100644 apache2/t/regression/action/00-meta.t create mode 100644 apache2/t/regression/action/00-misc.t create mode 100644 apache2/t/regression/action/00-transformations.t create mode 100644 apache2/t/regression/action/10-append-prepend.t create mode 100644 apache2/t/regression/action/10-ctl.t create mode 100644 apache2/t/regression/action/10-detectiononly-actions.t create mode 100644 apache2/t/regression/action/10-logging.t create mode 100644 apache2/t/regression/config/00-load-modsec.t create mode 100644 apache2/t/regression/config/10-audit-directives.t create mode 100644 apache2/t/regression/config/10-debug-directives.t create mode 100644 apache2/t/regression/config/10-misc-directives.t create mode 100644 apache2/t/regression/config/10-request-directives.t create mode 100644 apache2/t/regression/config/10-response-directives.t create mode 100644 apache2/t/regression/config/20-chroot.t create mode 100644 apache2/t/regression/misc/00-multipart-parser.t create mode 100644 apache2/t/regression/misc/00-phases.t create mode 100644 apache2/t/regression/misc/10-tfn-cache.t create mode 100644 apache2/t/regression/misc/20-pdf-xss.t create mode 100644 apache2/t/regression/rule/00-basics.t create mode 100644 apache2/t/regression/rule/00-inheritance.t create mode 100644 apache2/t/regression/rule/00-script.t create mode 100644 apache2/t/regression/rule/10-xml.t create mode 100644 apache2/t/regression/rule/20-exceptions.t create mode 100644 apache2/t/regression/server_root/conf/SoapEnvelope-bad.dtd create mode 100644 apache2/t/regression/server_root/conf/SoapEnvelope-bad.xsd create mode 100644 apache2/t/regression/server_root/conf/SoapEnvelope.dtd create mode 100644 apache2/t/regression/server_root/conf/SoapEnvelope.xsd create mode 100644 apache2/t/regression/server_root/conf/httpd.conf.in create mode 100644 apache2/t/regression/server_root/conf/match.lua create mode 100644 apache2/t/regression/server_root/conf/test.lua create mode 100644 apache2/t/regression/server_root/data/.empty create mode 100644 apache2/t/regression/server_root/htdocs/8k.txt create mode 100644 apache2/t/regression/server_root/htdocs/index.html create mode 100644 apache2/t/regression/server_root/htdocs/test.pdf create mode 100644 apache2/t/regression/server_root/htdocs/test.txt create mode 100644 apache2/t/regression/server_root/htdocs/test2.txt create mode 100644 apache2/t/regression/server_root/logs/audit/.empty create mode 100644 apache2/t/regression/server_root/logs/subdir/.empty create mode 100644 apache2/t/regression/server_root/tmp/.empty create mode 100644 apache2/t/regression/server_root/upload/.empty create mode 100644 apache2/t/regression/target/00-targets.t create mode 100755 apache2/t/run-regression-tests.pl.in create mode 100755 apache2/t/run-unit-tests.pl.in create mode 100644 apache2/t/tfn/base64Decode.t create mode 100644 apache2/t/tfn/base64Encode.t create mode 100644 apache2/t/tfn/compressWhitespace.t create mode 100644 apache2/t/tfn/cssDecode.t create mode 100644 apache2/t/tfn/escapeSeqDecode.t create mode 100644 apache2/t/tfn/hexDecode.t create mode 100644 apache2/t/tfn/hexEncode.t create mode 100644 apache2/t/tfn/htmlEntityDecode.t create mode 100644 apache2/t/tfn/jsDecode.t create mode 100644 apache2/t/tfn/length.t create mode 100644 apache2/t/tfn/lowercase.t create mode 100644 apache2/t/tfn/md5.t create mode 100644 apache2/t/tfn/normalisePath.t create mode 100644 apache2/t/tfn/normalisePathWin.t create mode 100644 apache2/t/tfn/parityEven7bit.t create mode 100644 apache2/t/tfn/parityOdd7bit.t create mode 100644 apache2/t/tfn/parityZero7bit.t create mode 100644 apache2/t/tfn/removeNulls.t create mode 100644 apache2/t/tfn/removeWhitespace.t create mode 100644 apache2/t/tfn/replaceComments.t create mode 100644 apache2/t/tfn/replaceNulls.t create mode 100644 apache2/t/tfn/sha1.t create mode 100644 apache2/t/tfn/trim.t create mode 100644 apache2/t/tfn/trimLeft.t create mode 100644 apache2/t/tfn/trimRight.t create mode 100644 apache2/t/tfn/urlDecode.t create mode 100644 apache2/t/tfn/urlDecodeUni.t create mode 100644 apache2/t/tfn/urlEncode.t create mode 100644 apache2/utf8tables.h create mode 100644 doc/apache_request_cycle-modsecurity.jpg create mode 100644 doc/breach-logo-small.gif create mode 100644 doc/html-multipage/actions.html create mode 100644 doc/html-multipage/apache_request_cycle-modsecurity.jpg create mode 100644 doc/html-multipage/ar01s02.html create mode 100644 doc/html-multipage/ar01s10.html create mode 100644 doc/html-multipage/ar01s11.html create mode 100644 doc/html-multipage/ar01s12.html create mode 100644 doc/html-multipage/breach-logo-small.gif create mode 100644 doc/html-multipage/configuration-directives.html create mode 100644 doc/html-multipage/index.html create mode 100644 doc/html-multipage/installation.html create mode 100644 doc/html-multipage/introduction.html create mode 100644 doc/html-multipage/modsecurity-reference.css create mode 100644 doc/html-multipage/modsecurity.gif create mode 100644 doc/html-multipage/operators.html create mode 100644 doc/html-multipage/processing-phases.html create mode 100644 doc/html-multipage/transformation-functions.html create mode 100644 doc/html-multipage/variables.html create mode 100644 doc/index.html create mode 100644 doc/migration-matrix.html create mode 100644 doc/migration-matrix.xml create mode 100644 doc/modsecurity-reference.css create mode 100644 doc/modsecurity.gif create mode 100644 doc/modsecurity2-apache-reference.html create mode 100644 doc/modsecurity2-apache-reference.pdf create mode 100644 doc/modsecurity2-apache-reference.xml create mode 100644 doc/modsecurity2-data-formats.html create mode 100644 doc/modsecurity2-data-formats.pdf create mode 100644 doc/modsecurity2-data-formats.xml create mode 100644 modsecurity.conf-minimal create mode 100644 rules/CHANGELOG create mode 100644 rules/LICENSE create mode 100644 rules/README create mode 100644 rules/base_rules/modsecurity_40_generic_attacks.data create mode 100644 rules/base_rules/modsecurity_41_sql_injection_attacks.data create mode 100644 rules/base_rules/modsecurity_46_et_sql_injection.data create mode 100644 rules/base_rules/modsecurity_46_et_web_rules.data create mode 100644 rules/base_rules/modsecurity_50_outbound.data create mode 100644 rules/base_rules/modsecurity_crs_20_protocol_violations.conf create mode 100644 rules/base_rules/modsecurity_crs_21_protocol_anomalies.conf create mode 100644 rules/base_rules/modsecurity_crs_23_request_limits.conf create mode 100644 rules/base_rules/modsecurity_crs_30_http_policy.conf create mode 100644 rules/base_rules/modsecurity_crs_35_bad_robots.conf create mode 100644 rules/base_rules/modsecurity_crs_40_generic_attacks.conf create mode 100644 rules/base_rules/modsecurity_crs_41_phpids_converter.conf create mode 100644 rules/base_rules/modsecurity_crs_41_phpids_filters.conf create mode 100644 rules/base_rules/modsecurity_crs_41_sql_injection_attacks.conf create mode 100644 rules/base_rules/modsecurity_crs_41_xss_attacks.conf create mode 100644 rules/base_rules/modsecurity_crs_45_trojans.conf create mode 100644 rules/base_rules/modsecurity_crs_46_et_sql_injection.conf create mode 100644 rules/base_rules/modsecurity_crs_46_et_web_rules.conf create mode 100644 rules/base_rules/modsecurity_crs_47_common_exceptions.conf create mode 100644 rules/base_rules/modsecurity_crs_48_local_exceptions.conf create mode 100644 rules/base_rules/modsecurity_crs_49_enforcement.conf create mode 100644 rules/base_rules/modsecurity_crs_50_outbound.conf create mode 100644 rules/base_rules/modsecurity_crs_60_correlation.conf create mode 100644 rules/modsecurity_crs_10_config.conf create mode 100644 rules/modsecurity_crs_10_global_config.conf create mode 100644 rules/optional_rules/modsecurity_crs_20_protocol_violations.conf create mode 100644 rules/optional_rules/modsecurity_crs_21_protocol_anomalies.conf create mode 100644 rules/optional_rules/modsecurity_crs_40_generic_attacks.conf create mode 100644 rules/optional_rules/modsecurity_crs_42_comment_spam.conf create mode 100644 rules/optional_rules/modsecurity_crs_42_tight_security.conf create mode 100644 rules/optional_rules/modsecurity_crs_55_marketing.conf create mode 100755 rules/util/httpd-guardian.pl create mode 100755 rules/util/modsec-clamscan.pl create mode 100755 rules/util/runav.pl create mode 100644 tools/README create mode 100644 tools/rules-updater-example.conf create mode 100644 tools/rules-updater.pl.in diff --git a/CHANGES b/CHANGES new file mode 100644 index 0000000..1bf685b --- /dev/null +++ b/CHANGES @@ -0,0 +1,702 @@ +04 Nov 2009 - 2.5.11 +-------------------- + + * Added a new multipart flag, MULTIPART_INVALID_QUOTING, which will be + set true if any invalid quoting is found during multipart parsing. + + * Fixed parsing quoted strings in multipart Content-Disposition headers. + Discovered by Stefan Esser. + + * Cleanup persistence database locking code. + + * Added warning during configure if libcurl is found linked against + gnutls for SSL. The openssl lib is recommended as gnutls has + proven to cause issues with mutexes and may crash. + + * Cleanup some mlogc (over)logging. + + * Do not log output filter errors in the error log. + + * Moved output filter to run before other stock filters (mod_deflate, + mod_cache, mod_expires, mod_filter) to avoid analyzing modified data + in the response. Patch originally submitted by Ivan Ristic. + + +18 Sep 2009 - 2.5.10 +-------------------- + + * Cleanup mlogc so that it builds on Windows. + + * Added more detailed messages to replace "Unknown error" in filters. + + * Added SecAuditLogDirMode and SecAuditLogFileMode to allow fine tuning + auditlog permissions (especially with mpm-itk). + + * Cleanup SecUploadFileMode implementation. + + * Cleanup build scripts. + + * Fixed crash on configuration if SecMarker is used before any rules. + + * Fixed SecRuleUpdateActionById so that it will work on chain starters. + + * Cleanup build system for mlogc. + + * Allow mlogc to periodically flush memory pools. + + * Using nolog,auditlog will now log the "Message:" line to the auditlog, but + nothing to the error log. Prior versions dropped the "Message:" line from + both logs. To do this now, just use "nolog" or "nolog,noauditlog". + + * Forced mlogc to use SSLv3 to avoid some potential auto negotiation + issues with some libcurl versions. + + * Fixed mlogc issue seen on big endian machines where content type + could be listed as zero. + + * Removed extra newline from audit log message line when logging XML errors. + This was causing problems parsing audit logs. + + * Fixed @pm/@pmFromFile case insensitivity. + + * Truncate long parameters in log message for "Match of ... against ... + required" messages. + + * Correctly resolve chained rule actions in logs. + + * Cleanup some code for portability. + + * AIX does not support hidden visibility with xlc compiler. + + * Allow specifying EXTRA_CFLAGS during configure to override gcc specific + values for non-gcc compilers. + + * Populate GEO:COUNTRY_NAME and GEO:COUNTRY_CONTINENT as documented. + + * Handle a newer geo database more gracefully, avoiding a potential crash for + new countries that ModSecurity is not yet aware. + + * Allow checking &GEO "@eq 0" for a failed @geoLookup. + + * Fixed mlogc global mutex locking issue and added more debugging output. + + * Cleaned up build dependencies and configure options. + + +05 Mar 2009 - 2.5.9 +------------------- + + * Fixed parsing multipart content with a missing part header name which + would crash Apache. Discovered by "Internet Security Auditors" + (isecauditors.com). + + * Added ability to specify the config script directly using --with-apr + and --with-apu. + + * Updated copyright year to 2009. + + * Added macro expansion for append/prepend action. + + * Fixed race condition in concurrent updates of persistent counters. Updates + are now atomic. + + * Cleaned up build, adding an option for verbose configure output and making + the mlogc build more portable. + + +21 Nov 2008 - 2.5.8 +------------------- + + * Fixed PDF XSS issue where a non-GET request for a PDF file would crash the + Apache httpd process. Discovered by Steve Grubb at Red Hat. + + * Removed an invalid "Internal error: Issuing "%s" for unspecified error." + message that was logged when denying with nolog/noauditlog set and + causing the request to be audited. + + +24 Sep 2008 - 2.5.7 +------------------- + + * Fixed XML DTD/Schema validation which will now fail after request body + processing errors, even if the XML parser returns a document tree. + + * Added ctl:forceRequestBodyVariable=on|off which, when enabled, will force + the REQUEST_BODY variable to be set when a request body processor is not set. + Previously the REQUEST_BODY target was only populated by the URLENCODED + request body processor. + + * Integrated mlogc source. + + * Fixed logging the hostname in the error_log which was logging the + request hostname instead of the Apache resolved hostname. + + * Allow for disabling request body limit checks in phase:1. + + * Added transformations for processing parity for legacy protocols ported + to HTTP(S): t:parityEven7bit, t:parityOdd7bit, t:parityZero7bit + + * Added t:cssDecode transformation to decode CSS escapes. + + * Now log XML parsing/validation warnings and errors to be in the debug log + at levels 3 and 4, respectivly. + + +31 Jul 2008 - 2.5.6 +------------------- + + * Transformation caching has been deprecated, and is now off by default. We + now advise against using transformation caching in production. + + * Fixed two separate transformation caching issues that could cause incorrect + content inspection in some circumstances. + + * Fixed an issue with the transformation cache using too much RAM, potentially + crashing Apache with a large number of cache entries. Two new configuration + options have been added to allow for a finer control of caching: + + maxitems: Max number of items to cache (default 1024) + incremental: Whether to cache incrementally (default off) + + * Added an experimental regression testing suite. The regression suite may + be executed via "make test-regression", however it is strongly advised + to only be executed on a non-production machine as it will startup the + Apache web server that ModSecurity is compiled against with various + configurations in which it will run tests. + + * Added a licensing exception so that ModSecurity can be used in a derivative + work when that derivative is also under an approved open source license. + + * Updated mlogc to version 1.4.5 which adds a LockFile directive and fixes an + issue in which the configuration file may be deleted. + + +05 Jun 2008 - 2.5.5 +------------------- + + * Fixed an issue where an alert was not logged in the error log + unless "auditlog" was used. + + * Enable the "auditlog" action by default to help prevent a misconfiguration. + The new default is now: "phase:2,log,auditlog,pass" + + * Improve request body processing error messages. + + * Handle lack of a new line after the final boundary in a multipart request. + This fixes the reported WordPress Flash file uploader problem. + + * Fixed issue with multithreaded servers where concurrent XML processing + could crash the web server (at least under Windows). + + * Fixed blocking in phase 3. + + * Force modules "mod_rpaf-2.0.c" and "mod_custom_header.c" to run before + ModSecurity so that the correct IP is used. + + +07 May 2008 - 2.5.4 +------------------- + + * Fixed issue where transformation cache was using the SecDefaultAction + value even when t:none was used within a rule. + + +24 Apr 2008 - 2.5.3 +------------------- + + * Fixed issue where the exec action may not be able to execute shell scripts. + + * Macros are now expanded in expirevar and deprecatevar. + + * Fixed crash if a persistent variable name was more than 126 characters. + + * Updated included Core Ruleset to version 1.6.1 which fixes some + false negative issues in the migration to using some 2.5 features. + + +02 Apr 2008 - 2.5.2 +------------------- + + * Allow HTTP_* targets as an alias for REQUEST_HEADERS:*. + + * Make sure temporary filehandles are closed after a transaction. + + * Make sure the apache include directory is included during build. + + +02 Apr 2008 - 2.1.7 +------------------- + + * Make sure temporary filehandles are closed after a transaction. + + +14 Mar 2008 - 2.5.1 +------------------- + + * Fixed an issue where a match would not occur if transformation caching + was enabled. + + * Using "severity" in a default action is now just a warning. + + * Cleaned up the "make test" target to better locate headers/libraries. + + * Now search /usr/lib64 and /usr/lib32 for lua libs. + + * No longer treat warnings as errors by default (use --enable-strict-compile). + + +19 Feb 2008 - 2.5.0 +------------------- + + * Updated included Core Ruleset to version 1.6.0 which uses 2.5 features. + + * Cleaned up and clarified some documentation. + + * Updated code to be more portable so it builds with MS VC++. + + * Added unit tests for most operators and transformations. + + * Fixed crash on startup when ENV is improperly used without a parameter. + + * Allow macro resolution in setenv action. + + * The default action is now a minimal "phase:2,log,pass" with no default + transformations performed. + + * Implemented SecUploadFileMode to allow setting the mode for uploaded files. + + * Implemented "block" action. + + * Implemented SecRuleUpdateActionById. + + * Fixed removal of phase 5 rules via SecRuleRemoveBy* directives. + + * No longer log the query portion of the URI in the error log as + it may contain sensitive data. + + * Build is now 'configure' based: ./configure && make && make install + + * Added support for Lua scripting in the following ways: SecRuleScript + can be used to specify a script to execute as a rule, the exec + action processes Lua scripts internally, as does the @inspectFile + operator. Refer to the documentation for more details. + + * Changed how allow works. Used on its own it now allows phases 1-4. Used + with parameter "phase" (e.g. SecAction allow:phase) it only affects + the current phase. Used with parameter "request" it allows phases + 1-2. + + * Fixed issue where only the first phase 5 rule would run when the + request was intercepted in an earlier phase. + + * Stricter configuration parsing. Disruptive actions, meta actions and + phases are no longer allowed in a chained rule. Disruptive actions, + are no longer allowed in a logging phase (phase 5) rule, including + inheriting from SecDefaultAction. + + * More efficient collection persistance. + + * Fixed t:escapeSeqDecode to better follow ANSI C escapes. + + * Added t:jsDecode to decode JavScript escape sequences. + + * Added IS_NEW built-in collection variables. + + * New audit log part 'K' logs all matching rules. + + * Implemented SecRequestBodyNoFilesLimit. + + * Enhance handling of the case where we run out of disk space while + writing to audit log entry. + + * Added SecComponentSignature to allow other components the ability + to append to the logged signature. + + * Added skipAfter: action to allow skipping all rules until a rule + with a specified ID is reached. Rule execution then continues after + the specified rule. + + * Added SecMarker directive to allow a fixed target for skipAfter. + + * Added ctl:ruleRemoveById action to allow rule removal on a match. + + * Added a @containsWord operator that will match a given string anywhere in + the target value, but only on word boundaries. + + * Added a MATCHED_VAR_NAME variable to store the last matched variable name + so that it can be more easily used by rules. + + * Added a MATCHED_VAR variable to store the last matched variable value + so that it can be more easily used by rules. + + * Fixed expansion of macros when using relative changes with setvar. In + addition, added support for expanding macros in the variable name. + + * Situations where ModSecurity will intercept, generate an error or log + a level 1-3 message to the debug log are now marked as 'relevant' and may + generate an audit log entry. + + * Fixed deprecatevar:var=N/S action so that it decrements N every S seconds + as documented instead of decrementing by a rate. + + * Enable ModSecurity to look at partial response bodies. In previous + versions, ModSecurity would respond with status code 500 when the + response body was too long. Now, if SecResponseBodyLimitAction is + set to "ProcessPartial", it will process the part of the response + body received up until that point but send the rest without buffering. + + * ModSecurity will now process phases 3 and 4 even when request processing + is interrupted (either by Apache - e.g. by responding with 400, 401 + or 403, or by ModSecurity itself). + + * Fixed the base64decode transformation function to not return extra + characters at the end. + + * Return from the output filter with an error in addition to setting + up the HTTP error status in the output data. + + * Used new Apache API calls to get the server version/banner when available. + + * Added "logdata" meta action to allow logging of raw transaction data. + + * Added TX_SEVERITY that keeps track of the highest severity + for any matched rules so far. + + * Added ARGS_GET, ARGS_POST, ARGS_GET_NAMES, ARGS_POST_NAMES variables to + allow seperation of GET and POST arguments. + + * Added an Apache define (MODSEC_2.5) so that you can conditionally include + directives based on the ModSecurity major/minor versions with IfDefine. + + * Added MODSEC_BUILD variable that contains the numeric build value based + on the ModSecurity version. + + * Enhanced debug logging by displaying more data on rule execution. All + invoked rules are now logged in the debug log at level 5. + + * Stricter validation for @validateUtf8Encoding. + + * No longer process Apache internal subrequests. + + * Fixed warnings on Solaris and/or 64bit builds. + + * Added @within string comparison operator with support for macro expansion. + + * Do not trigger "pause" action for internal requests. + + * Added matching rule filename and line number to audit log. + + * Added new phrase matching operators, @pm and @pmFromFile. These use + an alternate set based matching engine (Aho-Corasick) to perform faster + phrase type matches such as black/white lists, spam keywords, etc. + + * Allow caching transformations per-request/phase so they are not repeated. + + * Added Solaris and Cygwin to the list of platforms not supporting the hidden + visibility attribute. + + * Fixed decoding full-width unicode in t:urlDecodeUni. + + * Add SecGeoLookupDB, @geoLookups and GEO collection to support + geographical lookups by IP/host. + + * Do not try to intercept a request after a failed rule. This fixes the + issue associated with an "Internal Error: Asked to intercept request + but was_intercepted is zero" error message. + + * Removed extraneous exported symbols. + + * Merged the PDF XSS protection functionality into ModSecurity. + + * Exported API for registering custom variables. Example in api directory. + + * Added experimental support for content injection. Directive + SecContentInjection (On|Off) controls whether injection is taking place. + Actions "prepend" and "append" inject content when executed. Do note that + it is your responsibility to make sure the response is of the appropriate + content type (e.g. HTML, plain text, etc). + + * Added string comparison operators with support for macro expansion: + @contains, @streq, @beginsWith and @endsWith. + + * Enhanced debug log output to log macro expansion, quote values and + correctly display values that contained NULs. + + * Removed support for %0 - %9 capture macros as they were incorrectly + expanding url encoded values. Use %{TX.0} - %{TX.9} instead. + + * Added t:length to transform a value to its character length. + + * Added t:trimLeft, t:trimRight, t:trim to remove whitespace + from a value on the left, right or both. + + * Added SecAuditLog2 directive to allow redundent concurrent audit log + index files. This will allow sending audit data to two consoles, etc. + + * Removed CGI style HTTP_* variables in favor of REQUEST_HEADERS:Header-Name. + + * Store filename/line for each rule and display it and the ID (if available) + in the debug log when invoking a rule. Thanks to Christian Bockermann + for the idea. + + * Do not log 'allow' action as intercepted in the debug log. + + * Fixed some collection variable names not printing with the parameter + and/or counting operator in the debug log. + + +19 Feb 2008 - 2.1.6 +------------------- + + * Fixed crash on startup when ENV is improperly used without a parameter. + + * Allow macro resolution in setenv action. + + * Implemented SecUploadFileMode to allow setting the mode for uploaded files. + + * No longer log the query portion of the URI in the error log as + it may contain sensitive data. + + +10 Jan 2008 - 2.1.5 +------------------- + + * Updated included Core Ruleset to version 1.5.1. + + * Phase 5 rules can now be removed via SecRuleRemoveBy* directives. + + * Fixed issue where only the first phase 5 rule would run when the + request was intercepted in an earlier phase. + + * Fixed configuration parsing so that disruptive actions, meta actions + and phases are not allowed in a chained rule (as originally intended). + + * Fixed t:escapeSeqDecode to better follow ANSI C escapes. + + +27 Nov 2007 - 2.1.4 +------------------- + + * Updated included Core Ruleset to version 1.5 and noted in the docs that + XML support is required to use the rules without modification. + + * Fixed an evasion FP, mistaking a multipart non-boundary for a boundary. + + * Fixed multiple warnings on Solaris and/or 64bit builds. + + * Do not process subrequests in phase 2-4, but do hand off the request data. + + * Fixed a blocking FP in the multipart parser, which affected Safari. + + +11 Sep 2007 - 2.1.3 +------------------- + + * Updated multipart parsing code adding variables to allow checking + for various parsing issues (request body abnormalities). + + * Allow mod_rpaf and mod_extract_forwarded2 to work before ModSecurity. + + * Quiet some compiler warnings. + + * Do not block internal ErrorDocument requests after blocking request. + + * Added ability to compile without an external API (use -DNO_MODSEC_API). + + +27 Jul 2007 - 2.1.2 +------------------- + + * Cleaned up and clarified some documentation. + + * Update included core rules to latest version (1.4.3). + + * Enhanced ability to alert/audit failed requests. + + * Do not trigger "pause" action for internal requests. + + * Fixed issue with requests that use internal requests. These had the + potential to be intercepted incorrectly when other Apache httpd modules + that used internal requests were used with mod_security. + + * Added Solaris and Cygwin to the list of platforms not supporting the hidden + visibility attribute. + + * Fixed decoding full-width unicode in t:urlDecodeUni. + + * Lessen some overhead of debugging messages and calculations. + + * Do not try to intercept a request after a failed rule. This fixes the + issue associated with an "Internal Error: Asked to intercept request + but was_intercepted is zero" error message. + + * Added SecAuditLog2 directive to allow redundent concurrent audit log + index files. This will allow sending audit data to two consoles, etc. + + * Small performance improvement in memory management for rule execution. + + +11 Apr 2007 - 2.1.1 +------------------- + + * Add the PCRE_DOLLAR_ENDONLY option when compiling regular expression + for the @rx operator and variables. + + * Really set PCRE_DOTALL option when compiling the regular expression + for the @rx operator as the docs state. + + * Fixed potential memory corruption when expanding macros. + + * Fixed error when a collection was retrieved from storage in the same second + as creation by setting the rate to zero. + + * Fixed ASCIIZ (NUL) parsing for application/x-www-form-urlencoded forms. + + * Fixed the faulty REQUEST_FILENAME variable, which used to change + the internal Apache structures by mistake. + + * Updates to quiet some compiler warnings. + + * Fixed some casting issues for compiling on NetWare (patch from Guenter Knauf). + + +23 Feb 2007 - 2.1.0 +------------------- + + * Removed the "Connection reset by peer" message, which has nothing + to do with us. Actually the message was downgraded from ERROR to + NOTICE so it will still appear in the debug log. + + * Removed the (harmless) message mentioning LAST_UPDATE_TIME missing. + + * It was not possible to remove a rule placed in phase 4 using + SecRuleRemoveById or SecRuleRemoveByMsg. Fixed. + + * Fixed a problem with incorrectly setting requestBodyProcessor using + the ctl action. + + * Bundled Core Rules 2.1-1.3.2b4. + + * Updates to the reference manual. + + * Reversed the return values of @validateDTD and @validateSchema, to + make them consistent with other operators. + + * Added a few helpful debug messages in the XML validation area. + + * Updates to the reference manual. + + * Fixed the validateByteRange operator. + + * Default value for the status action is now 403 (as it was supposed to + be but it was effectively 500). + + * Rule exceptions (removing using an ID range or an regular expression) + is now applied to the current context too. (Previously it only worked + on rules that are inherited from the parent context.) + + * Fix of a bug with expired variables. + + * Fixed regular expression variable selectors for many collections. + + * Performance improvements - up to two times for real-life work loads! + + * Memory consumption improvements (not measured but significant). + + * The allow action did not work in phases 3 and 4. Fixed. + + * Unlocked collections GLOBAL and RESOURCE. + + * Added support for variable expansion in the msg action. + + * New feature: It is now possible to make relative changes to the + audit log parts with the ctl action. For example: "ctl:auditLogParts=+E". + + * New feature: "tag" action. To be used for event categorisation. + + * XML parser was not reporting errors that occured at the end + of XML payload. + + * Files were not extracted from request if SecUploadKeepFiles was + Off. Fixed. + + * Regular expressions that are too long are truncated to 256 + characters before used in error messages. (In order to keep + the error messages in the log at a reasonable size.) + + * Fixed the sha1 transformation function. + + * Fixed the skip action. + + * Fixed REQUEST_PROTOCOL, REMOTE_USER, and AUTH_TYPE. + + * SecRuleEngine did not work in child configuration contexts + (e.g. ). + + * Fixed base64Decode and base64Encode. + + +15 Nov 2006 - 2.0.4 +------------------- + + * Fixed the "deprecatevar" action. + + * Decreasing variable values did not work. + + * Made "nolog" do what it is supposed to do - cause a rule match to + not be logged. Also "nolog" now implies "noauditlog" but it's + possible to follow "nolog" with "auditlog" and have the match + not logged to the error log but logged to the auditlog. (Not + something that strikes me as useful but it's possible.) + + * Relative paths given to SecDataDir will now be treated as relative + to the Apache server root. + + * Added checks to make sure only correct actions are specified in + SecDefaultAction (some actions are required, some don't make any + sense) and in rules that are not chain starters (same). This should + make the unhelpful "Internal Error: Failed to add rule to the ruleset" + message go away. + + * Fixed the problem when "SecRuleInheritance Off" is used in a context + with no rules defined. + + * Fixed a problem of lost input (request body) data on some redirections, + for example when mod_rewrite is used. + + +26 Oct 2006 - 2.0.3 +------------------- + + * Fixed a memory leak (all platforms) and a concurrency control + problem that could cause a crash (multithreaded platforms only). + + * Fixed a SecAuditLogRelevantStatus problem, which would not work + properly unless the regular expression contained a subexpression. + + +19 Oct 2006 - 2.0.2 +------------------- + + * Fixed incorrect permissions on the global mutex, which prevented + the mutex from working properly. + + * Fixed incorrect actionset merging where the status was copied from + the child actionset even though it was not defined. + + * Fixed missing metadata information (in the logs) for warnings. + + +16 Oct 2006 - 2.0.1 +------------------- + + * Rules that used operator negation did not work. Fixed. + + * Fixed bug that prevented invalid regular expressions from being reported. + + +16 Oct 2006 - 2.0.0 +------------------- + + * First stable 2.x release. + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..0cd26d5 --- /dev/null +++ b/LICENSE @@ -0,0 +1,281 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + diff --git a/MODSECURITY_LICENSING_EXCEPTION b/MODSECURITY_LICENSING_EXCEPTION new file mode 100644 index 0000000..1e99ad2 --- /dev/null +++ b/MODSECURITY_LICENSING_EXCEPTION @@ -0,0 +1,137 @@ + +MODSECURITY LICENSING EXCEPTION +=============================== + +Version 1.0, 29 July 2008 + +As a special exception ("Exception") to the terms and conditions of version 2 +of the GPL, Breach Security, Inc. hereby grants you the rights described +below, provided you agree to the terms and conditions in this Exception, +including its obligations and restrictions on use. + + +Exception Intent +================ + +We want specified Free/Libre and Open Source Software ("FLOSS") programs to be +able to use ModSecurity (the "Program") despite the fact that not all FLOSS +licenses are compatible with version 2 of the GNU General Public License (the +"GPLv2"). + + +Legal Terms and Conditions +========================== + +You are free to distribute a Derivative Work that is formed entirely from the +Program and one or more works (each, a "FLOSS Work") licensed under one or +more of the licenses listed below in section 1, as long as all of the +following conditions are met: + + 1. You obey the GPLv2 in all respects for the Program and the Derivative + Work, except for identifiable sections of the Derivative Work which are + + 1. not derived from the Program, and + + 2. are not designed to interact with the Program, and + + 3. which can reasonably be considered independent and separate works in + themselves. + + 2. All such identifiable sections of the Derivative Work are + + 1. distributed subject to one of the FLOSS licenses listed below, and + + 2. the object code or executable form of those sections are accompanied + by the complete corresponding machine-readable source code for those + sections on the same medium and under the same FLOSS license as the + corresponding object code or executable forms of those sections. + + 3. Any works which are aggregated with the Program or with a Derivative Work + on a volume of a storage or distribution medium in accordance with the + GPLv2, can reasonably be considered independent and separate works in + themselves which are not derivatives of either the Program, a Derivative + Work or a FLOSS Work, and are not designed to interact with the Program. + +If the above conditions are not met, then the Program may only be copied, +modified, distributed or used under the terms and conditions of the GPLv2 +or another valid licensing option from Breach Security, Inc. + + +FLOSS License List +================== + +License name Version(s)/Copyright Date +----------------------------------------------------------------------- +Academic Free License 2.0 +Apache Software License 1.0/1.1/2.0 +Apple Public Source License 2.0 +Artistic license From Perl 5.8.0 +BSD license "July 22 1999" +Common Development and Distribution License (CDDL) 1.0 +Common Public License 1.0 +Eclipse Public License 1.0 +GNU Library or "Lesser" General Public License (LGPL) 2.0/2.1/3.0 +Jabber Open Source License 1.0 +MIT License (As listed in file MIT-License.txt) - +Mozilla Public License (MPL) 1.0/1.1 +Open Software License 2.0 +OpenSSL license (with original SSLeay license) "2003" ("1998") +PHP License 3.0 +Python license (CNRI Python License) - +Python Software Foundation License 2.1.1 +Sleepycat License "1999" +University of Illinois/NCSA Open Source License - +W3C License "2001" +X11 License "2001" +Zlib/libpng License - +Zope Public License 2.0 + +Due to the many variants of some of the above licenses, we require that for +any version of the listed FLOSS licenses to qualify under this exception, it +must follow the 2003 version of the Free Software Foundation's Free Software +Definition (http://www.gnu.org/philosophy/free-sw.html) or version 1.9 of the +Open Source Definition by the Open Source Initiative +(http://www.opensource.org/docs/definition.php). + + +Definitions +=========== + +1. Terms used, but not defined, herein shall have the meaning provided in the + version 2 of the GPL. + +2. Derivative Work means a derivative work under copyright law. + + +Applicability +============= + +This Exception applies to all Programs that contain a notice placed by Breach +Security, Inc. saying that the Program may be distributed under the terms of +this Exception. If you create or distribute a work which is a Derivative Work +of both the Program and any other work licensed under the GPL, then this FLOSS +Exception is not available for that work; thus, you must remove the FLOSS +Exception notice from that work and comply with the GPL in all respects, +including by retaining all GPL notices. + +You may choose to redistribute a copy of the Program exclusively under the +terms of the GPLv2 by removing the Exception notice from that copy of the +Program, provided that the copy has never been modified by you or any third +party. + + +Appendix A. Qualified Libraries and Packages +============================================ + +The following is a non-exhaustive list of libraries and packages which are +covered by the Exception when they are licensed under one or more of the +licenses listed above. Please note that this appendix is merely provided as +an additional service to specific FLOSS projects who wish to simplify +licensing information for their users. Compliance with one of the licenses +noted under the "FLOSS license list" section remains a prerequisite. + +Package name Qualifying License and Version +----------------------------------------------------------------- +Apache HTTP Server Apache Software License 2.0 +Apache Portable Runtime (APR) Apache Software License 2.0 + diff --git a/README.TXT b/README.TXT new file mode 100644 index 0000000..188e629 --- /dev/null +++ b/README.TXT @@ -0,0 +1,17 @@ +ModSecurity for Apache 2.x, http://www.modsecurity.org/ +Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + +ModSecurity for Apache is an open source product, released under terms of +the General Public Licence, Version 2 (GPLv2). Please refer to the +file LICENSE, which contains the complete text of the licence. + +There are special exceptions to the terms and conditions of the GPL +as it is applied to this software. View the full text of the exception in +file MODSECURITY_LICENSING_EXCEPTION in the directory of this software +distribution. + + +DOCUMENTATION + +Please refer to the documentation folder (/doc) for +the reference manual. diff --git a/apache2/.deps b/apache2/.deps new file mode 100644 index 0000000..e69de29 diff --git a/apache2/Makefile.in b/apache2/Makefile.in new file mode 100644 index 0000000..c3aae46 --- /dev/null +++ b/apache2/Makefile.in @@ -0,0 +1,127 @@ +# Makefile for ModSecurity + +MOD_SECURITY2 = mod_security2 apache2_config apache2_io apache2_util \ + re re_operators re_actions re_tfns re_variables \ + msc_logging msc_xml msc_multipart modsecurity msc_parsers msc_util msc_pcre \ + persist_dbm msc_reqbody pdf_protect msc_geo acmp msc_lua msc_release + +MSC_TEST = re re_operators re_actions re_tfns re_variables \ + msc_logging msc_xml msc_multipart modsecurity \ + msc_parsers msc_util msc_pcre persist_dbm \ + msc_reqbody msc_geo acmp msc_lua msc_release + +MOD_SECURITY2_H = re.h modsecurity.h msc_logging.h msc_multipart.h msc_parsers.h \ + msc_pcre.h msc_util.h msc_xml.h persist_dbm.h apache2.h pdf_protect.h \ + msc_geo.h acmp.h utf8tables.h msc_lua.h msc_release.h + +CC = @APXS_CC@ +LIBTOOL = @APXS_LIBTOOL@ +PERL = @PERL@ +EXTRA_CFLAGS = @EXTRA_CFLAGS@ +MODSEC_EXTRA_CFLAGS = @MODSEC_EXTRA_CFLAGS@ + +### Note: must be in APXS format: -Wc,-flag +APXS_EXTRA_CFLAGS = @APXS_EXTRA_CFLAGS@ +MODSEC_APXS_EXTRA_CFLAGS = @MODSEC_APXS_EXTRA_CFLAGS@ + +APXS = @APXS@ +APXS_WRAPPER = @APXS_WRAPPER@ +APXS_INCLUDEDIR = @APXS_INCLUDEDIR@ +APXS_INCLUDES = @APXS_INCLUDES@ +APXS_CFLAGS = @APXS_CFLAGS@ +APXS_LDFLAGS = @APXS_LDFLAGS@ +APXS_LIBS = @APXS_LIBS@ + +PCRE_CFLAGS = @PCRE_CFLAGS@ +PCRE_LIBS = @PCRE_LIBS@ + +LUA_CFLAGS = @LUA_CFLAGS@ +LUA_LIBS = @LUA_LIBS@ + +LIBXML2_CFLAGS = @LIBXML2_CFLAGS@ +LIBXML2_LIBS = @LIBXML2_LIBS@ + +APR_CFLAGS = @APR_CFLAGS@ +APR_LDFLAGS = @APR_LDFLAGS@ +APR_LIBS = @APR_LIBS@ +APR_LINK_LD = @APR_LINK_LD@ + +APU_CFLAGS = @APU_CFLAGS@ +APU_LDFLAGS = @APU_LDFLAGS@ +APU_LIBS = @APU_LIBS@ +APU_LINK_LD = @APU_LINK_LD@ + +CPPFLAGS = @CPPFLAGS@ $(PCRE_CFLAGS) $(LIBXML2_CFLAGS) $(LUA_CFLAGS) +LIBS = @LIBS@ $(PCRE_LIBS) $(LIBXML2_LIBS) $(LUA_LIBS) +LDFLAGS = @LDFLAGS@ +CFLAGS = @CFLAGS@ + +COMPILE_APACHE_MOD = $(APXS_WRAPPER) -c $(CPPFLAGS) $(LDFLAGS) $(LIBS) + +INSTALL_MOD_SHARED = $(APXS_WRAPPER) -i + +all: mod_security2.la + +install: install-mods + +clean-extras: + @for dir in mlogc-src; do \ + if test -d $$dir; then \ + (cd $$dir && $(MAKE) clean); \ + fi; \ + done + @rm -rf ../tools/mlogc ../tools/mlogc-batch-load.pl + +clean: clean-extras + @rm -rf *.la *.lo *.loT *.o *.slo .libs msc_test msc-test-debug.log + +distclean: clean + @rm -rf Makefile mlogc-src/Makefile mlogc-src/mlogc-batch-load.pl ../tools/*.pl t/run-unit-tests.pl t/run-regression-tests.pl t/gen_rx-pm.pl t/csv_rx-pm.pl t/run-tests.pl t/regression/server_root/conf/httpd.conf t/regression/server_root/conf/*.t_*.conf t/regression/server_root/tmp/* t/regression/server_root/logs/*.log t/regression/server_root/logs/audit/* t/regression/server_root/upload/* t/regression/server_root/data/* config config.log config.status build/apxs-wrapper + +maintainer-clean: distclean + @rm -rf config config.log config.status configure mod_security2_config.h autoscan.log configure.scan build/libtool.m4 build/config.guess build/config.sub build/ltmain.sh + +install-mods: mod_security2.la + $(INSTALL_MOD_SHARED) mod_security2.la + +${MOD_SECURITY2:=.slo}: $(MOD_SECURITY2_H) +${MOD_SECURITY2:=.lo}: $(MOD_SECURITY2_H) +${MOD_SECURITY2:=.o}: $(MOD_SECURITY2_H}) + +mod_security2.la: $(MOD_SECURITY2_H) *.c + @src=""; \ + for f in $(MOD_SECURITY2); do \ + src="$$src $$f.c"; \ + done; \ + rm -f msc_test msc_test.o msc_test.lo msc_test.slo; \ + $(COMPILE_APACHE_MOD) $(APXS_EXTRA_CFLAGS) $(MODSEC_APXS_EXTRA_CFLAGS) $$src + +### MLogC +mlogc: + @(cd mlogc-src && $(MAKE) mlogc) \ + && cp -p mlogc-src/mlogc ../tools \ + && cp -p mlogc-src/mlogc-batch-load.pl ../tools \ + && echo \ + && echo "Successfully built \"mlogc\" in ../tools." \ + && echo "See: mlogc-src/INSTALL" \ + && echo + +### Experimental Test Framework (*NIX only right now) +msc_test.lo: msc_test.c + $(LIBTOOL) --mode=compile $(CC) $(APXS_INCLUDES) $(APXS_CFLAGS) $(CPPFLAGS) $(APR_CFLAGS) $(APU_CFLAGS) -o msc_test.lo -c msc_test.c + +msc_test: $(TESTOBJS) $(MOD_SECURITY2_H}) msc_test.lo + objs=""; \ + for f in $(MSC_TEST); do \ + objs="$$objs $$f.lo"; \ + done; \ + $(LIBTOOL) --mode=link $(CC) $$objs -o msc_test msc_test.lo $(LDFLAGS) $(LIBS) $(APR_LINK_LD) $(APU_LINK_LD) + +test: t/run-unit-tests.pl msc_test + @rm -f msc-test-debug.log; \ + $(PERL) t/run-unit-tests.pl + +test-regression: t/run-regression-tests.pl + @$(PERL) t/run-regression-tests.pl + +.PHONY: all install clean-extras clean maintainer-clean distclean install-mods test test-regression diff --git a/apache2/Makefile.win b/apache2/Makefile.win new file mode 100644 index 0000000..95a7a3f --- /dev/null +++ b/apache2/Makefile.win @@ -0,0 +1,73 @@ +########################################################################### +### You Will need to modify the following variables for your system +########################################################################### +########################################################################### + +# Path to Apache httpd installation +BASE = C:\Apache2 + +# Paths to required libraries +LIBXML2 = C:\work\libxml2-2.6.31 +LUA = C:\work\lua-5.1.3 +PCRE = C:\work\httpd-2.2.8\srclib\pcre + +# Linking libraries +LIBS = $(BASE)\lib\libhttpd.lib \ + $(BASE)\lib\libapr-1.lib \ + $(BASE)\lib\libaprutil-1.lib \ + $(PCRE)\LibR\pcre.lib \ + $(LIBXML2)\win32\bin.msvc\libxml2.lib \ + $(LUA)\lua5.1.lib \ + wsock32.lib + +########################################################################### +########################################################################### + +CC = cL + +MT = mt + +DEFS = /nologo /O2 /LD /W3 /wd4244 -DWIN32 -DWINNT -Dinline=APR_INLINE + +DLL = mod_security2.so + +INCLUDES = -I. \ + -I$(PCRE)\include -I$(PCRE) \ + -I$(LIBXML2)\include \ + -I$(LUA)\include -I$(LUA) \ + -I$(BASE)\include + +CFLAGS= -MD $(INCLUDES) $(DEFS) + +LDFLAGS = + +OBJS = mod_security2.obj apache2_config.obj apache2_io.obj apache2_util.obj \ + re.obj re_operators.obj re_actions.obj re_tfns.obj re_variables.obj \ + msc_logging.obj msc_xml.obj msc_multipart.obj modsecurity.obj \ + msc_parsers.obj msc_util.obj msc_pcre.obj persist_dbm.obj \ + msc_reqbody.obj pdf_protect.obj msc_geo.obj acmp.obj msc_lua.obj \ + msc_release.obj + +all: $(DLL) + +dll: $(DLL) + +mod_security2_config.h: mod_security2_config.hw + @echo off + type mod_security2_config.hw > mod_security2_config.h + +.c.obj: + $(CC) $(CFLAGS) -c $< -Fo$@ + +.cpp.obj: + $(CC) $(CFLAGS) -c $< -Fo$@ + +$(DLL): mod_security2_config.h $(OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) -LD $(OBJS) -Fe$(DLL) $(LIBS) /link + IF EXIST $(DLL).manifest $(MT) -manifest $(DLL).manifest -outputresource:$(DLL);2 + +install: $(DLL) + copy $(DLL) $(BASE)\modules + +clean: + del $(OBJS) $(DLL) *.dll *.lib *.pdb *.idb *.ilk *.exp *.res *.rc *.bin mod_security2_config.h *.manifest diff --git a/apache2/acmp.c b/apache2/acmp.c new file mode 100644 index 0000000..d8c0c0a --- /dev/null +++ b/apache2/acmp.c @@ -0,0 +1,810 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ + +/* Aho-Corasick Matching */ + +#include "acmp.h" + +#ifdef ACMP_USE_UTF8 +/* UTF support */ +#include "utf8tables.h" +#else +/* No UTF support */ +#define acmp_utf8_char_t long +#include +#define utf8_lcase(a) apr_tolower(a) +#endif + +#include +#include +#include + + +/* + ******************************************************************************* + ******************************************************************************* + * Data structures for acmp parser + */ + + /** + * One node in trie + */ +typedef struct acmp_node_t acmp_node_t; +typedef struct acmp_btree_node_t acmp_btree_node_t; +struct acmp_node_t { + acmp_utf8_char_t letter; + int is_last; + acmp_callback_t callback; + void *callback_data; + int depth; + + acmp_node_t *child; + acmp_node_t *sibling; + acmp_node_t *fail; + acmp_node_t *parent; + acmp_node_t *o_match; + + acmp_btree_node_t *btree; + + apr_size_t hit_count; + + char *text; + char *pattern; +}; + +struct acmp_btree_node_t { + acmp_utf8_char_t letter; + acmp_btree_node_t *left; + acmp_btree_node_t *right; + acmp_node_t *node; +}; + +/** + * Data related to parser, not to individual nodes + */ +struct ACMP { + #ifdef ACMP_USE_UTF8 + int is_utf8; + #endif + int is_case_sensitive; + apr_pool_t *parent_pool; + apr_pool_t *pool; + + int dict_count; + apr_size_t longest_entry; + + acmp_node_t *root_node; + + const char *data_start; + const char *data_end; + const char *data_pos; + apr_size_t data_len; + + apr_size_t *bp_buffer; + apr_size_t bp_buff_len; + + acmp_node_t *active_node; + char u8_buff[6]; + apr_size_t u8buff_len; + apr_size_t hit_count; + int is_failtree_done; + int is_active; + apr_size_t byte_pos; + apr_size_t char_pos; +}; + +/* + ******************************************************************************* + ******************************************************************************* + * Functions for UTF-8 support + */ + +#ifdef ACMP_USE_UTF8 +/** + * Returns length of utf-8 sequence based on its first byte + */ +static int utf8_seq_len(const char *first_byte) { + return utf8_seq_lengths[(unsigned int)(unsigned char)first_byte[0]]; +} + +/** + * Returns length of utf8-encoded text + */ +static size_t utf8_strlen(const char *str) { + int len = 0; + const char *c = str; + while (*c != 0) { + c += utf8_seq_len(c); + len++; + } + return len; +} + +/** + * Returns ucs code for given utf-8 sequence + */ +static acmp_utf8_char_t utf8_decodechar(const char *str) { + int len = utf8_seq_len(str); + acmp_utf8_char_t ch = 0; + switch (len) { + case 6: ch += (unsigned char)*str++; ch <<= 6; + case 5: ch += (unsigned char)*str++; ch <<= 6; + case 4: ch += (unsigned char)*str++; ch <<= 6; + case 3: ch += (unsigned char)*str++; ch <<= 6; + case 2: ch += (unsigned char)*str++; ch <<= 6; + case 1: ch += (unsigned char)*str++; + } + ch -= utf8_offsets[len - 1]; + return ch; +} + +/** + * Returns lowercase for given unicode character. Searches through + * utf8_lcase_map table, if it doesn't find the code assumes + * it doesn't have a lowercase variant and returns code itself. + */ +static long utf8_lcase(acmp_utf8_char_t ucs_code) { + long mid, left, right; + left = 1; + right = UTF8_LCASEMAP_LEN * 2 + 1; + + while (left <= right) { + mid = (left + right) >> 1; + mid -= (mid % 2); mid++; + if (ucs_code > utf8_lcase_map[mid]) + left = mid + 2; + else if (ucs_code < utf8_lcase_map[mid]) + right = mid - 2; + else if (ucs_code == utf8_lcase_map[mid]) + return utf8_lcase_map[mid - 1]; + } + return ucs_code; +} +#endif + +/* + ******************************************************************************* + ******************************************************************************* + * Code for local / static utility functions + */ + +/** + * Returns length of given string for parser's encoding + */ +static size_t acmp_strlen(ACMP *parser, const char *str) { + #ifdef ACMP_USE_UTF8 + return (parser->is_utf8 == 0) ? strlen(str) : utf8_strlen(str); + #else + return strlen(str); + #endif +} + +/** + * Turns string to array of ucs values, depending on parser's encoding + * str - string to convert, doesn't have to be NULL-terminated + * ucs_chars - where to write ucs values + * len - length of input string + */ +static void acmp_strtoucs(ACMP *parser, const char *str, acmp_utf8_char_t *ucs_chars, int len) { + int i; + const char *c = str; + + #ifdef ACMP_USE_UTF8 + if (parser->is_utf8) { + for (i = 0; i < len; i++) { + *(ucs_chars++) = utf8_decodechar(c); + c += utf8_seq_len(c); + } + } else + #endif + { + for (i = 0; i < len; i++) { + *(ucs_chars++) = *(c++); + } + } +} + +/** + * Returns node with given letter, or null if not found + */ +static acmp_node_t *acmp_child_for_code(acmp_node_t *parent_node, acmp_utf8_char_t ucs_code) { + acmp_node_t *node = parent_node->child; + if (node == NULL) return NULL; + for (;;) { + if (node->letter == ucs_code) return node; + node = node->sibling; + if (node == NULL) return NULL; + } +} + +/** + * Adds node to parent node, if it is not already there + */ +static void acmp_add_node_to_parent(acmp_node_t *parent, acmp_node_t *child) { + acmp_node_t *node = NULL; + + child->parent = parent; + if (parent->child == NULL) { + parent->child = child; + return; + } + + node = parent->child; + for (;;) { + if (node == child) return; + if (node->sibling == NULL) { + node->sibling = child; + return; + } + node = node->sibling; + } +} + +/** + * Copies values from one node to another, without child/sibling/fail pointers + * and without state variables. + */ +static void acmp_clone_node_no_state(acmp_node_t *from, acmp_node_t *to) { + memcpy(to, from, sizeof(acmp_node_t)); + to->child = NULL; + to->sibling = NULL; + to->fail = NULL; + to->hit_count = 0; +} + +/** + * Copies sibling nodes and child node for from given "from" node to "to" node. + * Both nodes must already exist. + */ +static void acmp_copy_nodes_recursive(acmp_node_t *from, acmp_node_t *to, apr_pool_t *pool) { + acmp_node_t *old_node = from->child, *new_node, *nn2; + if (old_node == NULL) return; + nn2 = apr_pcalloc(pool, sizeof(acmp_node_t)); + /* ENH: Check alloc succeded */ + acmp_clone_node_no_state(old_node, nn2); + nn2->parent = to; + to->child = nn2; + acmp_copy_nodes_recursive(from->child, to->child, pool); + + for (;;) { + old_node = old_node->sibling; + if (old_node == NULL) break; + new_node = apr_pcalloc(pool, sizeof(acmp_node_t)); + /* ENH: Check alloc succeded */ + acmp_clone_node_no_state(old_node, new_node); + new_node->parent = to; + nn2->sibling = new_node; + nn2 = new_node; + acmp_copy_nodes_recursive(old_node, new_node, pool); + } +} + +static inline acmp_node_t *acmp_btree_find(acmp_node_t *node, acmp_utf8_char_t letter) { + acmp_btree_node_t *bnode = node->btree; + for (;;) { + if (bnode == NULL) return NULL; + if (bnode->letter == letter) return bnode->node; + if (bnode->letter > letter) { + bnode = bnode->left; + } else { + bnode = bnode->right; + } + } +} + +/** + * + */ +static inline acmp_node_t *acmp_goto(acmp_node_t *node, acmp_utf8_char_t letter) { + return acmp_btree_find(node, letter); +} + +/** + * Connects each node with its first fail node that is end of a phrase. + */ +static void acmp_connect_other_matches(ACMP *parser, acmp_node_t *node) { + acmp_node_t *child, *om; + + for (child = node->child; child != NULL; child = child->sibling) { + if (child->fail == NULL) continue; + for (om = child->fail; om != parser->root_node; om = om->fail) { + if (om->is_last) { + child->o_match = om; + break; + } + } + } + + /* Go recursively through children of this node that have a child node */ + for(child = node->child; child != NULL; child = child->sibling) { + if (child->child != NULL) acmp_connect_other_matches(parser, child); + } +} + +/** + * Adds leaves to binary tree, working from sorted array of keyword tree nodes + */ +static void acmp_add_btree_leaves(acmp_btree_node_t *node, acmp_node_t *nodes[], + int pos, int lb, int rb, apr_pool_t *pool) { + + int left = 0, right = 0; + if ((pos - lb) > 1) { + left = lb + (pos - lb) / 2; + node->left = apr_pcalloc(pool, sizeof(acmp_btree_node_t)); + /* ENH: Check alloc succeded */ + node->left->node = nodes[left]; + node->left->letter = nodes[left]->letter; + #ifdef DEBUG_ACMP + fprintf(stderr, "%lc ->left %lc\n", (wint_t)node->node->letter, (wint_t)node->left->node->letter); + #endif + } + if ((rb - pos) > 1) { + right = pos + (rb - pos) / 2; + node->right = apr_pcalloc(pool, sizeof(acmp_btree_node_t)); + /* ENH: Check alloc succeded */ + node->right->node = nodes[right]; + node->right->letter = nodes[right]->letter; + #ifdef DEBUG_ACMP + fprintf(stderr, "%lc ->right %lc\n", (wint_t)node->node->letter, (wint_t)node->right->node->letter); + #endif + } + if (node->right != NULL) { + acmp_add_btree_leaves(node->right, nodes, right, pos, rb, pool); + } + if (node->left != NULL) { + acmp_add_btree_leaves(node->left, nodes, left, lb, pos, pool); + } +} + +/** + * Builds balanced binary tree from children nodes of given node. + */ +static void acmp_build_binary_tree(ACMP *parser, acmp_node_t *node) { + apr_size_t count, i, j; + acmp_node_t *child = node->child; + acmp_node_t **nodes; + apr_size_t pos; + + /* Build an array big enough */ + for (count = 0; child != NULL; child = child->sibling) count++; + nodes = apr_pcalloc(parser->pool, count * sizeof(acmp_node_t *)); + /* ENH: Check alloc succeded */ + + /* ENH: Combine this in the loop below - we do not need two loops */ + child = node->child; + for (i = 0; i < count; i++) { + nodes[i] = child; + child = child->sibling; + }; + + /* We have array with all children of the node and number of those children + */ + for (i = 0; i < count - 1; i++) + for (j = i + 1; j < count; j++) { + acmp_node_t *tmp; + + if (nodes[i]->letter < nodes[j]->letter) continue; + + tmp = nodes[i]; + nodes[i] = nodes[j]; + nodes[j] = tmp; + } + node->btree = apr_pcalloc(parser->pool, sizeof(acmp_btree_node_t)); + /* ENH: Check alloc succeded */ + pos = count / 2; + node->btree->node = nodes[pos]; + node->btree->letter = nodes[pos]->letter; + acmp_add_btree_leaves(node->btree, nodes, pos, -1, count, parser->pool); + for (i = 0; i < count; i++) { + if (nodes[i]->child != NULL) acmp_build_binary_tree(parser, nodes[i]); + } +} + +/** + * Constructs fail paths on keyword trie + */ +static apr_status_t acmp_connect_fail_branches(ACMP *parser) { + /* Already connected ? */ + acmp_node_t *child, *node, *goto_node; + apr_array_header_t *arr, *arr2, *tmp; + + if (parser->is_failtree_done != 0) return APR_SUCCESS; + + parser->root_node->text = ""; + arr = apr_array_make(parser->pool, 32, sizeof(acmp_node_t *)); + arr2 = apr_array_make(parser->pool, 32, sizeof(acmp_node_t *)); + + parser->root_node->fail = parser->root_node; + + /* All first-level children will fail back to root node */ + for (child = parser->root_node->child; child != NULL; child = child->sibling) { + child->fail = parser->root_node; + *(acmp_node_t **)apr_array_push(arr) = child; + #ifdef DEBUG_ACMP + fprintf(stderr, "fail direction: *%s* => *%s*\n", child->text, child->fail->text); + #endif + } + + for (;;) { + while (apr_is_empty_array(arr) == 0) { + node = *(acmp_node_t **)apr_array_pop(arr); + node->fail = parser->root_node; + if (node->parent != parser->root_node) { + goto_node = acmp_child_for_code(node->parent->fail, node->letter); + node->fail = (goto_node != NULL) ? goto_node : parser->root_node; + } + #ifdef DEBUG_ACMP + fprintf(stderr, "fail direction: *%s* => *%s*\n", node->text, node->fail->text); + #endif + child = node->child; + while (child != NULL) { + *(acmp_node_t **)apr_array_push(arr2) = child; + child = child->sibling; + } + } + if (apr_is_empty_array(arr2) != 0) break; + + tmp = arr; + arr = arr2; + arr2 = tmp; + } + acmp_connect_other_matches(parser, parser->root_node); + if (parser->root_node->child != NULL) acmp_build_binary_tree(parser, parser->root_node); + parser->is_failtree_done = 1; + return APR_SUCCESS; +} + +/** + * Clears hit count of each node, called from acmp_reset() + */ +static void acmp_clear_hit_count_recursive(acmp_node_t *node) { + for (; node != NULL; node = node->sibling) { + node->hit_count = 0; + if (node->child != NULL) acmp_clear_hit_count_recursive(node->child); + } +} + +/** + * Called when a match is found + */ +static void acmp_found(ACMP *parser, acmp_node_t *node) { + if (node->callback) { + node->callback(parser, node->callback_data, + parser->bp_buffer[(parser->char_pos - node->depth - 1) % parser->bp_buff_len], + parser->char_pos - node->depth - 1); + } + node->hit_count++; + parser->hit_count++; +} + +/* + ******************************************************************************* + ******************************************************************************* + * Code for functions from header file + */ + + +/** + * flags - OR-ed values of ACMP_FLAG constants + * pool - apr_pool to use as parent pool, can be set to NULL + */ +ACMP *acmp_create(int flags, apr_pool_t *pool) { + apr_status_t rc; + apr_pool_t *p; + ACMP *parser; + + rc = apr_pool_create(&p, pool); + if (rc != APR_SUCCESS) return NULL; + + parser = apr_pcalloc(p, sizeof(ACMP)); + /* ENH: Check alloc succeded */ + parser->pool = p; + parser->parent_pool = pool; + #ifdef ACMP_USE_UTF8 + parser->is_utf8 = (flags & ACMP_FLAG_UTF8) == 0 ? 0 : 1; + #endif + parser->is_case_sensitive = (flags & ACMP_FLAG_CASE_SENSITIVE) == 0 ? 0 : 1; + parser->root_node = apr_pcalloc(p, sizeof(acmp_node_t)); + /* ENH: Check alloc succeded */ + return parser; +} + +/** + * Destroys previously created parser + */ +void acmp_destroy(ACMP *parser) { + /* + * All data is kept in parser's pool (including parser struct itself), so + * destroying the pool will destroy everything + */ + apr_pool_destroy(parser->pool); +} + +/** + * Creates parser with same options and same patterns + * parser - ACMP parser to duplicate + * pool - parent pool to use, if left as NULL original parser's parent pool is used + */ +ACMP *acmp_duplicate(ACMP *parser, apr_pool_t *pool) { + apr_status_t rc; + apr_pool_t *p; + ACMP *new_parser; + + if (pool == NULL) pool = parser->parent_pool; + rc = apr_pool_create(&p, pool); + if (rc != APR_SUCCESS) return NULL; + + new_parser = apr_pcalloc(p, sizeof(ACMP)); + /* ENH: Check alloc succeded */ + new_parser->pool = p; + new_parser->parent_pool = pool; + #ifdef ACMP_USE_UTF8 + new_parser->is_utf8 = parser->is_utf8; + #endif + new_parser->is_case_sensitive = parser->is_case_sensitive; + new_parser->root_node = apr_pcalloc(p, sizeof(acmp_node_t)); + /* ENH: Check alloc succeded */ + new_parser->dict_count = parser->dict_count; + new_parser->longest_entry = parser->longest_entry; + acmp_copy_nodes_recursive(parser->root_node, new_parser->root_node, new_parser->pool); + acmp_prepare(new_parser); + return new_parser; +} + +/** + * Creates fail tree and initializes buffer + */ +apr_status_t acmp_prepare(ACMP *parser) { + apr_status_t st; + + if (parser->bp_buff_len < parser->longest_entry) { + parser->bp_buff_len = parser->longest_entry * 2; + parser->bp_buffer = apr_pcalloc(parser->pool, sizeof(apr_size_t) * parser->bp_buff_len); + /* ENH: Check alloc succeded */ + } + + st = acmp_connect_fail_branches(parser); + parser->active_node = parser->root_node; + if (st != APR_SUCCESS) return st; + parser->is_active = 1; + return APR_SUCCESS; +} + +/** + * Adds pattern to parser + * parser - ACMP parser + * pattern - string with pattern to match + * callback - Optional, pointer to an acmp_callback_t function + * data - pointer to data that will be passed to callback function, only used if callback + * is supplied + * len - Length of pattern in characters, if zero string length is used. + */ +apr_status_t acmp_add_pattern(ACMP *parser, const char *pattern, + acmp_callback_t callback, void *data, apr_size_t len) +{ + size_t length, i, j; + acmp_utf8_char_t *ucs_chars; + acmp_node_t *parent, *child; + + if (parser->is_active != 0) return APR_EGENERAL; + + length = (len == 0) ? acmp_strlen(parser, pattern) : len; + ucs_chars = apr_pcalloc(parser->pool, length * sizeof(acmp_utf8_char_t)); + /* ENH: Check alloc succeded */ + + parent = parser->root_node; + acmp_strtoucs(parser, pattern, ucs_chars, length); + + for (i = 0; i < length; i++) { + acmp_utf8_char_t letter = ucs_chars[i]; + if (parser->is_case_sensitive == 0) { + letter = utf8_lcase(letter); + } + child = acmp_child_for_code(parent, letter); + if (child == NULL) { + child = apr_pcalloc(parser->pool, sizeof(acmp_node_t)); + /* ENH: Check alloc succeded */ + child->pattern = ""; + child->letter = letter; + child->depth = i; + child->text = apr_pcalloc(parser->pool, strlen(pattern) + 2); + /* ENH: Check alloc succeded */ + for (j = 0; j <= i; j++) child->text[j] = pattern[j]; + } + if (i == length - 1) { + if (child->is_last == 0) { + parser->dict_count++; + child->is_last = 1; + child->pattern = apr_pcalloc(parser->pool, strlen(pattern) + 2); + /* ENH: Check alloc succeded */ + strcpy(child->pattern, pattern); + } + child->callback = callback; + child->callback_data = data; + } + acmp_add_node_to_parent(parent, child); + parent = child; + } + if (length > parser->longest_entry) parser->longest_entry = length; + parser->is_failtree_done = 0; + + return APR_SUCCESS; +} + +/** + * Called to process incoming data stream + * data - ptr to incoming data + * len - size of data in bytes + */ +apr_status_t acmp_process(ACMP *parser, const char *data, apr_size_t len) { + acmp_node_t *node, *go_to; + #ifdef ACMP_USE_UTF8 + apr_size_t seq_length; + #endif + const char *end; + + if (parser->is_failtree_done == 0) acmp_prepare(parser); + + node = parser->active_node; + end = data + len; + + while (data < end) { + acmp_utf8_char_t letter; + + parser->bp_buffer[parser->char_pos % parser->bp_buff_len] = parser->byte_pos; + #ifdef ACMP_USE_UTF8 + if (parser->is_utf8) { + if (parser->u8buff_len > 0) { + /* Resuming partial utf-8 sequence */ + seq_length = utf8_seq_len(parser->u8_buff); + for (;;) { + parser->u8_buff[parser->u8buff_len++] = *data++; + if (parser->u8buff_len == seq_length) { + parser->u8buff_len = 0; + letter = utf8_decodechar(parser->u8_buff); + parser->byte_pos += seq_length; + parser->char_pos++; + break; + } + } + } else { + /* not resuming partial sequence, reading from the stream */ + seq_length = utf8_seq_len(data); + if ((data + seq_length) > end) { + while (data < end) parser->u8_buff[parser->u8buff_len++] = *data++; + return APR_SUCCESS; + } else { + letter = utf8_decodechar(data); + data += seq_length; + parser->byte_pos += seq_length; + parser->char_pos++; + } + } + } else + #endif + { + letter = *data++; + parser->byte_pos++; + parser->char_pos++; + } + if (parser->is_case_sensitive == 0) letter = utf8_lcase(letter); + + go_to = NULL; + while (go_to == NULL) { + acmp_node_t *n2 = acmp_goto(node, letter); + go_to = acmp_child_for_code(node, letter); + if (n2 != go_to) { + n2 = acmp_goto(node, letter); + }; + if (go_to != NULL) { + if (go_to->is_last) { + acmp_found(parser, go_to); + } + } + if (node == parser->root_node) break; + if (go_to == NULL) node = node->fail; + } + if (go_to != NULL) node = go_to; + + /* We need to collect other nodes that are last letters of phrase. These + * will be fail node of current node if it has is_last flag set, and + * fail node of that node, recursively down to root node. + */ + go_to = node; + if (go_to != parser->root_node) { + for (go_to = go_to->o_match; go_to != NULL; go_to = go_to->o_match) { + acmp_found(parser, go_to); + } + } + } + parser->active_node = node; + return parser->hit_count > 0 ? 1 : 0; +} + +/** + * Resets the state of parser so you can start using it with new set of data. + * + * No need to clear buffer since it will be re-initialized at first run of + * acmp_process + */ +void acmp_reset(ACMP *parser) { + parser->is_active = 0; + parser->byte_pos = 0; + parser->char_pos = 0; + parser->hit_count = 0; + parser->u8buff_len = 0; + acmp_clear_hit_count_recursive(parser->root_node); +} + +/** + * Creates an ACMPT struct that will use parser's tree, without duplicating its data + */ +ACMPT *acmp_duplicate_quick(ACMP *parser, apr_pool_t *pool) { + apr_pool_t *p = (pool != NULL) ? pool : parser->pool; + ACMPT *dup = apr_pcalloc(p, sizeof(ACMPT)); + /* ENH: Check alloc succeded */ + dup->parser = parser; + return dup; +} + +/** + * Process the data using ACMPT to keep state, and ACMPT's parser to keep the tree + */ +apr_status_t acmp_process_quick(ACMPT *acmpt, const char **match, const char *data, apr_size_t len) { + ACMP *parser; + acmp_node_t *node, *go_to; + const char *end; + + if (acmpt->parser->is_failtree_done == 0) { + acmp_prepare(acmpt->parser); + }; + + parser = acmpt->parser; + if (acmpt->ptr == NULL) acmpt->ptr = parser->root_node; + node = acmpt->ptr; + end = data + len; + + while (data < end) { + acmp_utf8_char_t letter = (unsigned char)*data++; + + if (parser->is_case_sensitive == 0) letter = utf8_lcase(letter); + + go_to = NULL; + while (go_to == NULL) { + go_to = acmp_goto(node, letter); + if (go_to != NULL) { + if (go_to->is_last) { + *match = go_to->text; + return 1; + } + } + if (node == parser->root_node) break; + if (go_to == NULL) node = node->fail; + } + if (go_to != NULL) node = go_to; + + /* If node has o_match, then we found a pattern */ + if (node->o_match != NULL) { + *match = node->text; + return 1; + } + } + acmpt->ptr = node; + return 0; +} diff --git a/apache2/acmp.h b/apache2/acmp.h new file mode 100644 index 0000000..761e3a4 --- /dev/null +++ b/apache2/acmp.h @@ -0,0 +1,125 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ +#ifndef ACMP_H_ +#define ACMP_H_ + +#include +#include + +#define ACMP_FLAG_BYTE 0 +#define ACMP_FLAG_CASE_SENSITIVE 1 +#define ACMP_FLAG_CASE_INSENSITIVE 0 +#ifdef ACMP_USE_UTF8 +#define ACMP_FLAG_UTF8 0x100 +#endif + +/** + * Opaque struct with parser data + */ +typedef struct ACMP ACMP; + +/** + * Used to separate state from the trie for acmp_process_quick function + */ +typedef struct { + ACMP *parser; + void *ptr; +} ACMPT; + +/** + * Callback function. Arguments are: + * ACMP * - acmp parser that initiated callback + * void * - custom data you supplied when adding callback + * apr_size_t - position in bytes where pattern was found + * apr_size_t - position in chars where pattern was found, for multibyte strings + */ +typedef void (*acmp_callback_t)(ACMP *, void *, apr_size_t, apr_size_t); + +/** + * flags - OR-ed values of ACMP_FLAG constants + * pool - apr_pool to use as parent pool, can be set to NULL + */ +ACMP *acmp_create(int flags, apr_pool_t *pool); + +/** + * Destroys previously created parser + */ +void acmp_destroy(ACMP *parser); + +/** + * Creates parser with same options and same patterns + * parser - ACMP parser to duplicate + * pool - parent pool to use, if left as NULL original parser's parent pool is used + */ +ACMP *acmp_duplicate(ACMP *parser, apr_pool_t *pool); + +/** + * Adds pattern to parser. Cannot be done after starting the search. + * parser - ACMP parser + * pattern - string with pattern to match + * callback - Optional, pointer to an acmp_callback_t function + * data - pointer to data that will be passed to callback function, only used if callback + * is supplied + * len - Length of pattern in characters, if zero string length is used. + */ +apr_status_t acmp_add_pattern(ACMP *parser, const char *pattern, + acmp_callback_t callback, void *data, apr_size_t len); + +/** + * Called to process incoming data stream. You must call acmp_done after sending + * last data packet + * + * data - ptr to incoming data + * len - size of data in bytes + */ +apr_status_t acmp_process(ACMP *parser, const char *data, apr_size_t len); + +/** + * Returns number of matches on all patterns combined + */ +apr_size_t acmp_match_count_total(ACMP *parser); + +/** + * Returns number of matches for given pattern + */ +apr_size_t acmp_match_count(ACMP *parser, const char *pattern); + +/** + * Resets the state of parser so you can start using it with new set of data, + * or add new patterns. + */ +void acmp_reset(ACMP *parser); + +/** + * Creates an ACMPT struct that will use parser's tree, without duplicating its data + */ +ACMPT *acmp_duplicate_quick(ACMP *parser, apr_pool_t *pool); + +/** + * Process the data using ACMPT to keep state, and ACMPT's parser to keep the tree + */ +apr_status_t acmp_process_quick(ACMPT *acmpt, const char **match, const char *data, apr_size_t len); + +/** + * Prepares parser for searching + */ +apr_status_t acmp_prepare(ACMP *parser); + + +#endif /*ACMP_H_*/ diff --git a/apache2/apache2.h b/apache2/apache2.h new file mode 100644 index 0000000..264fcf4 --- /dev/null +++ b/apache2/apache2.h @@ -0,0 +1,108 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ +#ifndef _APACHE2_H_ +#define _APACHE2_H_ + +#include "http_core.h" +#include "http_request.h" +#include "httpd.h" +#include "ap_release.h" + +#include +#include + + +#if (!defined(NO_MODSEC_API)) +/* Optional functions. */ + +APR_DECLARE_OPTIONAL_FN(void, modsec_register_tfn, (const char *name, void *fn)); +APR_DECLARE_OPTIONAL_FN(void, modsec_register_operator, (const char *name, void *fn_init, void *fn_exec)); +APR_DECLARE_OPTIONAL_FN(void, modsec_register_variable, + (const char *name, unsigned int type, + unsigned int argc_min, unsigned int argc_max, + void *fn_validate, void *fn_generate, + unsigned int is_cacheable, unsigned int availability)); +#endif + +/* ap_get_server_version() is gone in 2.3.0. + * It was replaced by two calls in 2.2.4 and higher: + * ap_get_server_banner() + * ap_get_server_description() + */ +#if (AP_SERVER_MAJORVERSION_NUMBER > 2) \ + || ((AP_SERVER_MAJORVERSION_NUMBER == 2)&& (AP_SERVER_MINORVERSION_NUMBER > 2)) \ + || ((AP_SERVER_MAJORVERSION_NUMBER == 2) && (AP_SERVER_MINORVERSION_NUMBER == 2) && (AP_SERVER_PATCHLEVEL_NUMBER >= 4)) +#define apache_get_server_version() ap_get_server_banner() +#else +#define apache_get_server_version() ap_get_server_version() +#endif + + +/* Configuration functions. */ + +void DSOLOCAL *create_directory_config(apr_pool_t *mp, char *path); + +void DSOLOCAL *merge_directory_configs(apr_pool_t *mp, void *_parent, void *_child); + +void DSOLOCAL init_directory_config(directory_config *dcfg); + + +/* IO functions. */ + +apr_status_t DSOLOCAL input_filter(ap_filter_t *f, apr_bucket_brigade *bb_out, + ap_input_mode_t mode, apr_read_type_e block, apr_off_t nbytes); + +apr_status_t DSOLOCAL output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in); + +apr_status_t DSOLOCAL read_request_body(modsec_rec *msr, char **error_msg); + + +/* Utility functions */ + +int DSOLOCAL perform_interception(modsec_rec *msr); + +apr_status_t DSOLOCAL send_error_bucket(modsec_rec *msr, ap_filter_t *f, int status); + +int DSOLOCAL apache2_exec(modsec_rec *msr, const char *command, const char **argv, char **output); + +void DSOLOCAL record_time_checkpoint(modsec_rec *msr, int checkpoint_no); + +char DSOLOCAL *get_apr_error(apr_pool_t *p, apr_status_t rc); + +char DSOLOCAL *get_env_var(request_rec *r, char *name); + +void DSOLOCAL internal_log_ex(request_rec *r, directory_config *dcfg, modsec_rec *msr, + int level, int fixup, const char *text, va_list ap); + +void DSOLOCAL internal_log(request_rec *r, directory_config *dcfg, modsec_rec *msr, + int level, const char *text, va_list ap); + +void DSOLOCAL msr_log(modsec_rec *msr, int level, const char *text, ...) PRINTF_ATTRIBUTE(3,4); + +void DSOLOCAL msr_log_error(modsec_rec *msr, const char *text, ...) PRINTF_ATTRIBUTE(2,3); + +void DSOLOCAL msr_log_warn(modsec_rec *msr, const char *text, ...) PRINTF_ATTRIBUTE(2,3); + +char DSOLOCAL *format_error_log_message(apr_pool_t *mp, error_message *em); + +const DSOLOCAL char *get_response_protocol(request_rec *r); + + +#endif + diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c new file mode 100644 index 0000000..545e169 --- /dev/null +++ b/apache2/apache2_config.c @@ -0,0 +1,2252 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ +#include + +#include "modsecurity.h" +#include "msc_logging.h" +#include "msc_util.h" +#include "pdf_protect.h" +#include "http_log.h" + +#if defined(WITH_LUA) +#include "msc_lua.h" +#endif + + +/* -- Directory context creation and initialisation -- */ + +/** + * Creates a fresh directory configuration. + */ +void *create_directory_config(apr_pool_t *mp, char *path) { + directory_config *dcfg = (directory_config *)apr_pcalloc(mp, sizeof(directory_config)); + if (dcfg == NULL) return NULL; + + #ifdef DEBUG_CONF + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Created directory config %pp path %s", dcfg, path); + #endif + + dcfg->mp = mp; + dcfg->is_enabled = NOT_SET; + + dcfg->reqbody_access = NOT_SET; + dcfg->reqbody_buffering = NOT_SET; + dcfg->reqbody_inmemory_limit = NOT_SET; + dcfg->reqbody_limit = NOT_SET; + dcfg->reqbody_no_files_limit = NOT_SET; + dcfg->resbody_access = NOT_SET; + + dcfg->debuglog_name = NOT_SET_P; + dcfg->debuglog_level = NOT_SET; + dcfg->debuglog_fd = NOT_SET_P; + + dcfg->of_limit = NOT_SET; + dcfg->of_limit_action = NOT_SET; + dcfg->of_mime_types = NOT_SET_P; + dcfg->of_mime_types_cleared = NOT_SET; + + dcfg->cookie_format = NOT_SET; + dcfg->argument_separator = NOT_SET; + + dcfg->rule_inheritance = NOT_SET; + dcfg->rule_exceptions = apr_array_make(mp, 16, sizeof(rule_exception *)); + + /* audit log variables */ + dcfg->auditlog_flag = NOT_SET; + dcfg->auditlog_type = NOT_SET; + dcfg->auditlog_dirperms = NOT_SET; + dcfg->auditlog_fileperms = NOT_SET; + dcfg->auditlog_name = NOT_SET_P; + dcfg->auditlog2_name = NOT_SET_P; + dcfg->auditlog_fd = NOT_SET_P; + dcfg->auditlog2_fd = NOT_SET_P; + dcfg->auditlog_storage_dir = NOT_SET_P; + dcfg->auditlog_parts = NOT_SET_P; + dcfg->auditlog_relevant_regex = NOT_SET_P; + + dcfg->ruleset = NULL; + + /* Upload */ + dcfg->tmp_dir = NOT_SET_P; + dcfg->upload_dir = NOT_SET_P; + dcfg->upload_keep_files = NOT_SET; + dcfg->upload_validates_files = NOT_SET; + dcfg->upload_filemode = NOT_SET; + + /* These are only used during the configuration process. */ + dcfg->tmp_chain_starter = NULL; + dcfg->tmp_default_actionset = NULL; + dcfg->tmp_rule_placeholders = NULL; + + /* Misc */ + dcfg->data_dir = NOT_SET_P; + dcfg->webappid = NOT_SET_P; + + /* Content injection. */ + dcfg->content_injection_enabled = NOT_SET; + + /* PDF XSS protection. */ + dcfg->pdfp_enabled = NOT_SET; + dcfg->pdfp_secret = NOT_SET_P; + dcfg->pdfp_timeout = NOT_SET; + dcfg->pdfp_token_name = NOT_SET_P; + dcfg->pdfp_only_get = NOT_SET; + dcfg->pdfp_method = NOT_SET; + + /* Geo Lookups */ + dcfg->geo = NOT_SET_P; + + /* Cache */ + dcfg->cache_trans = NOT_SET; + dcfg->cache_trans_incremental = NOT_SET; + dcfg->cache_trans_min = NOT_SET; + dcfg->cache_trans_max = NOT_SET; + dcfg->cache_trans_maxitems = NOT_SET; + + dcfg->component_signatures = apr_array_make(mp, 16, sizeof(char *)); + + dcfg->request_encoding = NOT_SET_P; + + return dcfg; +} + +/** + * Copies rules between one phase of two configuration contexts, + * taking exceptions into account. + */ +static void copy_rules_phase(apr_pool_t *mp, apr_array_header_t *parent_phase_arr, + apr_array_header_t *child_phase_arr, apr_array_header_t *exceptions_arr) +{ + rule_exception **exceptions; + msre_rule **rules; + int i, j; + int mode = 0; + + rules = (msre_rule **)parent_phase_arr->elts; + for(i = 0; i < parent_phase_arr->nelts; i++) { + msre_rule *rule = (msre_rule *)rules[i]; + int copy = 1; + + if (mode == 0) { + /* First rule in the chain. */ + exceptions = (rule_exception **)exceptions_arr->elts; + for(j = 0; j < exceptions_arr->nelts; j++) { + + /* Process exceptions. */ + switch(exceptions[j]->type) { + case RULE_EXCEPTION_REMOVE_ID : + if ((rule->actionset != NULL)&&(rule->actionset->id != NULL)) { + int ruleid = atoi(rule->actionset->id); + if (rule_id_in_range(ruleid, exceptions[j]->param)) copy--; + } + break; + case RULE_EXCEPTION_REMOVE_MSG : + if ((rule->actionset != NULL)&&(rule->actionset->msg != NULL)) { + char *my_error_msg = NULL; + + int rc = msc_regexec(exceptions[j]->param_data, + rule->actionset->msg, strlen(rule->actionset->msg), + &my_error_msg); + if (rc >= 0) copy--; + } + break; + } + } + + if (copy > 0) { + #ifdef DEBUG_CONF + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Copy rule %pp [id \"%s\"]", rule, rule->actionset->id); + #endif + + /* Copy the rule. */ + *(msre_rule **)apr_array_push(child_phase_arr) = rule; + if (rule->actionset->is_chained) mode = 2; + } else { + if (rule->actionset->is_chained) mode = 1; + } + } else { + if (mode == 2) { + #ifdef DEBUG_CONF + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Copy chain %pp for rule %pp [id \"%s\"]", rule, rule->chain_starter, rule->chain_starter->actionset->id); + #endif + + /* Copy the rule (it belongs to the chain we want to include. */ + *(msre_rule **)apr_array_push(child_phase_arr) = rule; + } + + if ((rule->actionset == NULL)||(rule->actionset->is_chained == 0)) mode = 0; + } + } +} + +/** + * Copies rules between two configuration contexts, + * taking exceptions into account. + */ +static int copy_rules(apr_pool_t *mp, msre_ruleset *parent_ruleset, msre_ruleset *child_ruleset, + apr_array_header_t *exceptions_arr) +{ + copy_rules_phase(mp, parent_ruleset->phase_request_headers, + child_ruleset->phase_request_headers, exceptions_arr); + copy_rules_phase(mp, parent_ruleset->phase_request_body, + child_ruleset->phase_request_body, exceptions_arr); + copy_rules_phase(mp, parent_ruleset->phase_response_headers, + child_ruleset->phase_response_headers, exceptions_arr); + copy_rules_phase(mp, parent_ruleset->phase_response_body, + child_ruleset->phase_response_body, exceptions_arr); + copy_rules_phase(mp, parent_ruleset->phase_logging, + child_ruleset->phase_logging, exceptions_arr); + + return 1; +} + +/** + * Merges two directory configurations. + */ +void *merge_directory_configs(apr_pool_t *mp, void *_parent, void *_child) { + directory_config *parent = (directory_config *)_parent; + directory_config *child = (directory_config *)_child; + directory_config *merged = create_directory_config(mp, NULL); + + #ifdef DEBUG_CONF + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Merge parent %pp child %pp RESULT %pp", _parent, _child, merged); + #endif + + if (merged == NULL) return NULL; + + /* Use values from the child configuration where possible, + * otherwise use the parent's. + */ + + merged->is_enabled = (child->is_enabled == NOT_SET + ? parent->is_enabled : child->is_enabled); + + /* IO parameters */ + merged->reqbody_access = (child->reqbody_access == NOT_SET + ? parent->reqbody_access : child->reqbody_access); + merged->reqbody_buffering = (child->reqbody_buffering == NOT_SET + ? parent->reqbody_buffering : child->reqbody_buffering); + merged->reqbody_inmemory_limit = (child->reqbody_inmemory_limit == NOT_SET + ? parent->reqbody_inmemory_limit : child->reqbody_inmemory_limit); + merged->reqbody_limit = (child->reqbody_limit == NOT_SET + ? parent->reqbody_limit : child->reqbody_limit); + merged->reqbody_no_files_limit = (child->reqbody_no_files_limit == NOT_SET + ? parent->reqbody_no_files_limit : child->reqbody_no_files_limit); + merged->resbody_access = (child->resbody_access == NOT_SET + ? parent->resbody_access : child->resbody_access); + + merged->of_limit = (child->of_limit == NOT_SET + ? parent->of_limit : child->of_limit); + merged->of_limit_action = (child->of_limit_action == NOT_SET + ? parent->of_limit_action : child->of_limit_action); + + if (child->of_mime_types != NOT_SET_P) { + /* Child added to the table */ + + if (child->of_mime_types_cleared == 1) { + /* The list of MIME types was cleared in the child, + * which means the parent's MIME types went away and + * we should not take them into consideration here. + */ + merged->of_mime_types = child->of_mime_types; + merged->of_mime_types_cleared = 1; + } else { + /* Add MIME types defined in the child to those + * defined in the parent context. + */ + if (parent->of_mime_types == NOT_SET_P) { + merged->of_mime_types = child->of_mime_types; + merged->of_mime_types_cleared = NOT_SET; + } else { + merged->of_mime_types = apr_table_overlay(mp, parent->of_mime_types, + child->of_mime_types); + if (merged->of_mime_types == NULL) return NULL; + } + } + } else { + /* Child did not add to the table */ + + if (child->of_mime_types_cleared == 1) { + merged->of_mime_types_cleared = 1; + } else { + merged->of_mime_types = parent->of_mime_types; + merged->of_mime_types_cleared = parent->of_mime_types_cleared; + } + } + + /* debug log */ + if (child->debuglog_fd == NOT_SET_P) { + merged->debuglog_name = parent->debuglog_name; + merged->debuglog_fd = parent->debuglog_fd; + } else { + merged->debuglog_name = child->debuglog_name; + merged->debuglog_fd = child->debuglog_fd; + } + + merged->debuglog_level = (child->debuglog_level == NOT_SET + ? parent->debuglog_level : child->debuglog_level); + + merged->cookie_format = (child->cookie_format == NOT_SET + ? parent->cookie_format : child->cookie_format); + merged->argument_separator = (child->argument_separator == NOT_SET + ? parent->argument_separator : child->argument_separator); + + + /* rule inheritance */ + if ((child->rule_inheritance == NOT_SET)||(child->rule_inheritance == 1)) { + merged->rule_inheritance = parent->rule_inheritance; + if ((child->ruleset == NULL)&&(parent->ruleset == NULL)) { + #ifdef DEBUG_CONF + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "No rules in this context."); + #endif + + /* Do nothing, there are no rules in either context. */ + } else + if (child->ruleset == NULL) { + #ifdef DEBUG_CONF + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Using parent rules in this context."); + #endif + + /* Copy the rules from the parent context. */ + merged->ruleset = msre_ruleset_create(parent->ruleset->engine, mp); + copy_rules(mp, parent->ruleset, merged->ruleset, child->rule_exceptions); + } else + if (parent->ruleset == NULL) { + #ifdef DEBUG_CONF + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Using child rules in this context."); + #endif + + /* Copy child rules. */ + merged->ruleset = msre_ruleset_create(child->ruleset->engine, mp); + merged->ruleset->phase_request_headers = apr_array_copy(mp, + child->ruleset->phase_request_headers); + merged->ruleset->phase_request_body = apr_array_copy(mp, + child->ruleset->phase_request_body); + merged->ruleset->phase_response_headers = apr_array_copy(mp, + child->ruleset->phase_response_headers); + merged->ruleset->phase_response_body = apr_array_copy(mp, + child->ruleset->phase_response_body); + merged->ruleset->phase_logging = apr_array_copy(mp, + child->ruleset->phase_logging); + } else { + #ifdef DEBUG_CONF + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Using parent then child rules in this context."); + #endif + + /* Copy parent rules, then add child rules to it. */ + merged->ruleset = msre_ruleset_create(parent->ruleset->engine, mp); + copy_rules(mp, parent->ruleset, merged->ruleset, child->rule_exceptions); + + apr_array_cat(merged->ruleset->phase_request_headers, + child->ruleset->phase_request_headers); + apr_array_cat(merged->ruleset->phase_request_body, + child->ruleset->phase_request_body); + apr_array_cat(merged->ruleset->phase_response_headers, + child->ruleset->phase_response_headers); + apr_array_cat(merged->ruleset->phase_response_body, + child->ruleset->phase_response_body); + apr_array_cat(merged->ruleset->phase_logging, + child->ruleset->phase_logging); + } + } else { + merged->rule_inheritance = 0; + if (child->ruleset != NULL) { + /* Copy child rules. */ + merged->ruleset = msre_ruleset_create(child->ruleset->engine, mp); + merged->ruleset->phase_request_headers = apr_array_copy(mp, + child->ruleset->phase_request_headers); + merged->ruleset->phase_request_body = apr_array_copy(mp, + child->ruleset->phase_request_body); + merged->ruleset->phase_response_headers = apr_array_copy(mp, + child->ruleset->phase_response_headers); + merged->ruleset->phase_response_body = apr_array_copy(mp, + child->ruleset->phase_response_body); + merged->ruleset->phase_logging = apr_array_copy(mp, + child->ruleset->phase_logging); + } + } + + /* Merge rule exceptions. */ + merged->rule_exceptions = apr_array_append(mp, parent->rule_exceptions, + child->rule_exceptions); + + /* audit log variables */ + merged->auditlog_flag = (child->auditlog_flag == NOT_SET + ? parent->auditlog_flag : child->auditlog_flag); + merged->auditlog_type = (child->auditlog_type == NOT_SET + ? parent->auditlog_type : child->auditlog_type); + merged->auditlog_dirperms = (child->auditlog_dirperms == NOT_SET + ? parent->auditlog_dirperms : child->auditlog_dirperms); + merged->auditlog_fileperms = (child->auditlog_fileperms == NOT_SET + ? parent->auditlog_fileperms : child->auditlog_fileperms); + if (child->auditlog_fd != NOT_SET_P) { + merged->auditlog_fd = child->auditlog_fd; + merged->auditlog_name = child->auditlog_name; + } else { + merged->auditlog_fd = parent->auditlog_fd; + merged->auditlog_name = parent->auditlog_name; + } + if (child->auditlog2_fd != NOT_SET_P) { + merged->auditlog2_fd = child->auditlog2_fd; + merged->auditlog2_name = child->auditlog2_name; + } else { + merged->auditlog2_fd = parent->auditlog2_fd; + merged->auditlog2_name = parent->auditlog2_name; + } + merged->auditlog_storage_dir = (child->auditlog_storage_dir == NOT_SET_P + ? parent->auditlog_storage_dir : child->auditlog_storage_dir); + merged->auditlog_parts = (child->auditlog_parts == NOT_SET_P + ? parent->auditlog_parts : child->auditlog_parts); + merged->auditlog_relevant_regex = (child->auditlog_relevant_regex == NOT_SET_P + ? parent->auditlog_relevant_regex : child->auditlog_relevant_regex); + + /* Upload */ + merged->tmp_dir = (child->tmp_dir == NOT_SET_P + ? parent->tmp_dir : child->tmp_dir); + merged->upload_dir = (child->upload_dir == NOT_SET_P + ? parent->upload_dir : child->upload_dir); + merged->upload_keep_files = (child->upload_keep_files == NOT_SET + ? parent->upload_keep_files : child->upload_keep_files); + merged->upload_validates_files = (child->upload_validates_files == NOT_SET + ? parent->upload_validates_files : child->upload_validates_files); + merged->upload_filemode = (child->upload_filemode == NOT_SET + ? parent->upload_filemode : child->upload_filemode); + + /* Misc */ + merged->data_dir = (child->data_dir == NOT_SET_P + ? parent->data_dir : child->data_dir); + merged->webappid = (child->webappid == NOT_SET_P + ? parent->webappid : child->webappid); + + /* Content injection. */ + merged->content_injection_enabled = (child->content_injection_enabled == NOT_SET + ? parent->content_injection_enabled : child->content_injection_enabled); + + /* PDF XSS protection. */ + merged->pdfp_enabled = (child->pdfp_enabled == NOT_SET + ? parent->pdfp_enabled : child->pdfp_enabled); + merged->pdfp_secret = (child->pdfp_secret == NOT_SET_P + ? parent->pdfp_secret : child->pdfp_secret); + merged->pdfp_timeout = (child->pdfp_timeout == NOT_SET + ? parent->pdfp_timeout : child->pdfp_timeout); + merged->pdfp_token_name = (child->pdfp_token_name == NOT_SET_P + ? parent->pdfp_token_name : child->pdfp_token_name); + merged->pdfp_only_get = (child->pdfp_only_get == NOT_SET + ? parent->pdfp_only_get : child->pdfp_only_get); + merged->pdfp_method = (child->pdfp_method == NOT_SET + ? parent->pdfp_method : child->pdfp_method); + + /* Geo Lookup */ + merged->geo = (child->geo == NOT_SET_P + ? parent->geo : child->geo); + + /* Cache */ + merged->cache_trans = (child->cache_trans == NOT_SET + ? parent->cache_trans : child->cache_trans); + merged->cache_trans_incremental = (child->cache_trans_incremental == NOT_SET + ? parent->cache_trans_incremental : child->cache_trans_incremental); + merged->cache_trans_min = (child->cache_trans_min == (apr_size_t)NOT_SET + ? parent->cache_trans_min : child->cache_trans_min); + merged->cache_trans_max = (child->cache_trans_max == (apr_size_t)NOT_SET + ? parent->cache_trans_max : child->cache_trans_max); + merged->cache_trans_maxitems = (child->cache_trans_maxitems == (apr_size_t)NOT_SET + ? parent->cache_trans_maxitems : child->cache_trans_maxitems); + + /* Merge component signatures. */ + merged->component_signatures = apr_array_append(mp, parent->component_signatures, + child->component_signatures); + + merged->request_encoding = (child->request_encoding == NOT_SET_P + ? parent->request_encoding : child->request_encoding); + + return merged; +} + +/** + * Initialise directory configuration. This function is *not* meant + * to be called for directory configuration instances created during + * the configuration phase. It can only be called on copies of those + * (created fresh for every transaction). + */ +void init_directory_config(directory_config *dcfg) { + if (dcfg == NULL) return; + + if (dcfg->is_enabled == NOT_SET) dcfg->is_enabled = 0; + + if (dcfg->reqbody_access == NOT_SET) dcfg->reqbody_access = 0; + if (dcfg->reqbody_buffering == NOT_SET) dcfg->reqbody_buffering = REQUEST_BODY_FORCEBUF_OFF; + if (dcfg->reqbody_inmemory_limit == NOT_SET) + dcfg->reqbody_inmemory_limit = REQUEST_BODY_DEFAULT_INMEMORY_LIMIT; + if (dcfg->reqbody_limit == NOT_SET) dcfg->reqbody_limit = REQUEST_BODY_DEFAULT_LIMIT; + if (dcfg->reqbody_no_files_limit == NOT_SET) dcfg->reqbody_no_files_limit = REQUEST_BODY_NO_FILES_DEFAULT_LIMIT; + if (dcfg->resbody_access == NOT_SET) dcfg->resbody_access = 0; + if (dcfg->of_limit == NOT_SET) dcfg->of_limit = RESPONSE_BODY_DEFAULT_LIMIT; + if (dcfg->of_limit_action == NOT_SET) dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_REJECT; + + if (dcfg->of_mime_types == NOT_SET_P) { + dcfg->of_mime_types = apr_table_make(dcfg->mp, 3); + if (dcfg->of_mime_types_cleared != 1) { + apr_table_setn(dcfg->of_mime_types, "text/plain", "1"); + apr_table_setn(dcfg->of_mime_types, "text/html", "1"); + } + } + + if (dcfg->debuglog_fd == NOT_SET_P) dcfg->debuglog_fd = NULL; + if (dcfg->debuglog_name == NOT_SET_P) dcfg->debuglog_name = NULL; + if (dcfg->debuglog_level == NOT_SET) dcfg->debuglog_level = 0; + + if (dcfg->cookie_format == NOT_SET) dcfg->cookie_format = 0; + if (dcfg->argument_separator == NOT_SET) dcfg->argument_separator = '&'; + + if (dcfg->rule_inheritance == NOT_SET) dcfg->rule_inheritance = 1; + + /* audit log variables */ + if (dcfg->auditlog_flag == NOT_SET) dcfg->auditlog_flag = 0; + if (dcfg->auditlog_type == NOT_SET) dcfg->auditlog_type = AUDITLOG_SERIAL; + if (dcfg->auditlog_dirperms == NOT_SET) dcfg->auditlog_dirperms = CREATEMODE_DIR; + if (dcfg->auditlog_fileperms == NOT_SET) dcfg->auditlog_fileperms = CREATEMODE; + if (dcfg->auditlog_fd == NOT_SET_P) dcfg->auditlog_fd = NULL; + if (dcfg->auditlog2_fd == NOT_SET_P) dcfg->auditlog2_fd = NULL; + if (dcfg->auditlog_name == NOT_SET_P) dcfg->auditlog_name = NULL; + if (dcfg->auditlog2_name == NOT_SET_P) dcfg->auditlog2_name = NULL; + if (dcfg->auditlog_storage_dir == NOT_SET_P) dcfg->auditlog_storage_dir = NULL; + if (dcfg->auditlog_parts == NOT_SET_P) dcfg->auditlog_parts = "ABCFHZ"; + if (dcfg->auditlog_relevant_regex == NOT_SET_P) dcfg->auditlog_relevant_regex = NULL; + + /* Upload */ + if (dcfg->tmp_dir == NOT_SET_P) dcfg->tmp_dir = guess_tmp_dir(dcfg->mp); + if (dcfg->upload_dir == NOT_SET_P) dcfg->upload_dir = NULL; + if (dcfg->upload_keep_files == NOT_SET) dcfg->upload_keep_files = KEEP_FILES_OFF; + if (dcfg->upload_validates_files == NOT_SET) dcfg->upload_validates_files = 0; + if (dcfg->upload_filemode == NOT_SET) dcfg->upload_filemode = mode2fileperms(0600); + + /* Misc */ + if (dcfg->data_dir == NOT_SET_P) dcfg->data_dir = NULL; + if (dcfg->webappid == NOT_SET_P) dcfg->webappid = "default"; + + /* Content injection. */ + if (dcfg->content_injection_enabled == NOT_SET) dcfg->content_injection_enabled = 0; + + /* PDF XSS protection. */ + if (dcfg->pdfp_enabled == NOT_SET) dcfg->pdfp_enabled = 0; + if (dcfg->pdfp_secret == NOT_SET_P) dcfg->pdfp_secret = NULL; + if (dcfg->pdfp_timeout == NOT_SET) dcfg->pdfp_timeout = 10; + if (dcfg->pdfp_token_name == NOT_SET_P) dcfg->pdfp_token_name = "PDFPTOKEN"; + if (dcfg->pdfp_only_get == NOT_SET) dcfg->pdfp_only_get = 1; + if (dcfg->pdfp_method == NOT_SET) dcfg->pdfp_method = PDF_PROTECT_METHOD_TOKEN_REDIRECTION; + + /* Geo Lookup */ + if (dcfg->geo == NOT_SET_P) dcfg->geo = NULL; + + /* Cache */ + if (dcfg->cache_trans == NOT_SET) dcfg->cache_trans = MODSEC_CACHE_DISABLED; + if (dcfg->cache_trans_incremental == NOT_SET) dcfg->cache_trans_incremental = 0; + if (dcfg->cache_trans_min == (apr_size_t)NOT_SET) dcfg->cache_trans_min = 32; + if (dcfg->cache_trans_max == (apr_size_t)NOT_SET) dcfg->cache_trans_max = 1024; + if (dcfg->cache_trans_maxitems == (apr_size_t)NOT_SET) dcfg->cache_trans_maxitems = 512; + + if (dcfg->request_encoding == NOT_SET_P) dcfg->request_encoding = NULL; +} + +/** + * + */ +static const char *add_rule(cmd_parms *cmd, directory_config *dcfg, int type, + const char *p1, const char *p2, const char *p3) +{ + char *my_error_msg = NULL; + msre_rule *rule = NULL; + extern msc_engine *modsecurity; + + #ifdef DEBUG_CONF + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, + "Rule: type=%d p1='%s' p2='%s' p3='%s'", type, p1, p2, p3); + #endif + + /* Create a ruleset if one does not exist. */ + if ((dcfg->ruleset == NULL)||(dcfg->ruleset == NOT_SET_P)) { + dcfg->ruleset = msre_ruleset_create(modsecurity->msre, cmd->pool); + if (dcfg->ruleset == NULL) return FATAL_ERROR; + } + + /* Create the rule now. */ + switch(type) { + #if defined(WITH_LUA) + case RULE_TYPE_LUA : + rule = msre_rule_lua_create(dcfg->ruleset, cmd->directive->filename, + cmd->directive->line_num, p1, p2, &my_error_msg); + break; + #endif + default : + rule = msre_rule_create(dcfg->ruleset, type, cmd->directive->filename, + cmd->directive->line_num, p1, p2, p3, &my_error_msg); + break; + } + + if (rule == NULL) { + return my_error_msg; + } + + /* Create default actionset if one does not already exist. */ + if (dcfg->tmp_default_actionset == NULL) { + dcfg->tmp_default_actionset = msre_actionset_create_default(modsecurity->msre); + if (dcfg->tmp_default_actionset == NULL) return FATAL_ERROR; + } + + /* Check some cases prior to merging so we know where it came from */ + + /* Check syntax for chained rules */ + if ((rule->actionset != NULL) && (dcfg->tmp_chain_starter != NULL)) { + /* Must NOT specify a disruptive action. */ + if (rule->actionset->intercept_action != NOT_SET) { + return apr_psprintf(cmd->pool, "ModSecurity: Disruptive actions can only " + "be specified by chain starter rules."); + } + + /* Must NOT specify a phase. */ + if (rule->actionset->phase != NOT_SET) { + return apr_psprintf(cmd->pool, "ModSecurity: Execution phases can only be " + "specified by chain starter rules."); + } + + /* Must NOT use metadata actions. */ + /* ENH: loop through to check for tags */ + if ((rule->actionset->id != NOT_SET_P) + ||(rule->actionset->rev != NOT_SET_P) + ||(rule->actionset->msg != NOT_SET_P) + ||(rule->actionset->severity != NOT_SET) + ||(rule->actionset->logdata != NOT_SET_P)) + { + return apr_psprintf(cmd->pool, "ModSecurity: Metadata actions (id, rev, msg, tag, severity, logdata) " + " can only be specified by chain starter rules."); + } + + /* Must NOT use skip. */ + if (rule->actionset->skip_count != NOT_SET) { + return apr_psprintf(cmd->pool, "ModSecurity: The skip action can only be used " + " by chain starter rules. "); + } + } + + /* Merge actions with the parent. + * + * ENH Probably do not want this done fully for chained rules. + */ + rule->actionset = msre_actionset_merge(modsecurity->msre, dcfg->tmp_default_actionset, + rule->actionset, 1); + + /* Keep track of the parent action for "block" */ + rule->actionset->parent_intercept_action_rec = dcfg->tmp_default_actionset->intercept_action_rec; + rule->actionset->parent_intercept_action = dcfg->tmp_default_actionset->intercept_action; + + /* Must NOT specify a disruptive action in logging phase. */ + if ((rule->actionset != NULL) + && (rule->actionset->phase == PHASE_LOGGING) + && (rule->actionset->intercept_action != ACTION_ALLOW) + && (rule->actionset->intercept_action != ACTION_ALLOW_REQUEST) + && (rule->actionset->intercept_action != ACTION_NONE) + ) { + return apr_psprintf(cmd->pool, "ModSecurity: Disruptive actions " + "cannot be specified in the logging phase."); + } + + if (dcfg->tmp_chain_starter != NULL) { + rule->chain_starter = dcfg->tmp_chain_starter; + rule->actionset->phase = rule->chain_starter->actionset->phase; + } + + if (rule->actionset->is_chained != 1) { + /* If this rule is part of the chain but does + * not want more rules to follow in the chain + * then cut it (the chain). + */ + dcfg->tmp_chain_starter = NULL; + } else { + /* On the other hand, if this rule wants other + * rules to follow it, then start a new chain + * if there isn't one already. + */ + if (dcfg->tmp_chain_starter == NULL) { + dcfg->tmp_chain_starter = rule; + } + } + + /* Optimisation */ + if ((rule->op_name != NULL)&&(strcasecmp(rule->op_name, "inspectFile") == 0)) { + dcfg->upload_validates_files = 1; + } + + /* Create skip table if one does not already exist. */ + if (dcfg->tmp_rule_placeholders == NULL) { + dcfg->tmp_rule_placeholders = apr_table_make(cmd->pool, 10); + if (dcfg->tmp_rule_placeholders == NULL) return FATAL_ERROR; + } + + /* Keep track of any rule IDs we need to skip after */ + if (rule->actionset->skip_after != NOT_SET_P) { + char *tmp_id = apr_pstrdup(cmd->pool, rule->actionset->skip_after); + apr_table_setn(dcfg->tmp_rule_placeholders, tmp_id, tmp_id); + + #ifdef DEBUG_CONF + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, + "Watching for skipafter target rule id=\"%s\".", tmp_id); + #endif + + } + + #ifdef DEBUG_CONF + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, + "Adding rule %pp phase=%d id=\"%s\".", rule, rule->actionset->phase, (rule->actionset->id == NOT_SET_P + ? "(none)" : rule->actionset->id)); + #endif + + /* Add rule to the recipe. */ + if (msre_ruleset_rule_add(dcfg->ruleset, rule, rule->actionset->phase) < 0) { + return "Internal Error: Failed to add rule to the ruleset."; + } + + /* Add an additional placeholder if this rule ID is on the list */ + if ((rule->actionset->id != NULL) && apr_table_get(dcfg->tmp_rule_placeholders, rule->actionset->id)) { + msre_rule *phrule = apr_palloc(rule->ruleset->mp, sizeof(msre_rule)); + if (phrule == NULL) { + return FATAL_ERROR; + } + + #ifdef DEBUG_CONF + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, + "Adding placeholder %pp for rule %pp id=\"%s\".", phrule, rule, rule->actionset->id); + #endif + + /* shallow copy of original rule with placeholder marked as target */ + memcpy(phrule, rule, sizeof(msre_rule)); + phrule->placeholder = RULE_PH_SKIPAFTER; + + /* Add placeholder. */ + if (msre_ruleset_rule_add(dcfg->ruleset, phrule, phrule->actionset->phase) < 0) { + return "Internal Error: Failed to add placeholder to the ruleset."; + } + + /* No longer need to search for the ID */ + apr_table_unset(dcfg->tmp_rule_placeholders, rule->actionset->id); + } + + /* Update the unparsed rule */ + rule->unparsed = msre_rule_generate_unparsed(dcfg->ruleset->mp, rule, NULL, NULL, NULL); + + return NULL; +} + +/** + * + */ +static const char *add_marker(cmd_parms *cmd, directory_config *dcfg, const char *p1, + const char *p2, const char *p3) +{ + char *my_error_msg = NULL; + msre_rule *rule = NULL; + extern msc_engine *modsecurity; + int p; + + #ifdef DEBUG_CONF + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, + "Rule: type=%d p1='%s' p2='%s' p3='%s'", RULE_TYPE_MARKER, p1, p2, p3); + #endif + + /* Create a ruleset if one does not exist. */ + if ((dcfg->ruleset == NULL)||(dcfg->ruleset == NOT_SET_P)) { + dcfg->ruleset = msre_ruleset_create(modsecurity->msre, cmd->pool); + if (dcfg->ruleset == NULL) return FATAL_ERROR; + } + + /* Create the rule now. */ + rule = msre_rule_create(dcfg->ruleset, RULE_TYPE_MARKER, cmd->directive->filename, cmd->directive->line_num, p1, p2, p3, &my_error_msg); + if (rule == NULL) { + return my_error_msg; + } + + /* This is a marker */ + rule->placeholder = RULE_PH_MARKER; + + /* Add placeholder to each phase */ + for (p = PHASE_FIRST; p <= PHASE_LAST; p++) { + #ifdef DEBUG_CONF + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, + "Adding marker %pp phase=%d id=\"%s\".", rule, p, (rule->actionset->id == NOT_SET_P + ? "(none)" : rule->actionset->id)); + #endif + + if (msre_ruleset_rule_add(dcfg->ruleset, rule, p) < 0) { + return "Internal Error: Failed to add marker to the ruleset."; + } + } + + /* No longer need to search for the ID */ + if (dcfg->tmp_rule_placeholders != NULL) { + apr_table_unset(dcfg->tmp_rule_placeholders, rule->actionset->id); + } + + return NULL; +} + +/** + * + */ +static const char *update_rule_action(cmd_parms *cmd, directory_config *dcfg, + const char *p1, const char *p2) +{ + char *my_error_msg = NULL; + msre_rule *rule = NULL; + msre_actionset *new_actionset = NULL; + msre_ruleset *ruleset = dcfg->ruleset; + extern msc_engine *modsecurity; + + /* Get the ruleset if one exists */ + if ((ruleset == NULL)||(ruleset == NOT_SET_P)) { + return NULL; + } + + #ifdef DEBUG_CONF + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, + "Update rule id=\"%s\" with action \"%s\".", p1, p2); + #endif + + /* Fetch the rule */ + rule = msre_ruleset_fetch_rule(ruleset, p1); + if (rule == NULL) { + #ifdef DEBUG_CONF + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, + "Update rule id=\"%s\" with action \"%s\" failed: Rule not found.", p1, p2); + #endif + return NULL; + } + + /* Check the rule actionset */ + /* ENH: Can this happen? */ + if (rule->actionset == NULL) { + return apr_psprintf(cmd->pool, "ModSecurity: Attempt to update action for rule \"%s\" failed: Rule does not have an actionset.", p1); + } + + /* Create a new actionset */ + new_actionset = msre_actionset_create(modsecurity->msre, p2, &my_error_msg); + if (new_actionset == NULL) return FATAL_ERROR; + if (my_error_msg != NULL) return my_error_msg; + + /* Must NOT change an id */ + if ((new_actionset->id != NOT_SET_P) && (rule->actionset->id != NULL) && (strcmp(rule->actionset->id, new_actionset->id) != 0)) { + return apr_psprintf(cmd->pool, "ModSecurity: Rule IDs cannot be updated via SecRuleUpdateActionById."); + } + + /* Must NOT alter the phase */ + if ((new_actionset->phase != NOT_SET) && (rule->actionset->phase != new_actionset->phase)) { + return apr_psprintf(cmd->pool, "ModSecurity: Rule phases cannot be updated via SecRuleUpdateActionById."); + } + + #ifdef DEBUG_CONF + { + char *actions = msre_actionset_generate_action_string(ruleset->mp, rule->actionset); + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, + "Update rule %pp id=\"%s\" old action: \"%s\"", + rule, + (rule->actionset->id == NOT_SET_P ? "(none)" : rule->actionset->id), + actions); + } + #endif + + /* Merge new actions with the rule */ + /* ENH: Will this leak the old actionset? */ + rule->actionset = msre_actionset_merge(modsecurity->msre, rule->actionset, + new_actionset, 1); + msre_actionset_set_defaults(rule->actionset); + + /* Update the unparsed rule */ + rule->unparsed = msre_rule_generate_unparsed(ruleset->mp, rule, NULL, NULL, NULL); + + #ifdef DEBUG_CONF + { + char *actions = msre_actionset_generate_action_string(ruleset->mp, rule->actionset); + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, + "Update rule %pp id=\"%s\" new action: \"%s\"", + rule, + (rule->actionset->id == NOT_SET_P ? "(none)" : rule->actionset->id), + actions); + } + #endif + + return NULL; +} + +/* -- Configuration directives -- */ + +static const char *cmd_action(cmd_parms *cmd, void *_dcfg, const char *p1) { + return add_rule(cmd, (directory_config *)_dcfg, RULE_TYPE_ACTION, SECACTION_TARGETS, SECACTION_ARGS, p1); +} + +static const char *cmd_marker(cmd_parms *cmd, void *_dcfg, const char *p1) { + directory_config *dcfg = (directory_config *)_dcfg; + const char *action = apr_pstrcat(dcfg->mp, SECMARKER_BASE_ACTIONS, p1, NULL); + return add_marker(cmd, (directory_config *)_dcfg, SECMARKER_TARGETS, SECMARKER_ARGS, action); +} + +static const char *cmd_argument_separator(cmd_parms *cmd, void *_dcfg, const char *p1) { + directory_config *dcfg = (directory_config *)_dcfg; + + if (strlen(p1) != 1) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid argument separator: %s", p1); + } + + dcfg->argument_separator = p1[0]; + + return NULL; +} + +static const char *cmd_audit_engine(cmd_parms *cmd, void *_dcfg, const char *p1) { + directory_config *dcfg = _dcfg; + + if (strcasecmp(p1, "On") == 0) dcfg->auditlog_flag = AUDITLOG_ON; + else + if (strcasecmp(p1, "Off") == 0) dcfg->auditlog_flag = AUDITLOG_OFF; + else + if (strcasecmp(p1, "RelevantOnly") == 0) dcfg->auditlog_flag = AUDITLOG_RELEVANT; + else + return (const char *)apr_psprintf(cmd->pool, + "ModSecurity: Unrecognised parameter value for SecAuditEngine: %s", p1); + + return NULL; +} + +static const char *cmd_audit_log(cmd_parms *cmd, void *_dcfg, const char *p1) { + directory_config *dcfg = _dcfg; + + dcfg->auditlog_name = (char *)p1; + + if (dcfg->auditlog_name[0] == '|') { + const char *pipe_name = ap_server_root_relative(cmd->pool, dcfg->auditlog_name + 1); + piped_log *pipe_log; + + pipe_log = ap_open_piped_log(cmd->pool, pipe_name); + if (pipe_log == NULL) { + return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the audit log pipe: %s", + pipe_name); + } + dcfg->auditlog_fd = ap_piped_log_write_fd(pipe_log); + } + else { + const char *file_name = ap_server_root_relative(cmd->pool, dcfg->auditlog_name); + apr_status_t rc; + + rc = apr_file_open(&dcfg->auditlog_fd, file_name, + APR_WRITE | APR_APPEND | APR_CREATE | APR_BINARY, + CREATEMODE, cmd->pool); + + if (rc != APR_SUCCESS) { + return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the audit log file: %s", + file_name); + } + } + + return NULL; +} + +static const char *cmd_audit_log2(cmd_parms *cmd, void *_dcfg, const char *p1) { + directory_config *dcfg = _dcfg; + + if (dcfg->auditlog_name == NOT_SET_P) { + return apr_psprintf(cmd->pool, "ModSecurity: Cannot configure a secondary audit log without a primary defined: %s", p1); + } + + dcfg->auditlog2_name = (char *)p1; + + if (dcfg->auditlog2_name[0] == '|') { + const char *pipe_name = ap_server_root_relative(cmd->pool, dcfg->auditlog2_name + 1); + piped_log *pipe_log; + + pipe_log = ap_open_piped_log(cmd->pool, pipe_name); + if (pipe_log == NULL) { + return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the secondary audit log pipe: %s", + pipe_name); + } + dcfg->auditlog2_fd = ap_piped_log_write_fd(pipe_log); + } + else { + const char *file_name = ap_server_root_relative(cmd->pool, dcfg->auditlog2_name); + apr_status_t rc; + + rc = apr_file_open(&dcfg->auditlog2_fd, file_name, + APR_WRITE | APR_APPEND | APR_CREATE | APR_BINARY, + CREATEMODE, cmd->pool); + + if (rc != APR_SUCCESS) { + return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the secondary audit log file: %s", + file_name); + } + } + + return NULL; +} + +static const char *cmd_audit_log_parts(cmd_parms *cmd, void *_dcfg, const char *p1) { + directory_config *dcfg = _dcfg; + + if (is_valid_parts_specification((char *)p1) != 1) { + return apr_psprintf(cmd->pool, "Invalid parts specification for SecAuditLogParts: %s", p1); + } + + dcfg->auditlog_parts = (char *)p1; + return NULL; +} + +static const char *cmd_audit_log_relevant_status(cmd_parms *cmd, void *_dcfg, const char *p1) { + directory_config *dcfg = _dcfg; + + dcfg->auditlog_relevant_regex = msc_pregcomp(cmd->pool, p1, PCRE_DOTALL, NULL, NULL); + if (dcfg->auditlog_relevant_regex == NULL) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p1); + } + + return NULL; +} + +static const char *cmd_audit_log_type(cmd_parms *cmd, void *_dcfg, const char *p1) { + directory_config *dcfg = _dcfg; + + if (strcasecmp(p1, "Serial") == 0) dcfg->auditlog_type = AUDITLOG_SERIAL; + else + if (strcasecmp(p1, "Concurrent") == 0) dcfg->auditlog_type = AUDITLOG_CONCURRENT; + else + return (const char *)apr_psprintf(cmd->pool, + "ModSecurity: Unrecognised parameter value for SecAuditLogType: %s", p1); + + return NULL; +} + +static const char *cmd_audit_log_dirmode(cmd_parms *cmd, void *_dcfg, const char *p1) { + directory_config *dcfg = (directory_config *)_dcfg; + + if (dcfg == NULL) return NULL; + + if (strcasecmp(p1, "default") == 0) { + dcfg->auditlog_dirperms = NOT_SET; + } + else { + long int mode = strtol(p1, NULL, 8); /* expects octal mode */ + if ((mode == LONG_MAX)||(mode == LONG_MIN)||(mode <= 0)||(mode > 07777)) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecAuditLogDirMode: %s", p1); + } + + dcfg->auditlog_dirperms = mode2fileperms(mode); + } + + return NULL; +} + +static const char *cmd_audit_log_filemode(cmd_parms *cmd, void *_dcfg, const char *p1) { + directory_config *dcfg = (directory_config *)_dcfg; + + if (dcfg == NULL) return NULL; + + if (strcasecmp(p1, "default") == 0) { + dcfg->auditlog_fileperms = NOT_SET; + } + else { + long int mode = strtol(p1, NULL, 8); /* expects octal mode */ + if ((mode == LONG_MAX)||(mode == LONG_MIN)||(mode <= 0)||(mode > 07777)) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecAuditLogFileMode: %s", p1); + } + + dcfg->auditlog_fileperms = mode2fileperms(mode); + } + + return NULL; +} + +static const char *cmd_audit_log_storage_dir(cmd_parms *cmd, void *_dcfg, const char *p1) { + directory_config *dcfg = _dcfg; + + dcfg->auditlog_storage_dir = ap_server_root_relative(cmd->pool, p1); + + return NULL; +} + +static const char *cmd_cookie_format(cmd_parms *cmd, void *_dcfg, const char *p1) { + directory_config *dcfg = (directory_config *)_dcfg; + + if (strcmp(p1, "0") == 0) dcfg->cookie_format = COOKIES_V0; + else + if (strcmp(p1, "1") == 0) dcfg->cookie_format = COOKIES_V1; + else { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid cookie format: %s", p1); + } + + return NULL; +} + +static const char *cmd_chroot_dir(cmd_parms *cmd, void *_dcfg, const char *p1) { + char cwd[1025] = ""; + + if (cmd->server->is_virtual) { + return "ModSecurity: SecChrootDir not allowed in VirtualHost"; + } + + chroot_dir = (char *)p1; + + if (getcwd(cwd, 1024) == NULL) { + return "ModSecurity: Failed to get the current working directory"; + } + + if (chdir(chroot_dir) < 0) { + return apr_psprintf(cmd->pool, "ModSecurity: Failed to chdir to %s, errno=%d (%s)", + chroot_dir, errno, strerror(errno)); + } + + if (chdir(cwd) < 0) { + return apr_psprintf(cmd->pool, "ModSecurity: Failed to chdir to %s, errno=%d (%s)", + cwd, errno, strerror(errno)); + } + + return NULL; +} + +/** + * Adds component signature to the list of signatures kept in configuration. + */ +static const char *cmd_component_signature(cmd_parms *cmd, void *_dcfg, const char *p1) { + directory_config *dcfg = (directory_config *)_dcfg; + + /* ENH Enforce "Name/VersionX.Y.Z (comment)" format. */ + *(char **)apr_array_push(dcfg->component_signatures) = (char *)p1; + + return NULL; +} + +static const char *cmd_content_injection(cmd_parms *cmd, void *_dcfg, int flag) { + directory_config *dcfg = (directory_config *)_dcfg; + if (dcfg == NULL) return NULL; + dcfg->content_injection_enabled = flag; + return NULL; +} + +static const char *cmd_data_dir(cmd_parms *cmd, void *_dcfg, const char *p1) { + directory_config *dcfg = (directory_config *)_dcfg; + + if (cmd->server->is_virtual) { + return "ModSecurity: SecDataDir not allowed in VirtualHost."; + } + + dcfg->data_dir = ap_server_root_relative(cmd->pool, p1); + + return NULL; +} + +static const char *cmd_debug_log(cmd_parms *cmd, void *_dcfg, const char *p1) { + directory_config *dcfg = (directory_config *)_dcfg; + apr_status_t rc; + + dcfg->debuglog_name = ap_server_root_relative(cmd->pool, p1); + + rc = apr_file_open(&dcfg->debuglog_fd, dcfg->debuglog_name, + APR_WRITE | APR_APPEND | APR_CREATE | APR_BINARY, + CREATEMODE, cmd->pool); + + if (rc != APR_SUCCESS) { + return apr_psprintf(cmd->pool, "ModSecurity: Failed to open debug log file: %s", + dcfg->debuglog_name); + } + + return NULL; +} + +static const char *cmd_debug_log_level(cmd_parms *cmd, void *_dcfg, const char *p1) { + directory_config *dcfg = (directory_config *)_dcfg; + + dcfg->debuglog_level = atoi(p1); + if ((dcfg->debuglog_level >= 0)&&(dcfg->debuglog_level <= 9)) return NULL; + + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecDebugLogLevel: %s", p1); +} + +static const char *cmd_default_action(cmd_parms *cmd, void *_dcfg, const char *p1) { + directory_config *dcfg = (directory_config *)_dcfg; + extern msc_engine *modsecurity; + char *my_error_msg = NULL; + + dcfg->tmp_default_actionset = msre_actionset_create(modsecurity->msre, p1, &my_error_msg); + if (dcfg->tmp_default_actionset == NULL) { + if (my_error_msg != NULL) return my_error_msg; + else return FATAL_ERROR; + } + + /* Must specify a disruptive action. */ + /* ENH: Remove this requirement? */ + if (dcfg->tmp_default_actionset->intercept_action == NOT_SET) { + return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must specify a disruptive action."); + } + + /* Must specify a phase. */ + /* ENH: Remove this requirement? */ + if (dcfg->tmp_default_actionset->phase == NOT_SET) { + return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must specify a phase."); + } + + /* Must not use metadata actions. */ + /* ENH: loop through to check for tags */ + if ((dcfg->tmp_default_actionset->id != NOT_SET_P) + ||(dcfg->tmp_default_actionset->rev != NOT_SET_P) + ||(dcfg->tmp_default_actionset->msg != NOT_SET_P)) + { + return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must not " + "contain any metadata actions (id, rev, msg, tag, severity, logdata)."); + } + /* These are just a warning for now. */ + if ((dcfg->tmp_default_actionset->severity != NOT_SET) + ||(dcfg->tmp_default_actionset->logdata != NOT_SET_P)) + { + ap_log_perror(APLOG_MARK, + APLOG_STARTUP|APLOG_WARNING|APLOG_NOERRNO, 0, cmd->pool, + "ModSecurity: WARNING Using \"severity\" or \"logdata\" in " + "SecDefaultAction is deprecated (%s:%d).", + cmd->directive->filename, cmd->directive->line_num); + } + + /* Must not use chain. */ + if (dcfg->tmp_default_actionset->is_chained != NOT_SET) { + return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must not " + "contain a chain action."); + } + + /* Must not use skip. */ + if (dcfg->tmp_default_actionset->skip_count != NOT_SET) { + return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must not " + "contain a skip action."); + } + + /* Must not use skipAfter. */ + if (dcfg->tmp_default_actionset->skip_after != NOT_SET_P) { + return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must not " + "contain a skipAfter action."); + } + + return NULL; +} + +static const char *cmd_guardian_log(cmd_parms *cmd, void *_dcfg, const char *p1, const char *p2) { + extern char *guardianlog_name; + extern apr_file_t *guardianlog_fd; + extern char *guardianlog_condition; + + if (cmd->server->is_virtual) { + return "ModSecurity: SecGuardianLog not allowed in VirtualHost"; + } + + if (p2 != NULL) { + if (strncmp(p2, "env=", 4) != 0) { + return "ModSecurity: Error in condition clause"; + } + if ( (p2[4] == '\0') || ((p2[4] == '!')&&(p2[5] == '\0')) ) { + return "ModSecurity: Missing variable name"; + } + guardianlog_condition = apr_pstrdup(cmd->pool, p2 + 4); + } + + guardianlog_name = (char *)p1; + + if (guardianlog_name[0] == '|') { + const char *pipe_name = ap_server_root_relative(cmd->pool, guardianlog_name + 1); + piped_log *pipe_log; + + pipe_log = ap_open_piped_log(cmd->pool, pipe_name); + if (pipe_log == NULL) { + return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the guardian log pipe: %s", + pipe_name); + } + guardianlog_fd = ap_piped_log_write_fd(pipe_log); + } + else { + const char *file_name = ap_server_root_relative(cmd->pool, guardianlog_name); + apr_status_t rc; + + rc = apr_file_open(&guardianlog_fd, file_name, + APR_WRITE | APR_APPEND | APR_CREATE | APR_BINARY, + CREATEMODE, cmd->pool); + + if (rc != APR_SUCCESS) { + return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the guardian log file: %s", + file_name); + } + } + + return NULL; +} + +static const char *cmd_request_body_inmemory_limit(cmd_parms *cmd, void *_dcfg, const char *p1) { + directory_config *dcfg = (directory_config *)_dcfg; + long int limit; + + if (dcfg == NULL) return NULL; + + limit = strtol(p1, NULL, 10); + if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRequestBodyInMemoryLimit: %s", p1); + } + + dcfg->reqbody_inmemory_limit = limit; + + return NULL; +} + +static const char *cmd_request_body_limit(cmd_parms *cmd, void *_dcfg, const char *p1) { + directory_config *dcfg = (directory_config *)_dcfg; + long int limit; + + if (dcfg == NULL) return NULL; + + limit = strtol(p1, NULL, 10); + if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRequestBodyLimit: %s", p1); + } + + dcfg->reqbody_limit = limit; + + return NULL; +} + +static const char *cmd_request_body_no_files_limit(cmd_parms *cmd, void *_dcfg, const char *p1) { + directory_config *dcfg = (directory_config *)_dcfg; + long int limit; + + if (dcfg == NULL) return NULL; + + limit = strtol(p1, NULL, 10); + if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRequestBodyNoFilesLimit: %s", p1); + } + + dcfg->reqbody_no_files_limit = limit; + + return NULL; +} + +static const char *cmd_request_body_access(cmd_parms *cmd, void *_dcfg, const char *p1) { + directory_config *dcfg = (directory_config *)_dcfg; + if (dcfg == NULL) return NULL; + + if (strcasecmp(p1, "on") == 0) dcfg->reqbody_access = 1; + else + if (strcasecmp(p1, "off") == 0) dcfg->reqbody_access = 0; + else + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRequestBodyAccess: %s", p1); + + return NULL; +} + +static const char *cmd_request_encoding(cmd_parms *cmd, void *_dcfg, const char *p1) { + directory_config *dcfg = (directory_config *)_dcfg; + if (dcfg == NULL) return NULL; + + /* ENH Validate encoding */ + + dcfg->request_encoding = p1; + + return NULL; +} + +static const char *cmd_response_body_access(cmd_parms *cmd, void *_dcfg, const char *p1) { + directory_config *dcfg = (directory_config *)_dcfg; + if (dcfg == NULL) return NULL; + + if (strcasecmp(p1, "on") == 0) dcfg->resbody_access = 1; + else + if (strcasecmp(p1, "off") == 0) dcfg->resbody_access = 0; + else + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecResponseBodyAccess: %s", p1); + + return NULL; +} + +static const char *cmd_response_body_limit(cmd_parms *cmd, void *_dcfg, const char *p1) { + directory_config *dcfg = (directory_config *)_dcfg; + long int limit; + + limit = strtol(p1, NULL, 10); + if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecResponseBodyLimit: %s", p1); + } + + if (limit > RESPONSE_BODY_HARD_LIMIT) { + return apr_psprintf(cmd->pool, "ModSecurity: Response size limit can not exceed the hard limit: %li", RESPONSE_BODY_HARD_LIMIT); + } + + dcfg->of_limit = limit; + + return NULL; +} + +static const char *cmd_response_body_limit_action(cmd_parms *cmd, void *_dcfg, const char *p1) { + directory_config *dcfg = (directory_config *)_dcfg; + if (dcfg == NULL) return NULL; + + if (strcasecmp(p1, "ProcessPartial") == 0) dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_PARTIAL; + else + if (strcasecmp(p1, "Reject") == 0) dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_REJECT; + else + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecResponseBodyLimitAction: %s", p1); + + return NULL; +} + +static const char *cmd_response_body_mime_type(cmd_parms *cmd, void *_dcfg, const char *_p1) { + directory_config *dcfg = (directory_config *)_dcfg; + char *p1 = apr_pstrdup(cmd->pool, _p1); + + /* TODO check whether the parameter is a valid MIME type of "???" */ + + if ((dcfg->of_mime_types == NULL)||(dcfg->of_mime_types == NOT_SET_P)) { + dcfg->of_mime_types = apr_table_make(cmd->pool, 10); + } + + strtolower_inplace((unsigned char *)p1); + apr_table_setn(dcfg->of_mime_types, p1, "1"); + + return NULL; +} + +static const char *cmd_response_body_mime_types_clear(cmd_parms *cmd, void *_dcfg) { + directory_config *dcfg = (directory_config *)_dcfg; + if (dcfg == NULL) return NULL; + + dcfg->of_mime_types_cleared = 1; + + if ((dcfg->of_mime_types != NULL)&&(dcfg->of_mime_types != NOT_SET_P)) { + apr_table_clear(dcfg->of_mime_types); + } + + return NULL; +} + +static const char *cmd_rule(cmd_parms *cmd, void *_dcfg, const char *p1, + const char *p2, const char *p3) +{ + return add_rule(cmd, (directory_config *)_dcfg, RULE_TYPE_NORMAL, p1, p2, p3); +} + +static const char *cmd_rule_engine(cmd_parms *cmd, void *_dcfg, const char *p1) { + directory_config *dcfg = (directory_config *)_dcfg; + if (dcfg == NULL) return NULL; + + if (strcasecmp(p1, "on") == 0) dcfg->is_enabled = MODSEC_ENABLED; + else + if (strcasecmp(p1, "off") == 0) dcfg->is_enabled = MODSEC_DISABLED; + else + if (strcasecmp(p1, "detectiononly") == 0) dcfg->is_enabled = MODSEC_DETECTION_ONLY; + else + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRuleEngine: %s", p1); + + return NULL; +} + +/* +static const char *cmd_rule_import_by_id(cmd_parms *cmd, void *_dcfg, const char *p1) { + directory_config *dcfg = (directory_config *)_dcfg; + rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception)); + if (dcfg == NULL) return NULL; + + re->type = RULE_EXCEPTION_IMPORT_ID; + // TODO verify p1 + re->param = p1; + *(rule_exception **)apr_array_push(dcfg->rule_exceptions) = re; + + return NULL; +} + +static const char *cmd_rule_import_by_msg(cmd_parms *cmd, void *_dcfg, const char *p1) { + directory_config *dcfg = (directory_config *)_dcfg; + rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception)); + if (dcfg == NULL) return NULL; + + re->type = RULE_EXCEPTION_IMPORT_MSG; + // TODO verify p1 + re->param = p1; + *(rule_exception **)apr_array_push(dcfg->rule_exceptions) = re; + + return NULL; +} +*/ + +static const char *cmd_rule_inheritance(cmd_parms *cmd, void *_dcfg, int flag) { + directory_config *dcfg = (directory_config *)_dcfg; + if (dcfg == NULL) return NULL; + dcfg->rule_inheritance = flag; + return NULL; +} + +static const char *cmd_rule_script(cmd_parms *cmd, void *_dcfg, const char *p1, + const char *p2) +{ + #if defined(WITH_LUA) + const char *filename = resolve_relative_path(cmd->pool, cmd->directive->filename, p1); + return add_rule(cmd, (directory_config *)_dcfg, RULE_TYPE_LUA, filename, p2, NULL); + #else + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, "Ignoring SecRuleScript \"%s\" directive (%s:%d): No Lua scripting support.", p1, cmd->directive->filename, cmd->directive->line_num); + return NULL; + #endif +} + +static const char *cmd_rule_remove_by_id(cmd_parms *cmd, void *_dcfg, const char *p1) { + directory_config *dcfg = (directory_config *)_dcfg; + rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception)); + if (dcfg == NULL) return NULL; + + re->type = RULE_EXCEPTION_REMOVE_ID; + re->param = p1; + *(rule_exception **)apr_array_push(dcfg->rule_exceptions) = re; + + /* Remove the corresponding rules from the context straight away. */ + msre_ruleset_rule_remove_with_exception(dcfg->ruleset, re); + + return NULL; +} + +static const char *cmd_rule_remove_by_msg(cmd_parms *cmd, void *_dcfg, const char *p1) { + directory_config *dcfg = (directory_config *)_dcfg; + rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception)); + if (dcfg == NULL) return NULL; + + re->type = RULE_EXCEPTION_REMOVE_MSG; + re->param = p1; + re->param_data = msc_pregcomp(cmd->pool, p1, 0, NULL, NULL); + if (re->param_data == NULL) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p1); + } + *(rule_exception **)apr_array_push(dcfg->rule_exceptions) = re; + + /* Remove the corresponding rules from the context straight away. */ + msre_ruleset_rule_remove_with_exception(dcfg->ruleset, re); + + #ifdef DEBUG_CONF + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, "Added exception %pp (%d %s) to dcfg %pp.", re, re->type, re->param, dcfg); + #endif + + return NULL; +} + +static const char *cmd_rule_update_action_by_id(cmd_parms *cmd, void *_dcfg, + const char *p1, const char *p2) +{ + return update_rule_action(cmd, (directory_config *)_dcfg, p1, p2); +} + +static const char *cmd_server_signature(cmd_parms *cmd, void *_dcfg, const char *p1) { + if (cmd->server->is_virtual) { + return "ModSecurity: SecServerSignature not allowed in VirtualHost"; + } + new_server_signature = (char *)p1; + return NULL; +} + +static const char *cmd_tmp_dir(cmd_parms *cmd, void *_dcfg, const char *p1) { + directory_config *dcfg = (directory_config *)_dcfg; + + if (dcfg == NULL) return NULL; + + if (strcasecmp(p1, "none") == 0) dcfg->tmp_dir = NULL; + else dcfg->tmp_dir = ap_server_root_relative(cmd->pool, p1); + + return NULL; +} + +static const char *cmd_upload_dir(cmd_parms *cmd, void *_dcfg, const char *p1) { + directory_config *dcfg = (directory_config *)_dcfg; + + if (dcfg == NULL) return NULL; + + if (strcasecmp(p1, "none") == 0) dcfg->upload_dir = NULL; + else dcfg->upload_dir = ap_server_root_relative(cmd->pool, p1); + + return NULL; +} + +static const char *cmd_upload_filemode(cmd_parms *cmd, void *_dcfg, const char *p1) { + directory_config *dcfg = (directory_config *)_dcfg; + + if (dcfg == NULL) return NULL; + + if (strcasecmp(p1, "default") == 0) { + dcfg->upload_filemode = NOT_SET; + } + else { + long int mode = strtol(p1, NULL, 8); /* expects octal mode */ + if ((mode == LONG_MAX)||(mode == LONG_MIN)||(mode <= 0)||(mode > 07777)) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecUploadFileMode: %s", p1); + } + + dcfg->upload_filemode = (int)mode; + } + + return NULL; +} + +static const char *cmd_upload_keep_files(cmd_parms *cmd, void *_dcfg, const char *p1) { + directory_config *dcfg = (directory_config *)_dcfg; + + if (dcfg == NULL) return NULL; + + if (strcasecmp(p1, "on") == 0) { + dcfg->upload_keep_files = KEEP_FILES_ON; + } else + if (strcasecmp(p1, "off") == 0) { + dcfg->upload_keep_files = KEEP_FILES_OFF; + } else + if (strcasecmp(p1, "relevantonly") == 0) { + dcfg->upload_keep_files = KEEP_FILES_RELEVANT_ONLY; + } else { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid setting for SecUploadKeepFiles: %s", + p1); + } + return NULL; +} + +static const char *cmd_web_app_id(cmd_parms *cmd, void *_dcfg, const char *p1) { + directory_config *dcfg = (directory_config *)_dcfg; + + /* ENH enforce format (letters, digits, ., _, -) */ + dcfg->webappid = p1; + + return NULL; +} + +/* -- PDF Protection configuration -- */ + +static const char *cmd_pdf_protect(cmd_parms *cmd, void *_dcfg, int flag) { + directory_config *dcfg = (directory_config *)_dcfg; + if (dcfg == NULL) return NULL; + + dcfg->pdfp_enabled = flag; + + return NULL; +} + +static const char *cmd_pdf_protect_secret(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + if (dcfg == NULL) return NULL; + + dcfg->pdfp_secret = p1; + + return NULL; +} + +static const char *cmd_pdf_protect_timeout(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + if (dcfg == NULL) return NULL; + + dcfg->pdfp_timeout = atoi(p1); + + return NULL; +} + +static const char *cmd_pdf_protect_token_name(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + if (dcfg == NULL) return NULL; + + dcfg->pdfp_token_name = p1; + + return NULL; +} + +static const char *cmd_pdf_protect_intercept_get_only(cmd_parms *cmd, void *_dcfg, + int flag) +{ + directory_config *dcfg = (directory_config *)_dcfg; + if (dcfg == NULL) return NULL; + + dcfg->pdfp_only_get = flag; + + return NULL; +} + +static const char *cmd_pdf_protect_method(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + if (dcfg == NULL) return NULL; + + if (strcasecmp(p1, "TokenRedirection") == 0) { + dcfg->pdfp_method = PDF_PROTECT_METHOD_TOKEN_REDIRECTION; + } else + if (strcasecmp(p1, "ForcedDownload") == 0) { + dcfg->pdfp_method = PDF_PROTECT_METHOD_FORCED_DOWNLOAD; + } else { + return (const char *)apr_psprintf(cmd->pool, + "ModSecurity: Unrecognised parameter value for SecPdfProtectMethod: %s", p1); + } + + return NULL; +} + +/* -- Geo Lookup configuration -- */ + +static const char *cmd_geo_lookup_db(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + const char *filename = resolve_relative_path(cmd->pool, cmd->directive->filename, p1); + char *error_msg; + directory_config *dcfg = (directory_config *)_dcfg; + if (dcfg == NULL) return NULL; + + if (geo_init(dcfg, filename, &error_msg) <= 0) { + return error_msg; + } + + return NULL; +} + + +/* -- Cache -- */ + +static const char *cmd_cache_transformations(cmd_parms *cmd, void *_dcfg, const char *p1, const char *p2) { + directory_config *dcfg = (directory_config *)_dcfg; + + if (dcfg == NULL) return NULL; + + if (strcasecmp(p1, "on") == 0) + dcfg->cache_trans = MODSEC_CACHE_ENABLED; + else if (strcasecmp(p1, "off") == 0) + dcfg->cache_trans = MODSEC_CACHE_DISABLED; + else + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecCacheTransformations: %s", p1); + + /* Process options */ + if (p2 != NULL) { + apr_table_t *vartable = apr_table_make(cmd->pool, 4); + apr_status_t rc; + char *error_msg = NULL; + const char *charval = NULL; + apr_int64_t intval = 0; + + if (vartable == NULL) { + return apr_psprintf(cmd->pool, "ModSecurity: Unable to process options for SecCacheTransformations"); + } + rc = msre_parse_generic(cmd->pool, p2, vartable, &error_msg); + if (rc < 0) { + return apr_psprintf(cmd->pool, "ModSecurity: Unable to parse options for SecCacheTransformations: %s", error_msg); + } + + /* incremental */ + charval = apr_table_get(vartable, "incremental"); + if (charval != NULL) { + if (strcasecmp(charval, "on") == 0) + dcfg->cache_trans_incremental = 1; + else if (strcasecmp(charval, "off") == 0) + dcfg->cache_trans_incremental = 0; + else + return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations invalid incremental value: %s", charval); + } + + /* minlen */ + charval = apr_table_get(vartable, "minlen"); + if (charval != NULL) { + intval = apr_atoi64(charval); + if (errno == ERANGE) { + return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations minlen out of range: %s", charval); + } + if (intval < 0) { + return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations minlen must be positive: %s", charval); + } + + /* The NOT_SET indicator is -1, a signed long, and therfore + * we cannot be >= the unsigned value of NOT_SET. + */ + if ((unsigned long)intval >= (unsigned long)NOT_SET) { + return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations minlen must be less than: %lu", (unsigned long)NOT_SET); + } + dcfg->cache_trans_min = (apr_size_t)intval; + } + + /* maxlen */ + charval = apr_table_get(vartable, "maxlen"); + if (charval != NULL) { + intval = apr_atoi64(charval); + if (errno == ERANGE) { + return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations maxlen out of range: %s", charval); + } + if (intval < 0) { + return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations maxlen must be positive: %s", charval); + } + + /* The NOT_SET indicator is -1, a signed long, and therfore + * we cannot be >= the unsigned value of NOT_SET. + */ + if ((unsigned long)intval >= (unsigned long)NOT_SET) { + return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations maxlen must be less than: %lu", (unsigned long)NOT_SET); + } + if ((intval != 0) && ((apr_size_t)intval < dcfg->cache_trans_min)) { + return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations maxlen must not be less than minlen: %lu < %" APR_SIZE_T_FMT, (unsigned long)intval, dcfg->cache_trans_min); + } + dcfg->cache_trans_max = (apr_size_t)intval; + + } + + /* maxitems */ + charval = apr_table_get(vartable, "maxitems"); + if (charval != NULL) { + intval = apr_atoi64(charval); + if (errno == ERANGE) { + return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations maxitems out of range: %s", charval); + } + if (intval < 0) { + return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations maxitems must be positive: %s", charval); + } + dcfg->cache_trans_maxitems = (apr_size_t)intval; + } + } + + return NULL; +} + + +/* -- Configuration directives definitions -- */ + +#define CMD_SCOPE_MAIN (RSRC_CONF) +#define CMD_SCOPE_ANY (RSRC_CONF | ACCESS_CONF) + +const command_rec module_directives[] = { + + AP_INIT_TAKE1 ( + "SecAction", + cmd_action, + NULL, + CMD_SCOPE_ANY, + "an action list" + ), + + AP_INIT_TAKE1 ( + "SecArgumentSeparator", + cmd_argument_separator, + NULL, + CMD_SCOPE_MAIN, + "character that will be used as separator when parsing application/x-www-form-urlencoded content." + ), + + AP_INIT_TAKE1 ( + "SecAuditEngine", + cmd_audit_engine, + NULL, + CMD_SCOPE_ANY, + "On, Off or RelevantOnly to determine the level of audit logging" + ), + + AP_INIT_TAKE1 ( + "SecAuditLog", + cmd_audit_log, + NULL, + CMD_SCOPE_ANY, + "filename of the primary audit log file" + ), + + AP_INIT_TAKE1 ( + "SecAuditLog2", + cmd_audit_log2, + NULL, + CMD_SCOPE_ANY, + "filename of the secondary audit log file" + ), + + AP_INIT_TAKE1 ( + "SecAuditLogParts", + cmd_audit_log_parts, + NULL, + CMD_SCOPE_ANY, + "list of audit log parts that go into the log." + ), + + AP_INIT_TAKE1 ( + "SecAuditLogRelevantStatus", + cmd_audit_log_relevant_status, + NULL, + CMD_SCOPE_ANY, + "regular expression that will be used to determine if the response status is relevant for audit logging" + ), + + AP_INIT_TAKE1 ( + "SecAuditLogType", + cmd_audit_log_type, + NULL, + CMD_SCOPE_ANY, + "whether to use the old audit log format (Serial) or new (Concurrent)" + ), + + AP_INIT_TAKE1 ( + "SecAuditLogStorageDir", + cmd_audit_log_storage_dir, + NULL, + CMD_SCOPE_ANY, + "path to the audit log storage area; absolute, or relative to the root of the server" + ), + + AP_INIT_TAKE1 ( + "SecAuditLogDirMode", + cmd_audit_log_dirmode, + NULL, + CMD_SCOPE_ANY, + "octal permissions mode for concurrent audit log directories" + ), + + AP_INIT_TAKE1 ( + "SecAuditLogFileMode", + cmd_audit_log_filemode, + NULL, + CMD_SCOPE_ANY, + "octal permissions mode for concurrent audit log files" + ), + + AP_INIT_TAKE12 ( + "SecCacheTransformations", + cmd_cache_transformations, + NULL, + CMD_SCOPE_ANY, + "whether or not to cache transformations. Defaults to true." + ), + + AP_INIT_TAKE1 ( + "SecChrootDir", + cmd_chroot_dir, + NULL, + CMD_SCOPE_MAIN, + "path of the directory to which server will be chrooted" + ), + + AP_INIT_TAKE1 ( + "SecComponentSignature", + cmd_component_signature, + NULL, + CMD_SCOPE_MAIN, + "component signature to add to ModSecurity signature." + ), + + AP_INIT_FLAG ( + "SecContentInjection", + cmd_content_injection, + NULL, + CMD_SCOPE_ANY, + "On or Off" + ), + + AP_INIT_TAKE1 ( + "SecCookieFormat", + cmd_cookie_format, + NULL, + CMD_SCOPE_ANY, + "version of the Cookie specification to use for parsing. Possible values are 0 and 1." + ), + + AP_INIT_TAKE1 ( + "SecDataDir", + cmd_data_dir, + NULL, + CMD_SCOPE_MAIN, + "path to the persistent data storage area" // TODO + ), + + AP_INIT_TAKE1 ( + "SecDebugLog", + cmd_debug_log, + NULL, + CMD_SCOPE_ANY, + "path to the debug log file" + ), + + AP_INIT_TAKE1 ( + "SecDebugLogLevel", + cmd_debug_log_level, + NULL, + CMD_SCOPE_ANY, + "debug log level, which controls the verbosity of logging." + " Use values from 0 (no logging) to 9 (a *lot* of logging)." + ), + + AP_INIT_TAKE1 ( + "SecDefaultAction", + cmd_default_action, + NULL, + CMD_SCOPE_ANY, + "default action list" + ), + + AP_INIT_TAKE1 ( + "SecGeoLookupDB", + cmd_geo_lookup_db, + NULL, + RSRC_CONF, + "database for geographical lookups module." + ), + + AP_INIT_TAKE12 ( + "SecGuardianLog", + cmd_guardian_log, + NULL, + CMD_SCOPE_MAIN, + "The filename of the filter debugging log file" + ), + + AP_INIT_TAKE1 ( + "SecMarker", + cmd_marker, + NULL, + CMD_SCOPE_ANY, + "marker for a skipAfter target" + ), + + AP_INIT_FLAG ( + "SecPdfProtect", + cmd_pdf_protect, + NULL, + RSRC_CONF, + "enable PDF protection module." + ), + + AP_INIT_TAKE1 ( + "SecPdfProtectSecret", + cmd_pdf_protect_secret, + NULL, + RSRC_CONF, + "secret that will be used to construct protection tokens." + ), + + AP_INIT_TAKE1 ( + "SecPdfProtectTimeout", + cmd_pdf_protect_timeout, + NULL, + RSRC_CONF, + "duration for which protection tokens will be valid." + ), + + AP_INIT_TAKE1 ( + "SecPdfProtectTokenName", + cmd_pdf_protect_token_name, + NULL, + RSRC_CONF, + "name of the protection token. The name 'PDFTOKEN' is used by default." + ), + + AP_INIT_FLAG ( + "SecPdfProtectInterceptGETOnly", + cmd_pdf_protect_intercept_get_only, + NULL, + RSRC_CONF, + "whether or not to intercept only GET and HEAD requess. Defaults to true." + ), + + AP_INIT_TAKE1 ( + "SecPdfProtectMethod", + cmd_pdf_protect_method, + NULL, + RSRC_CONF, + "protection method to use. Can be 'TokenRedirection' (default) or 'ForcedDownload'" + ), + + AP_INIT_TAKE1 ( + "SecRequestBodyAccess", + cmd_request_body_access, + NULL, + CMD_SCOPE_ANY, + "On or Off" + ), + + AP_INIT_TAKE1 ( + "SecRequestBodyInMemoryLimit", + cmd_request_body_inmemory_limit, + NULL, + CMD_SCOPE_ANY, + "maximum request body size that will be placed in memory (except for POST urlencoded requests)." + ), + + AP_INIT_TAKE1 ( + "SecRequestBodyLimit", + cmd_request_body_limit, + NULL, + CMD_SCOPE_ANY, + "maximum request body size ModSecurity will accept." + ), + + AP_INIT_TAKE1 ( + "SecRequestBodyNoFilesLimit", + cmd_request_body_no_files_limit, + NULL, + CMD_SCOPE_ANY, + "maximum request body size ModSecurity will accept, but excluding the size of uploaded files." + ), + + AP_INIT_TAKE1 ( + "SecRequestEncoding", + cmd_request_encoding, + NULL, + CMD_SCOPE_ANY, + "character encoding used in request." + ), + + AP_INIT_TAKE1 ( + "SecResponseBodyAccess", + cmd_response_body_access, + NULL, + CMD_SCOPE_ANY, + "On or Off" + ), + + AP_INIT_TAKE1 ( + "SecResponseBodyLimit", + cmd_response_body_limit, + NULL, + CMD_SCOPE_ANY, + "byte limit for response body" + ), + + AP_INIT_TAKE1 ( + "SecResponseBodyLimitAction", + cmd_response_body_limit_action, + NULL, + CMD_SCOPE_ANY, + "what happens when the response body limit is reached" + ), + + AP_INIT_ITERATE ( + "SecResponseBodyMimeType", + cmd_response_body_mime_type, + NULL, + CMD_SCOPE_ANY, + "adds given MIME types to the list of types that will be buffered on output" + ), + + AP_INIT_NO_ARGS ( + "SecResponseBodyMimeTypesClear", + cmd_response_body_mime_types_clear, + NULL, + CMD_SCOPE_ANY, + "clears the list of MIME types that will be buffered on output" + ), + + AP_INIT_TAKE23 ( + "SecRule", + cmd_rule, + NULL, + CMD_SCOPE_ANY, + "rule target, operator and optional action list" + ), + + AP_INIT_TAKE1 ( + "SecRuleEngine", + cmd_rule_engine, + NULL, + CMD_SCOPE_ANY, + "On or Off" + ), + + AP_INIT_FLAG ( + "SecRuleInheritance", + cmd_rule_inheritance, + NULL, + CMD_SCOPE_ANY, + "On or Off" + ), + + AP_INIT_TAKE12 ( + "SecRuleScript", + cmd_rule_script, + NULL, + CMD_SCOPE_ANY, + "rule script and optional actionlist" + ), + + AP_INIT_ITERATE ( + "SecRuleRemoveById", + cmd_rule_remove_by_id, + NULL, + CMD_SCOPE_ANY, + "rule ID for removal" + ), + + AP_INIT_ITERATE ( + "SecRuleRemoveByMsg", + cmd_rule_remove_by_msg, + NULL, + CMD_SCOPE_ANY, + "rule message for removal" + ), + + AP_INIT_TAKE2 ( + "SecRuleUpdateActionById", + cmd_rule_update_action_by_id, + NULL, + CMD_SCOPE_ANY, + "updated action list" + ), + + AP_INIT_TAKE1 ( + "SecServerSignature", + cmd_server_signature, + NULL, + CMD_SCOPE_MAIN, + "the new signature of the server" + ), + + AP_INIT_TAKE1 ( + "SecTmpDir", + cmd_tmp_dir, + NULL, + CMD_SCOPE_ANY, + "path to the temporary storage area" + ), + + AP_INIT_TAKE1 ( + "SecUploadDir", + cmd_upload_dir, + NULL, + CMD_SCOPE_ANY, + "path to the file upload area" + ), + + AP_INIT_TAKE1 ( + "SecUploadFileMode", + cmd_upload_filemode, + NULL, + CMD_SCOPE_ANY, + "octal permissions mode for uploaded files" + ), + + AP_INIT_TAKE1 ( + "SecUploadKeepFiles", + cmd_upload_keep_files, + NULL, + CMD_SCOPE_ANY, + "On or Off" + ), + + AP_INIT_TAKE1 ( + "SecWebAppId", + cmd_web_app_id, + NULL, + CMD_SCOPE_ANY, + "id" + ), + + { NULL } +}; diff --git a/apache2/apache2_io.c b/apache2/apache2_io.c new file mode 100644 index 0000000..1bed6e5 --- /dev/null +++ b/apache2/apache2_io.c @@ -0,0 +1,823 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ +#include + +#include "modsecurity.h" +#include "apache2.h" + + +/* -- Input filter -- */ + +#if 0 +static void dummy_free_func(void *data) {} +#endif + +/** + * This request filter will forward the previously stored + * request body further down the chain (most likely to the + * processing module). + */ +apr_status_t input_filter(ap_filter_t *f, apr_bucket_brigade *bb_out, + ap_input_mode_t mode, apr_read_type_e block, apr_off_t nbytes) +{ + modsec_rec *msr = (modsec_rec *)f->ctx; + msc_data_chunk *chunk = NULL; + apr_bucket *bucket; + apr_status_t rc; + char *my_error_msg = NULL; + + if (msr == NULL) { + ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, f->r->server, + "ModSecurity: Internal error in input filter: msr is null."); + ap_remove_input_filter(f); + return APR_EGENERAL; + } + + /* Make sure we are using the current request */ + msr->r = f->r; + + if (msr->phase < PHASE_REQUEST_BODY) { + msr_log(msr, 1, "Internal error: REQUEST_BODY phase incomplete for input filter in phase %d", msr->phase); + return APR_EGENERAL; + } + + if ((msr->if_status == IF_STATUS_COMPLETE)||(msr->if_status == IF_STATUS_NONE)) { + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Input filter: Input forwarding already complete, skipping (f %pp, r %pp).", f, f->r); + } + ap_remove_input_filter(f); + return ap_get_brigade(f->next, bb_out, mode, block, nbytes); + } + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Input filter: Forwarding input: mode=%d, block=%d, nbytes=%" APR_OFF_T_FMT + " (f %pp, r %pp).", mode, block, nbytes, f, f->r); + } + + if (msr->if_started_forwarding == 0) { + msr->if_started_forwarding = 1; + rc = modsecurity_request_body_retrieve_start(msr, &my_error_msg); + if (rc == -1) { + if (my_error_msg != NULL) { + msr_log(msr, 1, "%s", my_error_msg); + } + return APR_EGENERAL; + } + } + + rc = modsecurity_request_body_retrieve(msr, &chunk, (unsigned int)nbytes, &my_error_msg); + if (rc == -1) { + if (my_error_msg != NULL) { + msr_log(msr, 1, "%s", my_error_msg); + } + return APR_EGENERAL; + } + + if (chunk) { + /* Copy the data we received in the chunk */ + bucket = apr_bucket_heap_create(chunk->data, chunk->length, NULL, + f->r->connection->bucket_alloc); + + #if 0 + + It would seem that we cannot prevent other filters in the chain + from modifying data in-place. Hence we copy. + + if (chunk->is_permanent) { + /* Do not make a copy of the data we received in the chunk. */ + bucket = apr_bucket_heap_create(chunk->data, chunk->length, dummy_free_func, + f->r->connection->bucket_alloc); + } else { + /* Copy the data we received in the chunk. */ + bucket = apr_bucket_heap_create(chunk->data, chunk->length, NULL, + f->r->connection->bucket_alloc); + } + + #endif + + if (bucket == NULL) return APR_EGENERAL; + APR_BRIGADE_INSERT_TAIL(bb_out, bucket); + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Input filter: Forwarded %" APR_SIZE_T_FMT " bytes.", chunk->length); + } + } + + if (rc == 0) { + modsecurity_request_body_retrieve_end(msr); + + bucket = apr_bucket_eos_create(f->r->connection->bucket_alloc); + if (bucket == NULL) return APR_EGENERAL; + APR_BRIGADE_INSERT_TAIL(bb_out, bucket); + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Input filter: Sent EOS."); + } + + /* We're done */ + msr->if_status = IF_STATUS_COMPLETE; + ap_remove_input_filter(f); + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Input filter: Input forwarding complete."); + } + } + + return APR_SUCCESS; +} + +/** + * Reads request body from a client. + */ +apr_status_t read_request_body(modsec_rec *msr, char **error_msg) { + request_rec *r = msr->r; + unsigned int seen_eos; + apr_bucket_brigade *bb_in; + apr_bucket *bucket; + + if (error_msg == NULL) return -1; + *error_msg = NULL; + + if (msr->reqbody_should_exist != 1) { + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Input filter: This request does not have a body."); + } + return 0; + } + + if (msr->txcfg->reqbody_access != 1) { + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Input filter: Request body access not enabled."); + } + return 0; + } + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Input filter: Reading request body."); + } + + if (modsecurity_request_body_start(msr, error_msg) < 0) { + return -1; + } + + seen_eos = 0; + bb_in = apr_brigade_create(msr->mp, r->connection->bucket_alloc); + if (bb_in == NULL) return -1; + do { + apr_status_t rc; + + rc = ap_get_brigade(r->input_filters, bb_in, AP_MODE_READBYTES, APR_BLOCK_READ, HUGE_STRING_LEN); + if (rc != APR_SUCCESS) { + /* NOTE Apache returns AP_FILTER_ERROR here when the request is + * too large and APR_EGENERAL when the client disconnects. + */ + switch(rc) { + case APR_TIMEUP : + *error_msg = apr_psprintf(msr->mp, "Error reading request body: %s", get_apr_error(msr->mp, rc)); + return -4; + case AP_FILTER_ERROR : + *error_msg = apr_psprintf(msr->mp, "Error reading request body: HTTP Error 413 - Request entity too large. (Most likely.)"); + return -3; + case APR_EGENERAL : + *error_msg = apr_psprintf(msr->mp, "Error reading request body: Client went away."); + return -2; + default : + *error_msg = apr_psprintf(msr->mp, "Error reading request body: %s", get_apr_error(msr->mp, rc)); + return -1; + } + } + + /* Loop through the buckets in the brigade in order + * to extract the size of the data available. + */ + for(bucket = APR_BRIGADE_FIRST(bb_in); + bucket != APR_BRIGADE_SENTINEL(bb_in); + bucket = APR_BUCKET_NEXT(bucket)) + { + const char *buf; + apr_size_t buflen; + + rc = apr_bucket_read(bucket, &buf, &buflen, APR_BLOCK_READ); + if (rc != APR_SUCCESS) { + *error_msg = apr_psprintf(msr->mp, "Failed reading input / bucket (%d): %s", rc, get_apr_error(msr->mp, rc)); + return -1; + } + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Input filter: Bucket type %s contains %" APR_SIZE_T_FMT " bytes.", + bucket->type->name, buflen); + } + + /* Check request body limit (should only trigger on chunked requests). */ + if (msr->reqbody_length + buflen > (apr_size_t)msr->txcfg->reqbody_limit) { + *error_msg = apr_psprintf(msr->mp, "Request body is larger than the " + "configured limit (%ld).", msr->txcfg->reqbody_limit); + return -5; + } + + if (buflen != 0) { + int rcbs = modsecurity_request_body_store(msr, buf, buflen, error_msg); + if (rcbs < 0) { + if (rcbs == -5) { + *error_msg = apr_psprintf(msr->mp, "Request body no files data length is larger than the " + "configured limit (%ld).", msr->txcfg->reqbody_no_files_limit); + return -5; + } + + return -1; + } + + msr->reqbody_length += buflen; + } + + if (APR_BUCKET_IS_EOS(bucket)) { + seen_eos = 1; + } + } + + apr_brigade_cleanup(bb_in); + } while(!seen_eos); + + // TODO: Why ignore the return code here? + modsecurity_request_body_end(msr, error_msg); + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Input filter: Completed receiving request body (length %" APR_SIZE_T_FMT ").", + msr->reqbody_length); + } + + msr->if_status = IF_STATUS_WANTS_TO_RUN; + + return 1; +} + + +/* -- Output filter -- */ + +/** + * Examines the configuration and the response MIME type + * in order to determine whether output buffering should + * run or not. + */ +static int output_filter_should_run(modsec_rec *msr, request_rec *r) { + char *content_type = NULL; + + /* Check configuration. */ + if (msr->txcfg->resbody_access != 1) { + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Output filter: Response body buffering is not enabled."); + } + + return 0; + } + + /* Check MIME type. */ + + if ((msr->txcfg->of_mime_types == NULL)||(msr->txcfg->of_mime_types == NOT_SET_P)) { + msr_log(msr, 1, "Output filter: MIME type structures corrupted (internal error)."); + return -1; + } + + if (r->content_type != NULL) { + char *p = NULL; + + content_type = apr_pstrdup(msr->mp, r->content_type); + if (content_type == NULL) { + msr_log(msr, 1, "Output filter: Failed to allocate memory for content type."); + return -1; + } + + /* Hide the character encoding information + * if present. Sometimes the content type header + * looks like this "text/html; charset=xyz" ... + */ + p = strstr(content_type, ";"); + if (p != NULL) { + *p = '\0'; + } + + strtolower_inplace((unsigned char *)content_type); + + if (strcmp(content_type, "text/html") == 0) { + /* Useful information to have should we later + * decide to do something with the HTML output. + */ + msr->resbody_contains_html = 1; + } + } else { + content_type = "null"; + } + + if (apr_table_get(msr->txcfg->of_mime_types, content_type) != NULL) return 1; + + msr_log(msr, 4, "Output filter: Not buffering response body for unconfigured MIME type \"%s\".", content_type); + + return 0; +} + +/** + * Initialises the output filter. + */ +static apr_status_t output_filter_init(modsec_rec *msr, ap_filter_t *f, + apr_bucket_brigade *bb_in) +{ + request_rec *r = f->r; + const char *s_content_length = NULL; + apr_status_t rc; + + msr->of_brigade = apr_brigade_create(msr->mp, f->c->bucket_alloc); + if (msr->of_brigade == NULL) { + msr_log(msr, 1, "Output filter: Failed to create brigade."); + return -1; + } + msr->of_status = OF_STATUS_IN_PROGRESS; + + rc = output_filter_should_run(msr, r); + if (rc < 0) return -1; /* output_filter_should_run() generates error msg */ + if (rc == 0) return 0; + + /* Do not check the output limit if we are willing to + * process partial response bodies. + */ + + if (msr->txcfg->of_limit_action == RESPONSE_BODY_LIMIT_ACTION_PARTIAL) { + return 1; + } + + /* Look up the Content-Length header to see if we know + * the amount of data coming our way. If we do and if + * it's too much we might want to stop processing right here. + */ + s_content_length = apr_table_get(r->headers_out, "Content-Length"); + if (s_content_length == NULL) { + /* Try this too, mod_cgi seems to put headers there. */ + s_content_length = apr_table_get(r->err_headers_out, "Content-Length"); + } + + if (s_content_length != NULL) { + long int len; + + len = strtol(s_content_length, NULL, 10); + if ((len == LONG_MIN)||(len == LONG_MAX)||(len < 0)||(len >= 1073741824)) { + msr_log(msr, 1, "Output filter: Invalid Content-Length: %s", log_escape_nq(r->pool, + (char *)s_content_length)); + return -1; /* Invalid. */ + } + + if (len == 0) { + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Output filter: Skipping response since Content-Length is zero."); + } + + return 0; + } + + if (len > msr->txcfg->of_limit) { + msr_log(msr, 1, "Output filter: Content-Length (%s) over the limit (%ld).", + log_escape_nq(r->pool, (char *)s_content_length), msr->txcfg->of_limit); + return -2; /* Over the limit. */ + } + } + + return 1; +} + +/** + * Send the accumulated content down the filter stream + * and to the client. + */ +static apr_status_t send_of_brigade(modsec_rec *msr, ap_filter_t *f) { + apr_status_t rc; + + rc = ap_pass_brigade(f->next, msr->of_brigade); + if (rc != APR_SUCCESS) { + /* TODO: These need to move to flags in 2.6. For now log them + * at level 4 so that they are not confusing users. + */ + int log_level = 4; + + if (msr->txcfg->debuglog_level >= log_level) { + switch(rc) { + case AP_NOBODY_WROTE : + msr_log(msr, log_level, "Output filter: Error while forwarding response data (%d): No data", rc); + break; + case AP_FILTER_ERROR : + /* Look like this is caused by the error + * already being handled, so we should ignore it + * + msr_log(msr, log_level, "Output filter: Error while forwarding response data (%d): Filter error", rc); + */ + break; + default : + msr_log(msr, log_level, "Output filter: Error while forwarding response data (%d): %s", + rc, get_apr_error(msr->mp, rc)); + break; + } + } + + return rc; + } + + return APR_SUCCESS; +} + +/** + * + */ +static void prepend_content_to_of_brigade(modsec_rec *msr, ap_filter_t *f) { + if ((msr->txcfg->content_injection_enabled) && (msr->content_prepend) && (!msr->of_skipping)) { + apr_bucket *bucket_ci = NULL; + + bucket_ci = apr_bucket_heap_create(msr->content_prepend, + msr->content_prepend_len, NULL, f->r->connection->bucket_alloc); + APR_BRIGADE_INSERT_HEAD(msr->of_brigade, bucket_ci); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Content Injection (b): Added content to top: %s", + log_escape_nq_ex(msr->mp, msr->content_prepend, msr->content_prepend_len)); + } + } +} + +/** + * + */ +static int flatten_response_body(modsec_rec *msr) { + apr_status_t rc; + + msr->resbody_status = RESBODY_STATUS_READ_BRIGADE; + + if (msr->resbody_length + 1 <= 0) { + msr_log(msr, 1, "Output filter: Invalid response length: %" APR_SIZE_T_FMT, msr->resbody_length); + return -1; + } + + msr->resbody_data = apr_palloc(msr->mp, msr->resbody_length + 1); + if (msr->resbody_data == NULL) { + msr_log(msr, 1, "Output filter: Response body data memory allocation failed. Asked for: %" APR_SIZE_T_FMT, + msr->resbody_length + 1); + return -1; + } + + rc = apr_brigade_flatten(msr->of_brigade, msr->resbody_data, &msr->resbody_length); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "Output filter: Failed to flatten brigade (%d): %s", rc, + get_apr_error(msr->mp, rc)); + return -1; + } + + msr->resbody_data[msr->resbody_length] = '\0'; + msr->resbody_status = RESBODY_STATUS_READ; + + return 1; +} + +/** + * Output filter. + */ +apr_status_t output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) { + request_rec *r = f->r; + modsec_rec *msr = (modsec_rec *)f->ctx; + apr_bucket *bucket = NULL, *eos_bucket = NULL; + apr_status_t rc; + int start_skipping = 0; + + /* Do we have the context? */ + if (msr == NULL) { + ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, f->r->server, + "ModSecurity: Internal Error: msr is null in output filter."); + ap_remove_output_filter(f); + return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR); + } + + msr->r = r; + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Output filter: Receiving output (f %pp, r %pp).", f, f->r); + } + + /* Initialise on first invocation */ + if (msr->of_status == OF_STATUS_NOT_STARTED) { + /* Update our context from the request structure. */ + msr->r = r; + msr->response_status = r->status; + msr->status_line = ((r->status_line != NULL) + ? r->status_line : ap_get_status_line(r->status)); + msr->response_protocol = get_response_protocol(r); + msr->response_headers = apr_table_overlay(msr->mp, r->err_headers_out, r->headers_out); + + /* Process phase RESPONSE_HEADERS */ + rc = modsecurity_process_phase(msr, PHASE_RESPONSE_HEADERS); + if (rc < 0) { /* error */ + ap_remove_output_filter(f); + return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR); + } + + if (rc > 0) { /* transaction needs to be interrupted */ + int status = perform_interception(msr); + if (status != DECLINED) { /* DECLINED means we allow-ed the request. */ + ap_remove_output_filter(f); + msr->of_status = OF_STATUS_COMPLETE; + msr->resbody_status = RESBODY_STATUS_ERROR; + return send_error_bucket(msr, f, status); + } + } + + /* Decide whether to observe the response body. */ + rc = output_filter_init(msr, f, bb_in); + switch(rc) { + case -2 : /* response too large */ + case -1 : /* error */ + /* there's something wrong with this response */ + ap_remove_output_filter(f); + msr->of_status = OF_STATUS_COMPLETE; + msr->resbody_status = RESBODY_STATUS_ERROR; + return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR); + case 0 : + /* We do not want to observe this response body + * but we need to remain attached to observe + * when it is completed so that we can run + * the RESPONSE_BODY phase. + */ + msr->of_skipping = 1; + msr->resbody_status = RESBODY_STATUS_NOT_READ; + break; + default : + /* Continue (observe the response body). */ + break; + } + + /* If injecting content unset headers now. */ + if (msr->txcfg->content_injection_enabled == 0) { + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Content Injection: Not enabled."); + } + } else { + if ((msr->content_prepend) || (msr->content_append)) { + apr_table_unset(msr->r->headers_out, "Content-Length"); + apr_table_unset(msr->r->headers_out, "Last-Modified"); + apr_table_unset(msr->r->headers_out, "ETag"); + apr_table_unset(msr->r->headers_out, "Expires"); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Content Injection: Removing headers (C-L, L-M, Etag, Expires)."); + } + } else { + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Content Injection: Nothing to inject."); + } + } + } + + /* Content injection (prepend & non-buffering). */ + if ((msr->txcfg->content_injection_enabled) && (msr->content_prepend) && (msr->of_skipping)) { + apr_bucket *bucket_ci = apr_bucket_heap_create(msr->content_prepend, + msr->content_prepend_len, NULL, f->r->connection->bucket_alloc); + APR_BRIGADE_INSERT_HEAD(bb_in, bucket_ci); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Content Injection (nb): Added content to top: %s", + log_escape_nq_ex(msr->mp, msr->content_prepend, msr->content_prepend_len)); + } + } + } else + if (msr->of_status == OF_STATUS_COMPLETE) { + msr_log(msr, 1, "Output filter: Internal error: output filtering complete yet filter was invoked."); + ap_remove_output_filter(f); + return APR_EGENERAL; + } + + + /* Loop through the buckets in the brigade in order + * to extract the size of the data available. + */ + for(bucket = APR_BRIGADE_FIRST(bb_in); + bucket != APR_BRIGADE_SENTINEL(bb_in); + bucket = APR_BUCKET_NEXT(bucket)) { + const char *buf; + apr_size_t buflen; + + /* Look into response data if configured to do so, + * unless we've already processed a partial response. + */ + if ((msr->of_skipping == 0)&&(!msr->of_partial)) { /* Observe the response data. */ + /* Retrieve data from the bucket. */ + rc = apr_bucket_read(bucket, &buf, &buflen, APR_BLOCK_READ); + if (rc != APR_SUCCESS) { + msr->of_status = OF_STATUS_COMPLETE; + msr->resbody_status = RESBODY_STATUS_ERROR; + + msr_log(msr, 1, "Output filter: Failed to read bucket (rc %d): %s", + rc, get_apr_error(r->pool, rc)); + + ap_remove_output_filter(f); + return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR); + } + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Output filter: Bucket type %s contains %" APR_SIZE_T_FMT " bytes.", + bucket->type->name, buflen); + } + + /* Check the response size. */ + if (msr->resbody_length > (apr_size_t)msr->txcfg->of_limit) { + /* The size of the response is larger than what we're + * ready to accept. We need to decide what we want to do + * about it. + */ + if (msr->txcfg->of_limit_action == RESPONSE_BODY_LIMIT_ACTION_REJECT) { + /* Reject response. */ + msr_log(msr, 1, "Output filter: Response body too large (over limit of %ld, " + "total not specified).", msr->txcfg->of_limit); + + msr->of_status = OF_STATUS_COMPLETE; + msr->resbody_status = RESBODY_STATUS_PARTIAL; + + ap_remove_output_filter(f); + return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR); + } else { + /* Process partial response. */ + start_skipping = 1; + msr->resbody_length = msr->txcfg->of_limit; + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Output filter: Processing partial response body (limit %ld)", + msr->txcfg->of_limit); + } + } + } else { + msr->resbody_length += buflen; + } + } + + /* Have we reached the end of the response? */ + if (APR_BUCKET_IS_EOS(bucket)) { + eos_bucket = bucket; + + /* Inject content (append & non-buffering). */ + if ((msr->txcfg->content_injection_enabled) && (msr->content_append) + && (msr->of_skipping || msr->of_partial || start_skipping)) + { + apr_bucket *bucket_ci = NULL; + + bucket_ci = apr_bucket_heap_create(msr->content_append, + msr->content_append_len, NULL, f->r->connection->bucket_alloc); + APR_BUCKET_INSERT_BEFORE(bucket, bucket_ci); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Content-Injection (nb): Added content to bottom: %s", + log_escape_nq_ex(msr->mp, msr->content_append, msr->content_append_len)); + } + } + + msr->of_done_reading = 1; + } + } + + /* Add buckets in this brigade to the brigade + * we have in the context, but only if we actually + * want to keep the response body. + */ + if ((msr->of_skipping == 0)&&(msr->of_partial == 0)) { + ap_save_brigade(f, &msr->of_brigade, &bb_in, msr->mp); + + /* Do we need to process a partial response? */ + if (start_skipping) { + if (flatten_response_body(msr) < 0) { + ap_remove_output_filter(f); + return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR); + } + + /* Process phase RESPONSE_BODY */ + rc = modsecurity_process_phase(msr, PHASE_RESPONSE_BODY); + if (rc < 0) { + ap_remove_output_filter(f); + return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR); + } + if (rc > 0) { + int status = perform_interception(msr); + if (status != DECLINED) { /* DECLINED means we allow-ed the request. */ + ap_remove_output_filter(f); + return send_error_bucket(msr, f, status); + } + } + + /* Prepend content as necessary. */ + prepend_content_to_of_brigade(msr, f); + + if ((rc = send_of_brigade(msr, f)) != APR_SUCCESS) { + return rc; + } + + msr->of_partial = 1; + } + + if (msr->of_done_reading == 0) { + /* We are done for now. We will be called again with more data. */ + return APR_SUCCESS; + } + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Output filter: Completed receiving response body (buffered %s - %" APR_SIZE_T_FMT " bytes).", + (msr->of_partial ? "partial" : "full"), msr->resbody_length); + } + } else { /* Not looking at response data. */ + if (msr->of_done_reading == 0) { + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Output filter: Sending input brigade directly."); + } + + return ap_pass_brigade(f->next, bb_in); + } + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Output filter: Completed receiving response body (non-buffering)."); + } + } + + /* We've done our thing; remove us from the filter list. */ + msr->of_status = OF_STATUS_COMPLETE; + ap_remove_output_filter(f); + + /* Process phase RESPONSE_BODY, but + * only if it hasn't been processed already. + */ + if (msr->phase < PHASE_RESPONSE_BODY) { + if (flatten_response_body(msr) < 0) { + ap_remove_output_filter(f); + return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR); + } + + rc = modsecurity_process_phase(msr, PHASE_RESPONSE_BODY); + if (rc < 0) { + ap_remove_output_filter(f); + return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR); + } + if (rc > 0) { + int status = perform_interception(msr); + if (status != DECLINED) { /* DECLINED means we allow-ed the request. */ + ap_remove_output_filter(f); + return send_error_bucket(msr, f, status); + } + } + } + + /* Now send data down the filter stream + * (full-buffering only). + */ + if ((msr->of_skipping == 0)&&(!msr->of_partial)) { + record_time_checkpoint(msr, 3); + + prepend_content_to_of_brigade(msr, f); + + /* Inject content into response (append & buffering). */ + if ((msr->txcfg->content_injection_enabled) && (msr->content_append)) { + apr_bucket *bucket_ci = NULL; + + bucket_ci = apr_bucket_heap_create(msr->content_append, + msr->content_append_len, NULL, f->r->connection->bucket_alloc); + APR_BUCKET_INSERT_BEFORE(eos_bucket, bucket_ci); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Content-Injection (b): Added content to bottom: %s", + log_escape_nq_ex(msr->mp, msr->content_append, msr->content_append_len)); + } + } + + /* Send data down the filter stream. */ + if ((rc = send_of_brigade(msr, f)) != APR_SUCCESS) { + return rc; + } + } + + /* Another job well done! */ + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Output filter: Output forwarding complete."); + } + + if ((msr->of_skipping == 0)&&(msr->of_partial == 0)) { + return APR_SUCCESS; + } else { + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Output filter: Sending input brigade directly."); + } + + return ap_pass_brigade(f->next, bb_in); + } +} diff --git a/apache2/apache2_util.c b/apache2/apache2_util.c new file mode 100644 index 0000000..011f49a --- /dev/null +++ b/apache2/apache2_util.c @@ -0,0 +1,433 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ +#include "modsecurity.h" +#include "apache2.h" +#include "http_core.h" +#include "util_script.h" + +/** + * Sends a brigade with an error bucket down the filter chain. + */ +apr_status_t send_error_bucket(modsec_rec *msr, ap_filter_t *f, int status) { + apr_bucket_brigade *brigade = NULL; + apr_bucket *bucket = NULL; + + /* Set the status line explicitly for the error document */ + f->r->status_line = ap_get_status_line(status); + + brigade = apr_brigade_create(f->r->pool, f->r->connection->bucket_alloc); + if (brigade == NULL) return APR_EGENERAL; + + bucket = ap_bucket_error_create(status, NULL, f->r->pool, f->r->connection->bucket_alloc); + if (bucket == NULL) return APR_EGENERAL; + + APR_BRIGADE_INSERT_TAIL(brigade, bucket); + + bucket = apr_bucket_eos_create(f->r->connection->bucket_alloc); + if (bucket == NULL) return APR_EGENERAL; + + APR_BRIGADE_INSERT_TAIL(brigade, bucket); + + ap_pass_brigade(f->next, brigade); + + /* NOTE: + * It may not matter what we do from the filter as it may be too + * late to even generate an error (already sent to client). Nick Kew + * recommends to return APR_EGENERAL in hopes that the handler in control + * will notice and do The Right Thing. So, that is what we do now. + */ + + return APR_EGENERAL; +} + +/** + * Execute system command. First line of the output will be returned in + * the "output" parameter. + */ +int apache2_exec(modsec_rec *msr, const char *command, const char **argv, char **output) { + apr_procattr_t *procattr = NULL; + apr_proc_t *procnew = NULL; + apr_status_t rc = APR_SUCCESS; + const char *const *env = NULL; + apr_file_t *script_out = NULL; + request_rec *r = msr->r; + + if (argv == NULL) { + argv = apr_pcalloc(r->pool, 3 * sizeof(char *)); + argv[0] = command; + argv[1] = NULL; + } + + ap_add_cgi_vars(r); + ap_add_common_vars(r); + + /* PHP hack, getting around its silly security checks. */ + apr_table_add(r->subprocess_env, "PATH_TRANSLATED", command); + apr_table_add(r->subprocess_env, "REDIRECT_STATUS", "302"); + + env = (const char * const *)ap_create_environment(r->pool, r->subprocess_env); + if (env == NULL) { + msr_log(msr, 1, "Exec: Unable to create environment."); + return -1; + } + + procnew = apr_pcalloc(r->pool, sizeof(*procnew)); + if (procnew == NULL) { + msr_log(msr, 1, "Exec: Unable to allocate %lu bytes.", (unsigned long)sizeof(*procnew)); + return -1; + } + + apr_procattr_create(&procattr, r->pool); + if (procattr == NULL) { + msr_log(msr, 1, "Exec: Unable to create procattr."); + return -1; + } + + apr_procattr_io_set(procattr, APR_NO_PIPE, APR_FULL_BLOCK, APR_NO_PIPE); + apr_procattr_cmdtype_set(procattr, APR_SHELLCMD); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Exec: %s", log_escape_nq(r->pool, command)); + } + + rc = apr_proc_create(procnew, command, argv, env, procattr, r->pool); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "Exec: Execution failed: %s (%s)", log_escape_nq(r->pool, command), + get_apr_error(r->pool, rc)); + return -1; + } + + apr_pool_note_subprocess(r->pool, procnew, APR_KILL_AFTER_TIMEOUT); + + script_out = procnew->out; + if (!script_out) { + msr_log(msr, 1, "Exec: Failed to get script output pipe."); + return -1; + } + + apr_file_pipe_timeout_set(script_out, r->server->timeout); + + /* Now read from the pipe. */ + { + char buf[260] = ""; + char *p = buf; + apr_size_t nbytes = 255; + apr_status_t rc2; + + rc2 = apr_file_read(script_out, buf, &nbytes); + if (rc2 == APR_SUCCESS) { + buf[nbytes] = 0; + + /* if there is more than one line ignore them */ + while(*p != 0) { + if (*p == 0x0a) *p = 0; + p++; + } + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Exec: First line from script output: \"%s\"", + log_escape(r->pool, buf)); + } + + if (output != NULL) *output = apr_pstrdup(r->pool, buf); + + /* Soak up the remaining data. */ + nbytes = 255; + while(apr_file_read(script_out, buf, &nbytes) == APR_SUCCESS) nbytes = 255; + } else { + msr_log(msr, 1, "Exec: Execution failed while reading output: %s (%s)", + log_escape_nq(r->pool, command), + get_apr_error(r->pool, rc2)); + return -1; + } + } + + apr_proc_wait(procnew, NULL, NULL, APR_WAIT); + + return 1; +} + +/** + * Record the current time and store for later. + */ +void record_time_checkpoint(modsec_rec *msr, int checkpoint_no) { + char note[100], note_name[100]; + apr_time_t now; + + now = apr_time_now(); + switch(checkpoint_no) { + case 1 : + msr->time_checkpoint_1 = now; + break; + case 2 : + msr->time_checkpoint_2 = now; + break; + case 3 : + msr->time_checkpoint_3 = now; + break; + default : + msr_log(msr, 1, "Internal Error: Unknown checkpoint: %d", checkpoint_no); + return; + break; + } + + /* Apache-specific stuff. */ + apr_snprintf(note, 99, "%" APR_TIME_T_FMT, (now - msr->request_time)); + apr_snprintf(note_name, 99, "mod_security-time%d", checkpoint_no); + apr_table_set(msr->r->notes, note_name, note); + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Time #%d: %s", checkpoint_no, note); + } +} + +/** + * Returns a new string that contains the error + * message for the given return code. + */ +char *get_apr_error(apr_pool_t *p, apr_status_t rc) { + char *text = apr_pcalloc(p, 201); + if (text == NULL) return NULL; + apr_strerror(rc, text, 200); + return text; +} + +/** + * Retrieve named environment variable. + */ +char *get_env_var(request_rec *r, char *name) { + char *result = (char *)apr_table_get(r->notes, name); + + if (result == NULL) { + result = (char *)apr_table_get(r->subprocess_env, name); + } + + if (result == NULL) { + result = getenv(name); + } + + return result; +} + +/** + * Extended internal log helper function. Use msr_log instead. If fixup is + * true, the message will be stripped of any trailing newline and any + * required bytes will be escaped. + */ +void internal_log_ex(request_rec *r, directory_config *dcfg, modsec_rec *msr, + int level, int fixup, const char *text, va_list ap) +{ + apr_size_t nbytes, nbytes_written; + apr_file_t *debuglog_fd = NULL; + int filter_debug_level = 0; + char str1[1024] = ""; + char str2[1256] = ""; + + /* Find the logging FD and determine the logging level from configuration. */ + if (dcfg != NULL) { + if ((dcfg->debuglog_fd != NULL)&&(dcfg->debuglog_fd != NOT_SET_P)) { + debuglog_fd = dcfg->debuglog_fd; + } + + if (dcfg->debuglog_level != NOT_SET) { + filter_debug_level = dcfg->debuglog_level; + } + } + + /* Return immediately if we don't have where to write + * or if the log level of the message is higher than + * wanted in the log. + */ + if ((level > 3)&&( (debuglog_fd == NULL) || (level > filter_debug_level) )) return; + + /* Construct the message. */ + apr_vsnprintf(str1, sizeof(str1), text, ap); + if (fixup) { + int len = strlen(str1); + + /* Strip line ending. */ + if (len && str1[len - 1] == '\n') { + str1[len - 1] = '\0'; + } + if (len > 1 && str1[len - 2] == '\r') { + str1[len - 2] = '\0'; + } + } + + /* Construct the log entry. */ + apr_snprintf(str2, sizeof(str2), + "[%s] [%s/sid#%pp][rid#%pp][%s][%d] %s\n", + current_logtime(msr->mp), ap_get_server_name(r), (r->server), + r, ((r->uri == NULL) ? "" : log_escape_nq(msr->mp, r->uri)), + level, (fixup ? log_escape_nq(msr->mp, str1) : str1)); + + /* Write to the debug log. */ + if ((debuglog_fd != NULL)&&(level <= filter_debug_level)) { + nbytes = strlen(str2); + apr_file_write_full(debuglog_fd, str2, nbytes, &nbytes_written); + } + + /* Send message levels 1-3 to the Apache error log and + * add it to the message list in the audit log. */ + if (level <= 3) { + char *unique_id = (char *)get_env_var(r, "UNIQUE_ID"); + char *hostname = (char *)msr->hostname; + + if (unique_id != NULL) { + unique_id = apr_psprintf(msr->mp, " [unique_id \"%s\"]", + log_escape(msr->mp, unique_id)); + } + else unique_id = ""; + + if (hostname != NULL) { + hostname = apr_psprintf(msr->mp, " [hostname \"%s\"]", + log_escape(msr->mp, hostname)); + } + else hostname = ""; + + ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r->server, + "[client %s] ModSecurity: %s%s [uri \"%s\"]%s", r->connection->remote_ip, str1, + hostname, log_escape(msr->mp, r->uri), unique_id); + + /* Add this message to the list. */ + if (msr != NULL) { + /* Force relevency if this is an alert */ + msr->is_relevant++; + + *(const char **)apr_array_push(msr->alerts) = apr_pstrdup(msr->mp, str1); + } + } + + return; +} + +/** + * Internal log helper function. Use msr_log instead. + */ +void internal_log(request_rec *r, directory_config *dcfg, modsec_rec *msr, + int level, const char *text, va_list ap) +{ + internal_log_ex(r, dcfg, msr, level, 0, text, ap); +} + +/** + * Logs one message at the given level to the debug log (and to the + * Apache error log if the message is important enough. + */ +void msr_log(modsec_rec *msr, int level, const char *text, ...) { + va_list ap; + + va_start(ap, text); + internal_log_ex(msr->r, msr->txcfg, msr, level, 0, text, ap); + va_end(ap); +} + + +/** + * Logs one message at level 3 to the debug log and to the + * Apache error log. This is intended for error callbacks. + */ +void msr_log_error(modsec_rec *msr, const char *text, ...) { + va_list ap; + + va_start(ap, text); + internal_log_ex(msr->r, msr->txcfg, msr, 3, 1, text, ap); + va_end(ap); +} + +/** + * Logs one message at level 4 to the debug log and to the + * Apache error log. This is intended for warning callbacks. + * + * The 'text' will first be escaped. + */ +void msr_log_warn(modsec_rec *msr, const char *text, ...) { + va_list ap; + + va_start(ap, text); + internal_log_ex(msr->r, msr->txcfg, msr, 4, 1, text, ap); + va_end(ap); +} + + +/** + * Converts an Apache error log message into one line of text. + */ +char *format_error_log_message(apr_pool_t *mp, error_message *em) { + char *s_file = "", *s_line = "", *s_level = ""; + char *s_status = "", *s_message = ""; + char *msg = NULL; + + if (em == NULL) return NULL; + + if (em->file != NULL) { + s_file = apr_psprintf(mp, "[file \"%s\"] ", + log_escape(mp, (char *)em->file)); + if (s_file == NULL) return NULL; + } + + if (em->line > 0) { + s_line = apr_psprintf(mp, "[line %d] ", em->line); + if (s_line == NULL) return NULL; + } + + s_level = apr_psprintf(mp, "[level %d] ", em->level); + if (s_level == NULL) return NULL; + + if (em->status != 0) { + s_status = apr_psprintf(mp, "[status %d] ", em->status); + if (s_status == NULL) return NULL; + } + + if (em->message != NULL) { + s_message = log_escape_nq(mp, em->message); + if (s_message == NULL) return NULL; + } + + msg = apr_psprintf(mp, "%s%s%s%s%s", s_file, s_line, s_level, s_status, s_message); + if (msg == NULL) return NULL; + + return msg; +} + +/** + * Determines the reponse protocol Apache will use (or has used) + * to respond to the given request. + */ +const char *get_response_protocol(request_rec *r) { + int proto_num = r->proto_num; + + if (r->assbackwards) { + return NULL; + } + + if (proto_num > HTTP_VERSION(1,0) + && apr_table_get(r->subprocess_env, "downgrade-1.0")) + { + proto_num = HTTP_VERSION(1,0); + } + + if (proto_num == HTTP_VERSION(1,0) + && apr_table_get(r->subprocess_env, "force-response-1.0")) + { + return "HTTP/1.0"; + } + + return AP_SERVER_PROTOCOL; +} diff --git a/apache2/api/README b/apache2/api/README new file mode 100644 index 0000000..addfb75 --- /dev/null +++ b/apache2/api/README @@ -0,0 +1,76 @@ +Custom ModSecurity Modules +-------------------------- + +This directory contains three examples how you can extend +ModSecurity without having to touch it directly, simply +by creating custom Apache modules. + +NOTE: ModSecurity must be compiled with API support + to use this feature (do not use -DNO_MODSEC_API). + + +Building the Example Custom Modules +----------------------------------- + +1) Example custom transformation function module + +Module mod_tfn_reverse.c creates a custom transformation +function "reverse" that reverses the content it receives +on input. + + # Compile as a normal user + apxs -ca mod_tfn_reverse.c + + # Install as superuser + sudo apxs -i mod_tfn_reverse.la + + +2) Example custom operator module + +Module mod_op_strstr.c creates a custom operator "strstr" +that implements fast matching using the Boyer-Moore-Horspool +algorithm. + +Compiling this module is more involved because it requires +access to ModSecurity structures. + + # Compile as a normal user + apxs -I -I/usr/include/libxml2 \ + -ca mod_op_strstr.c + + # Install as superuser + sudo apxs -i mod_op_strstr.la + + +3) Example custom target variable module + +Module mod_var_remote_addr_port.c creates a custom variable "REMOTE_ADDR_PORT" +that combines the REMOTE_ADDR and REMOTE_PORT into a.b.c.d:port format. + +Compiling this module is more involved because it requires +access to ModSecurity structures. + + # Compile as a normal user + apxs -I -I/usr/include/libxml2 \ + -ca mod_var_remote_addr_port.c + + # Install as superuser + sudo apxs -i mod_var_remote_addr_port.la + + +Using the Modules +----------------- + +Once the modules are built and installed, you load them like any other Apache module, but they must be loaded *after* the mod_security2.so module. + + # Load ModSecurity + LoadModule security2_module modules/mod_security2.so + + # Load ModSecurity custom modules + LoadModule tfn_reverse_module modules/mod_tfn_reverse.so + LoadModule op_strstr_module modules/mod_op_strstr.so + LoadModule var_remote_addr_port_module modules/mod_var_remote_addr_port.so + + # All three custom var/op/tfn used + SecRule REMOTE_ADDR_PORT "@strstr 1.2.3.4:5678" "t:reverse" + diff --git a/apache2/api/mod_op_strstr.c b/apache2/api/mod_op_strstr.c new file mode 100644 index 0000000..46986e7 --- /dev/null +++ b/apache2/api/mod_op_strstr.c @@ -0,0 +1,171 @@ + +#include "httpd.h" +#include "http_core.h" +#include "http_config.h" +#include "http_log.h" +#include "http_protocol.h" +#include "ap_config.h" +#include "apr_optional.h" + +#include "modsecurity.h" + +#define ALPHABET_SIZE 256 +#define MAX_PATTERN_SIZE 64 + +static void initBoyerMooreHorspool(const char *pattern, int patlength, + int *bm_badcharacter_array); + +static int BoyerMooreHorspool(const char *pattern, int patlength, + const char *text, int textlen, int *bm_badcharacter_array); + +/** + * Operator parameter initialisation entry point. + */ +static int op_strstr_init(msre_rule *rule, char **error_msg) { + /* Operator initialisation function will be called once per + * statement where operator is used. It is meant to be used + * to check the parameters to see whether they are present + * and if they are in the correct format. + */ + + /* In this example we just look for a simple non-empty parameter. */ + if ((rule->op_param == NULL)||(strlen(rule->op_param) == 0)) { + *error_msg = apr_psprintf(rule->ruleset->mp, "Missing parameter for operator 'strstr'."); + return 0; /* ERROR */ + } + + /* If you need to transform the data in the parameter into something + * else you should do that here. Simply create a new structure to hold + * the transformed data and place the pointer to it into rule->op_param_data. + * You will have access to this pointer later on. + */ + rule->op_param_data = apr_pcalloc(rule->ruleset->mp, ALPHABET_SIZE * sizeof(int)); + initBoyerMooreHorspool(rule->op_param, strlen(rule->op_param), (int *)rule->op_param_data); + + /* OK */ + return 1; +} + +/** + * Operator execution entry point. + */ +static int op_strstr_exec(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + /* Here we need to inspect the contents of the supplied variable. */ + + /* In a general case it is possible for the value + * to be NULL. What you need to do in this case + * depends on your operator. In this example we return + * a "no match" response. + */ + if (var->value == NULL) return 0; /* No match. */ + + /* Another thing to note is that variables are not C strings, + * meaning the NULL byte is not used to determine the end + * of the string. Variable length var->value_len should be + * used for this purpose. + */ + + if (BoyerMooreHorspool(rule->op_param, strlen(rule->op_param), + var->value, var->value_len, (int *)rule->op_param_data) >= 0) + { + return 1; /* Match. */ + } + + return 0; /* No match. */ +} + +static int hook_pre_config(apr_pool_t *mp, apr_pool_t *mp_log, apr_pool_t *mp_temp) { + void (*fn)(const char *name, void *fn_init, void *fn_exec); + + /* Look for the registration function + * exported by ModSecurity. + */ + fn = APR_RETRIEVE_OPTIONAL_FN(modsec_register_operator); + if (fn) { + /* Use it to register our new + * transformation function under the + * name "reverse". + */ + fn("strstr", (void *)op_strstr_init, (void *)op_strstr_exec); + } + + return OK; +} + +static void register_hooks(apr_pool_t *p) { + ap_hook_pre_config(hook_pre_config, NULL, NULL, APR_HOOK_LAST); +} + +/* Dispatch list for API hooks */ +module AP_MODULE_DECLARE_DATA op_strstr_module = { + STANDARD20_MODULE_STUFF, + NULL, /* create per-dir config structures */ + NULL, /* merge per-dir config structures */ + NULL, /* create per-server config structures */ + NULL, /* merge per-server config structures */ + NULL, /* table of config file commands */ + register_hooks /* register hooks */ +}; + +/* + +This example uses an implementation Boyer-Moore-Horspool +matching algorithm as implemented in Streamline (http://ffpf.sourceforge.net). + +Copyright (c) 2004-2006, Vrije Universiteit Amsterdam +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +Neither the name of the Vrije Universiteit nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +*/ + +static void precompute_badcharacter(const char *pattern, int patlength, + int bm_badcharacter_array[]) +{ + int i; + + for (i = 0; i < ALPHABET_SIZE; ++i) { + bm_badcharacter_array[i] = patlength; + } + + for (i = 0; i < patlength - 1; ++i){ + bm_badcharacter_array[(uint8_t)pattern[i]] = patlength - i - 1; + } +} + +static void initBoyerMooreHorspool(const char *pattern, int patlength, + int *bm_badcharacter_array) +{ + precompute_badcharacter(pattern, + (patlength < MAX_PATTERN_SIZE ? patlength : MAX_PATTERN_SIZE), bm_badcharacter_array); +} + +static int BoyerMooreHorspool(const char *pattern, int patlength, + const char *text, int textlen, int *bm_badcharacter_array) +{ + int j; + char c; + + j = 0; + while (j <= textlen - patlength) { + c = text[j + patlength - 1]; + if (pattern[patlength - 1] == c && memcmp(pattern, text + j, patlength - 1) == 0) { + return j; + } + j += bm_badcharacter_array[(uint8_t)c]; + } + + return -1; +} diff --git a/apache2/api/mod_tfn_reverse.c b/apache2/api/mod_tfn_reverse.c new file mode 100644 index 0000000..8750678 --- /dev/null +++ b/apache2/api/mod_tfn_reverse.c @@ -0,0 +1,88 @@ + +#include "httpd.h" +#include "http_core.h" +#include "http_config.h" +#include "http_log.h" +#include "http_protocol.h" +#include "ap_config.h" +#include "apr_optional.h" + +/* Must be declared if modsecurity.h is not included */ +APR_DECLARE_OPTIONAL_FN(void, modsec_register_tfn, (const char *name, void *fn)); + + +/** + * This function will be invoked by + * ModSecurity to transform input. + */ +static int reverse(apr_pool_t *mptmp, unsigned char *input, + long int input_len, char **rval, long int *rval_len) +{ + /* Transformation functions can choose to do their + * thing in-place, overwriting the existing content. This + * is normally possible only if the transformed content + * is of equal length or shorter. + * + * If you need to expand the content use the temporary + * memory pool mptmp to allocate the space. + */ + + /* Reverse the string in place, but only if it's long enough. */ + if (input_len > 1) { + long int i = 0; + long int j = input_len - 1; + while(i < j) { + char c = input[i]; + input[i] = input[j]; + input[j] = c; + i++; + j--; + } + } + + /* Tell ModSecurity about the content + * we have generated. In this case we + * merely point back to the input buffer. + */ + *rval = (char *)input; + *rval_len = input_len; + + /* Must return 1 if the content was + * changed, or 0 otherwise. + */ + return 1; +} + +static int hook_pre_config(apr_pool_t *mp, apr_pool_t *mp_log, apr_pool_t *mp_temp) { + void (*fn)(const char *name, void *fn); + + /* Look for the registration function + * exported by ModSecurity. + */ + fn = APR_RETRIEVE_OPTIONAL_FN(modsec_register_tfn); + if (fn) { + /* Use it to register our new + * transformation function under the + * name "reverse". + */ + fn("reverse", (void *)reverse); + } + + return OK; +} + +static void register_hooks(apr_pool_t *p) { + ap_hook_pre_config(hook_pre_config, NULL, NULL, APR_HOOK_LAST); +} + +/* Dispatch list for API hooks */ +module AP_MODULE_DECLARE_DATA tfn_reverse_module = { + STANDARD20_MODULE_STUFF, + NULL, /* create per-dir config structures */ + NULL, /* merge per-dir config structures */ + NULL, /* create per-server config structures */ + NULL, /* merge per-server config structures */ + NULL, /* table of config file commands */ + register_hooks /* register hooks */ +}; + diff --git a/apache2/api/mod_var_remote_addr_port.c b/apache2/api/mod_var_remote_addr_port.c new file mode 100644 index 0000000..ffd18f1 --- /dev/null +++ b/apache2/api/mod_var_remote_addr_port.c @@ -0,0 +1,99 @@ + +#include "httpd.h" +#include "http_core.h" +#include "http_config.h" +#include "http_log.h" +#include "http_protocol.h" +#include "ap_config.h" +#include "apr_optional.h" + +#include "re.h" + +/* -- Generic generators/validators from re_variables.c -- */ + +/** + * Generates a variable from a string and a length. + */ +static int var_simple_generate_ex(msre_var *var, apr_table_t *vartab, apr_pool_t *mptmp, + const char *value, int value_len) +{ + msre_var *rvar = NULL; + + if (value == NULL) return 0; + + rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + rvar->value = value; + rvar->value_len = value_len; + apr_table_addn(vartab, rvar->name, (void *)rvar); + + return 1; +} + +/** + * Generates a variable from a NULL-terminated string. + */ +static int var_simple_generate(msre_var *var, apr_table_t *vartab, apr_pool_t *mptmp, + const char *value) +{ + if (value == NULL) return 0; + return var_simple_generate_ex(var, vartab, mptmp, value, strlen(value)); +} + + +/* -- Module specific code -- */ + +/** + * Create a silly variable with value = a.b.c.d:port + */ +static int var_remote_addr_port_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + const char *value = apr_psprintf(mptmp, "%s:%d", msr->remote_addr, msr->remote_port); + + return var_simple_generate(var, vartab, mptmp, value); +} + +static int hook_pre_config(apr_pool_t *mp, apr_pool_t *mp_log, apr_pool_t *mp_temp) { + void (*register_fn)(const char *name, unsigned int type, + unsigned int argc_min, unsigned int argc_max, + void *fn_validate, void *fn_generate, + unsigned int is_cacheable, unsigned int availability); + + /* Look for the registration function + * exported by ModSecurity. + */ + register_fn = APR_RETRIEVE_OPTIONAL_FN(modsec_register_variable); + if (register_fn) { + /* Use it to register our new + * variable under the + * name "REMOTE_ADDR_PORT". + */ + register_fn( + "REMOTE_ADDR_PORT", + VAR_SIMPLE, + 0, 0, + NULL, + var_remote_addr_port_generate, + VAR_DONT_CACHE, + PHASE_REQUEST_HEADERS + ); + } + + return OK; +} + +static void register_hooks(apr_pool_t *p) { + ap_hook_pre_config(hook_pre_config, NULL, NULL, APR_HOOK_LAST); +} + +/* Dispatch list for API hooks */ +module AP_MODULE_DECLARE_DATA var_remote_addr_port_module = { + STANDARD20_MODULE_STUFF, + NULL, /* create per-dir config structures */ + NULL, /* merge per-dir config structures */ + NULL, /* create per-server config structures */ + NULL, /* merge per-server config structures */ + NULL, /* table of config file commands */ + register_hooks /* register hooks */ +}; + diff --git a/apache2/autogen.sh b/apache2/autogen.sh new file mode 100755 index 0000000..197c269 --- /dev/null +++ b/apache2/autogen.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +rm -rf autom4te.cache + +#automake --add-missing --copy +autoreconf --install diff --git a/apache2/build/apxs-wrapper.in b/apache2/build/apxs-wrapper.in new file mode 100755 index 0000000..7e03273 --- /dev/null +++ b/apache2/build/apxs-wrapper.in @@ -0,0 +1,15 @@ +#!@SHELL@ + +WRAPPED_OPTS="" +for opt in "$@"; do + case "$opt" in + # Fix for -R not working w/apxs + -R*) WRAPPED_OPTS="$WRAPPED_OPTS -Wl,$opt" ;; + # OSF1 compiler option + -pthread) WRAPPED_OPTS="$WRAPPED_OPTS -Wc,$opt" ;; + # Unwrapped + *) WRAPPED_OPTS="$WRAPPED_OPTS $opt" ;; + esac +done + +exec @APXS@ $WRAPPED_OPTS diff --git a/apache2/build/find_apr.m4 b/apache2/build/find_apr.m4 new file mode 100644 index 0000000..6c2435a --- /dev/null +++ b/apache2/build/find_apr.m4 @@ -0,0 +1,82 @@ +dnl Check for APR Libraries +dnl CHECK_APR(ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]) +dnl Sets: +dnl APR_CFLAGS +dnl APR_LDFLAGS +dnl APR_LIBS +dnl APR_LINK_LD + +APR_CONFIG="" +APR_CFLAGS="" +APR_LDFLAGS="" +APR_LIBS="" +APR_LINK_LD="" + +AC_DEFUN([CHECK_APR], +[dnl + +AC_ARG_WITH( + apr, + [AC_HELP_STRING([--with-apr=PATH],[Path to apr prefix or config script])], + [test_paths="${with_apr}"], + [test_paths="/usr/local/libapr /usr/local/apr /usr/local /opt/libapr /opt/apr /opt /usr"]) + +AC_MSG_CHECKING([for libapr config script]) + +for x in ${test_paths}; do + dnl # Determine if the script was specified and use it directly + if test ! -d "$x" -a -e "$x"; then + APR_CONFIG=$x + apr_path=no + break + fi + + dnl # Try known config script names/locations + for APR_CONFIG in apr-1-mt-config apr-1-config apr-config-1 apr-mt-config-1 apr-mt-config apr-config; do + if test -e "${x}/bin/${APR_CONFIG}"; then + apr_path="${x}/bin" + break + elif test -e "${x}/${APR_CONFIG}"; then + apr_path="${x}" + break + else + apr_path="" + fi + done + if test -n "$apr_path"; then + break + fi +done + +if test -n "${apr_path}"; then + if test "${apr_path}" != "no"; then + APR_CONFIG="${apr_path}/${APR_CONFIG}" + fi + AC_MSG_RESULT([${APR_CONFIG}]) + APR_CFLAGS="`${APR_CONFIG} --includes --cppflags --cflags`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apr CFLAGS: $APR_CFLAGS); fi + APR_LDFLAGS="`${APR_CONFIG} --ldflags`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apr LDFLAGS: $APR_LDFLAGS); fi + APR_LIBS="`${APR_CONFIG} --libs`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apr LIBS: $APR_LIBS); fi + APR_LINK_LD="`${APR_CONFIG} --link-ld`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apr LINK_LD: $APR_LINK_LD); fi + CFLAGS=$save_CFLAGS + LDFLAGS=$save_LDFLAGS +else + AC_MSG_RESULT([no]) +fi + +AC_SUBST(APR_LIBS) +AC_SUBST(APR_CFLAGS) +AC_SUBST(APR_LDFLAGS) +AC_SUBST(APR_LINK_LD) + +if test -z "${APR_LIBS}"; then + AC_MSG_NOTICE([*** apr library not found.]) + ifelse([$2], , AC_MSG_ERROR([apr library is required]), $2) +else + AC_MSG_NOTICE([using '${APR_LIBS}' for apr Library]) + ifelse([$1], , , $1) +fi +]) diff --git a/apache2/build/find_apu.m4 b/apache2/build/find_apu.m4 new file mode 100644 index 0000000..27a96a8 --- /dev/null +++ b/apache2/build/find_apu.m4 @@ -0,0 +1,82 @@ +dnl Check for APU Libraries +dnl CHECK_APU(ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]) +dnl Sets: +dnl APU_CFLAGS +dnl APU_LDFLAGS +dnl APU_LIBS +dnl APU_LINK_LD + +APU_CONFIG="" +APU_CFLAGS="" +APU_LDFLAGS="" +APU_LIBS="" +APU_LINK_LD="" + +AC_DEFUN([CHECK_APU], +[dnl + +AC_ARG_WITH( + apu, + [AC_HELP_STRING([--with-apu=PATH],[Path to apu prefix or config script])], + [test_paths="${with_apu}"], + [test_paths="/usr/local/libapr-util /usr/local/apr-util /usr/local/libapu /usr/local/apu /usr/local /opt/libapr-util /opt/apr-util /opt/libapu /opt/apu /opt /usr"]) + +AC_MSG_CHECKING([for libapu config script]) + +for x in ${test_paths}; do + dnl # Determine if the script was specified and use it directly + if test ! -d "$x" -a -e "$x"; then + APU_CONFIG=$x + apu_path="no" + break + fi + + dnl # Try known config script names/locations + for APU_CONFIG in apu-1-mt-config apu-1-config apu-config-1 apu-mt-config-1 apu-mt-config apu-config; do + if test -e "${x}/bin/${APU_CONFIG}"; then + apu_path="${x}/bin" + break + elif test -e "${x}/${APU_CONFIG}"; then + apu_path="${x}" + break + else + apu_path="" + fi + done + if test -n "$apu_path"; then + break + fi +done + +if test -n "${apu_path}"; then + if test "${apu_path}" != "no"; then + APU_CONFIG="${apu_path}/${APU_CONFIG}" + fi + AC_MSG_RESULT([${APU_CONFIG}]) + APU_CFLAGS="`${APU_CONFIG} --includes`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apu CFLAGS: $APU_CFLAGS); fi + APU_LDFLAGS="`${APU_CONFIG} --ldflags`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apu LDFLAGS: $APU_LDFLAGS); fi + APU_LIBS="`${APU_CONFIG} --libs`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apu LIBS: $APU_LIBS); fi + APU_LINK_LD="`${APU_CONFIG} --link-ld`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apu LINK_LD: $APU_LINK_LD); fi + CFLAGS=$save_CFLAGS + LDFLAGS=$save_LDFLAGS +else + AC_MSG_RESULT([no]) +fi + +AC_SUBST(APU_LIBS) +AC_SUBST(APU_CFLAGS) +AC_SUBST(APU_LDFLAGS) +AC_SUBST(APU_LINK_LD) + +if test -z "${APU_LIBS}"; then + AC_MSG_NOTICE([*** apu library not found.]) + ifelse([$2], , AC_MSG_ERROR([apu library is required]), $2) +else + AC_MSG_NOTICE([using '${APU_LIBS}' for apu Library]) + ifelse([$1], , , $1) +fi +]) diff --git a/apache2/build/find_curl.m4 b/apache2/build/find_curl.m4 new file mode 100644 index 0000000..1e1dcb1 --- /dev/null +++ b/apache2/build/find_curl.m4 @@ -0,0 +1,100 @@ +dnl Check for CURL Libraries +dnl CHECK_CURL(ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]) +dnl Sets: +dnl CURL_CFLAGS +dnl CURL_LIBS + +CURL_CONFIG="" +CURL_CFLAGS="" +CURL_LIBS="" +CURL_MIN_VERSION="7.15.1" + +AC_DEFUN([CHECK_CURL], +[dnl + +AC_ARG_WITH( + curl, + [AC_HELP_STRING([--with-curl=PATH],[Path to curl prefix or config script])], + [test_paths="${with_curl}"], + [test_paths="/usr/local/libcurl /usr/local/curl /usr/local /opt/libcurl /opt/curl /opt /usr"]) + +AC_MSG_CHECKING([for libcurl config script]) + +for x in ${test_paths}; do + dnl # Determine if the script was specified and use it directly + if test ! -d "$x" -a -e "$x"; then + CURL_CONFIG=$x + curl_path="no" + break + fi + + dnl # Try known config script names/locations + for CURL_CONFIG in curl-config; do + if test -e "${x}/bin/${CURL_CONFIG}"; then + curl_path="${x}/bin" + break + elif test -e "${x}/${CURL_CONFIG}"; then + curl_path="${x}" + break + else + curl_path="" + fi + done + if test -n "$curl_path"; then + break + fi +done + +if test -n "${curl_path}"; then + if test "${curl_path}" != "no"; then + CURL_CONFIG="${curl_path}/${CURL_CONFIG}" + fi + AC_MSG_RESULT([${CURL_CONFIG}]) + CURL_CFLAGS="`${CURL_CONFIG} --cflags`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(curl CFLAGS: $CURL_CFLAGS); fi + CURL_LIBS="`${CURL_CONFIG} --libs`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(curl LIBS: $CURL_LIBS); fi + CURL_VERSION=`${CURL_CONFIG} --version | sed 's/^[[^0-9]][[^[:space:]]][[^[:space:]]]*[[[:space:]]]*//'` + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(curl VERSION: $CURL_VERSION); fi + CFLAGS=$save_CFLAGS + LDFLAGS=$save_LDFLAGS + + dnl # Check version is ok + AC_MSG_CHECKING([if libcurl is at least v${CURL_MIN_VERSION}]) + curl_min_ver=`echo ${CURL_MIN_VERSION} | awk -F. '{print (\$ 1 * 1000000) + (\$ 2 * 1000) + \$ 3}'` + curl_ver=`echo ${CURL_VERSION} | awk -F. '{print (\$ 1 * 1000000) + (\$ 2 * 1000) + \$ 3}'` + if test "$curl_min_ver" -le "$curl_ver"; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + AC_MSG_NOTICE([NOTE: curl library may be too old: $CURL_VERSION]) + fi + + dnl # Check/warn if GnuTLS is used + AC_MSG_CHECKING([if libcurl is linked with gnutls]) + curl_uses_gnutls=`echo ${CURL_LIBS} | grep gnutls | wc -l` + if test "$curl_uses_gnutls" -ne 0; then + AC_MSG_RESULT([yes]) + AC_MSG_NOTICE([NOTE: curl linked with gnutls may be buggy, openssl recommended]) + CURL_USES_GNUTLS=yes + else + AC_MSG_RESULT([no]) + CURL_USES_GNUTLS=no + fi + +else + AC_MSG_RESULT([no]) +fi + +AC_SUBST(CURL_LIBS) +AC_SUBST(CURL_CFLAGS) +AC_SUBST(CURL_USES_GNUTLS) + +if test -z "${CURL_LIBS}"; then + AC_MSG_NOTICE([*** curl library not found.]) + ifelse([$2], , AC_MSG_NOTICE([NOTE: curl library is only required for building mlogc]), $2) +else + AC_MSG_NOTICE([using '${CURL_LIBS}' for curl Library]) + ifelse([$1], , , $1) +fi +]) diff --git a/apache2/build/find_lua.m4 b/apache2/build/find_lua.m4 new file mode 100644 index 0000000..5c99561 --- /dev/null +++ b/apache2/build/find_lua.m4 @@ -0,0 +1,184 @@ +dnl Check for LUA Libraries +dnl CHECK_LUA(ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]) +dnl Sets: +dnl LUA_CFLAGS +dnl LUA_LIBS + +LUA_CONFIG="" +LUA_CFLAGS="" +LUA_LIBS="" +LUA_CONFIG=pkg-config +LUA_PKGNAMES="lua5.1 lua-5.1 lua_5.1 lua-51 lua_51 lua51 lua5 lua" +LUA_SONAMES="so la sl dll dylib" + +AC_DEFUN([CHECK_LUA], +[dnl + +AC_ARG_WITH( + lua, + [AC_HELP_STRING([--with-lua=PATH],[Path to lua prefix or config script])], + [test_paths="${with_lua}"], + [test_paths="/usr/local/liblua /usr/local/lua /usr/local /opt/liblua /opt/lua /opt /usr"; ]) + +AC_MSG_CHECKING([for liblua config script]) + +for x in ${test_paths}; do + dnl # Determine if the script was specified and use it directly + if test ! -d "$x" -a -e "$x"; then + LUA_CONFIG=$x + break + fi + + dnl # Try known config script names/locations + for y in $LUA_CONFIG; do + if test -e "${x}/bin/${y}"; then + LUA_CONFIG="${x}/bin/${y}" + lua_config="${LUA_CONFIG}" + break + elif test -e "${x}/${y}"; then + LUA_CONFIG="${x}/${y}" + lua_config="${LUA_CONFIG}" + break + fi + done + if test -n "${lua_config}"; then + break + fi +done + +dnl # Try known package names +if test -n "${LUA_CONFIG}"; then + LUA_PKGNAME="" + for x in ${LUA_PKGNAMES}; do + if ${LUA_CONFIG} --exists ${x}; then + LUA_PKGNAME="$x" + break + fi + done +fi + +if test -n "${LUA_PKGNAME}"; then + AC_MSG_RESULT([${LUA_CONFIG}]) + LUA_CFLAGS="`${LUA_CONFIG} ${LUA_PKGNAME} --cflags`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(lua CFLAGS: $LUA_CFLAGS); fi + LUA_LIBS="`${LUA_CONFIG} ${LUA_PKGNAME} --libs`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(lua LIBS: $LUA_LIBS); fi + CFLAGS=$save_CFLAGS + LDFLAGS=$save_LDFLAGS +else + AC_MSG_RESULT([no]) + + dnl Hack to just try to find the lib and include + AC_MSG_CHECKING([for lua install]) + for x in ${test_paths}; do + for y in ${LUA_SONAMES}; do + if test -e "${x}/liblua5.1.${y}"; then + lua_lib_path="${x}" + lua_lib_name="lua5.1" + break + elif test -e "${x}/lib/liblua5.1.${y}"; then + lua_lib_path="${x}/lib" + lua_lib_name="lua5.1" + break + elif test -e "${x}/lib64/liblua5.1.${y}"; then + lua_lib_path="${x}/lib64" + lua_lib_name="lua5.1" + break + elif test -e "${x}/lib32/liblua5.1.${y}"; then + lua_lib_path="${x}/lib32" + lua_lib_name="lua5.1" + break + elif test -e "${x}/liblua51.${y}"; then + lua_lib_path="${x}" + lua_lib_name="lua51" + break + elif test -e "${x}/lib/liblua51.${y}"; then + lua_lib_path="${x}/lib" + lua_lib_name="lua51" + break + elif test -e "${x}/lib64/liblua51.${y}"; then + lua_lib_path="${x}/lib64" + lua_lib_name="lua51" + break + elif test -e "${x}/lib32/liblua51.${y}"; then + lua_lib_path="${x}/lib32" + lua_lib_name="lua51" + break + elif test -e "${x}/liblua.${y}"; then + lua_lib_path="${x}" + lua_lib_name="lua" + break + elif test -e "${x}/lib/liblua.${y}"; then + lua_lib_path="${x}/lib" + lua_lib_name="lua" + break + elif test -e "${x}/lib64/liblua.${y}"; then + lua_lib_path="${x}/lib64" + lua_lib_name="lua" + break + elif test -e "${x}/lib32/liblua.${y}"; then + lua_lib_path="${x}/lib32" + lua_lib_name="lua" + break + else + lua_lib_path="" + lua_lib_name="" + fi + done + if test -n "$lua_lib_path"; then + break + fi + done + for x in ${test_paths}; do + if test -e "${x}/include/lua.h"; then + lua_inc_path="${x}/include" + break + elif test -e "${x}/lua.h"; then + lua_inc_path="${x}" + break + fi + + dnl # Check some sub-paths as well + for lua_pkg_name in ${lua_lib_name} ${LUA_PKGNAMES}; do + if test -e "${x}/include/${lua_pkg_name}/lua.h"; then + lua_inc_path="${x}/include" + break + elif test -e "${x}/${lua_pkg_name}/lua.h"; then + lua_inc_path="${x}" + break + else + lua_inc_path="" + fi + done + if test -n "$lua_inc_path"; then + break + fi + done + if test -n "${lua_lib_path}" -a -n "${lua_inc_path}"; then + LUA_CONFIG="" + AC_MSG_RESULT([${lua_lib_path} ${lua_inc_path}]) + LUA_CFLAGS="-I${lua_inc_path}" + LUA_LIBS="-L${lua_lib_path} -l${lua_lib_name}" + CFLAGS=$save_CFLAGS + LDFLAGS=$save_LDFLAGS + else + AC_MSG_RESULT([no]) + fi +fi + +if test -n "${LUA_LIBS}"; then + LUA_CFLAGS="-DWITH_LUA ${LUA_CFLAGS}" +fi + +AC_SUBST(LUA_LIBS) +AC_SUBST(LUA_CFLAGS) + +if test "${with_path}" != "no"; then + if test -z "${LUA_LIBS}"; then + ifelse([$2], , AC_MSG_NOTICE([optional lua library not found]), $2) + else + AC_MSG_NOTICE([using '${LUA_LIBS}' for lua Library]) + ifelse([$1], , , $1) + fi +fi +]) diff --git a/apache2/build/find_pcre.m4 b/apache2/build/find_pcre.m4 new file mode 100644 index 0000000..9241dba --- /dev/null +++ b/apache2/build/find_pcre.m4 @@ -0,0 +1,81 @@ +dnl Check for PCRE Libraries +dnl CHECK_PCRE(ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]) +dnl Sets: +dnl PCRE_CFLAGS +dnl PCRE_LIBS + +PCRE_CONFIG="" +PCRE_CFLAGS="" +PCRE_LIBS="" + +AC_DEFUN([CHECK_PCRE], +[dnl + +AC_ARG_WITH( + pcre, + [AC_HELP_STRING([--with-pcre=PATH],[Path to pcre prefix or config script])], + [test_paths="${with_pcre}"], + [test_paths="/usr/local/libpcre /usr/local/pcre /usr/local /opt/libpcre /opt/pcre /opt /usr"]) + +AC_MSG_CHECKING([for libpcre config script]) + +dnl # Determine pcre lib directory +if test -z "${with_pcre}"; then + test_paths="/usr/local/pcre /usr/local /usr" +else + test_paths="${with_pcre}" +fi + +for x in ${test_paths}; do + dnl # Determine if the script was specified and use it directly + if test ! -d "$x" -a -e "$x"; then + PCRE_CONFIG=$x + pcre_path="no" + break + fi + + dnl # Try known config script names/locations + for PCRE_CONFIG in pcre-config; do + if test -e "${x}/bin/${PCRE_CONFIG}"; then + pcre_path="${x}/bin" + break + elif test -e "${x}/${PCRE_CONFIG}"; then + pcre_path="${x}" + break + else + pcre_path="" + fi + done + if test -n "$pcre_path"; then + break + fi +done + CFLAGS=$save_CFLAGS + LDFLAGS=$save_LDFLAGS + +if test -n "${pcre_path}"; then + if test "${pcre_path}" != "no"; then + PCRE_CONFIG="${pcre_path}/${PCRE_CONFIG}" + fi + AC_MSG_RESULT([${PCRE_CONFIG}]) + PCRE_CFLAGS="`${PCRE_CONFIG} --cflags`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(pcre CFLAGS: $PCRE_CFLAGS); fi + PCRE_LIBS="`${PCRE_CONFIG} --libs`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(pcre LIBS: $PCRE_LIBS); fi + CFLAGS=$save_CFLAGS + LDFLAGS=$save_LDFLAGS +else + AC_MSG_RESULT([no]) +fi + +AC_SUBST(PCRE_LIBS) +AC_SUBST(PCRE_CFLAGS) + +if test -z "${PCRE_LIBS}"; then + AC_MSG_NOTICE([*** pcre library not found.]) + ifelse([$2], , AC_MSG_ERROR([pcre library is required]), $2) +else + AC_MSG_NOTICE([using '${PCRE_LIBS}' for pcre Library]) + ifelse([$1], , , $1) +fi +]) diff --git a/apache2/build/find_xml.m4 b/apache2/build/find_xml.m4 new file mode 100644 index 0000000..cd82694 --- /dev/null +++ b/apache2/build/find_xml.m4 @@ -0,0 +1,74 @@ +dnl Check for LIBXML2 Libraries +dnl CHECK_LIBXML2(ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]) +dnl Sets: +dnl LIBXML2_CFLAGS +dnl LIBXML2_LIBS + +LIBXML2_CONFIG="" +LIBXML2_CFLAGS="" +LIBXML2_LIBS="" + +AC_DEFUN([CHECK_LIBXML2], +[dnl + +AC_ARG_WITH( + libxml, + [AC_HELP_STRING([--with-libxml=PATH],[Path to libxml2 prefix or config script])], + [test_paths="${with_libxml}"], + [test_paths="/usr/local/libxml2 /usr/local/xml2 /usr/local/xml /usr/local /opt/libxml2 /opt/libxml /opt/xml2 /opt/xml /opt /usr"]) + +AC_MSG_CHECKING([for libxml2 config script]) + +for x in ${test_paths}; do + dnl # Determine if the script was specified and use it directly + if test ! -d "$x" -a -e "$x"; then + LIBXML2_CONFIG=$x + libxml2_path="no" + break + fi + + dnl # Try known config script names/locations + for LIBXML2_CONFIG in xml2-config xml-2-config xml-config; do + if test -e "${x}/bin/${LIBXML2_CONFIG}"; then + libxml2_path="${x}/bin" + break + elif test -e "${x}/${LIBXML2_CONFIG}"; then + libxml2_path="${x}" + break + else + libxml2_path="" + fi + done + if test -n "$libxml2_path"; then + break + fi +done + CFLAGS=$save_CFLAGS + LDFLAGS=$save_LDFLAGS + +if test -n "${libxml2_path}"; then + if test "${libxml2_path}" != "no"; then + LIBXML2_CONFIG="${libxml2_path}/${LIBXML2_CONFIG}" + fi + AC_MSG_RESULT([${LIBXML2_CONFIG}]) + LIBXML2_CFLAGS="`${LIBXML2_CONFIG} --cflags`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(xml CFLAGS: $LIBXML2_CFLAGS); fi + LIBXML2_LIBS="`${LIBXML2_CONFIG} --libs`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(xml LIBS: $LIBXML2_LIBS); fi + CFLAGS=$save_CFLAGS + LDFLAGS=$save_LDFLAGS +else + AC_MSG_RESULT([no]) +fi + +AC_SUBST(LIBXML2_LIBS) +AC_SUBST(LIBXML2_CFLAGS) + +if test -z "${LIBXML2_LIBS}"; then + AC_MSG_NOTICE([*** xml library not found.]) + ifelse([$2], , AC_MSG_ERROR([libxml2 is required]), $2) +else + AC_MSG_NOTICE([using '${LIBXML2_LIBS}' for libxml2]) + ifelse([$1], , , $1) +fi +]) diff --git a/apache2/build/install-sh b/apache2/build/install-sh new file mode 100755 index 0000000..b6376ec --- /dev/null +++ b/apache2/build/install-sh @@ -0,0 +1,224 @@ +#!/bin/sh +## +## install.sh -- install a program, script or datafile +## +## Based on `install-sh' from the X Consortium's X11R5 distribution +## as of 89/12/18 which is freely available. +## Cleaned up for Apache's Autoconf-style Interface (APACI) +## by Ralf S. Engelschall +## +# +# This script falls under the Apache License. +# See http://www.apache.org/docs/LICENSE + + +# +# put in absolute paths if you don't have them in your path; +# or use env. vars. +# +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" + +# +# parse argument line +# +instcmd="$mvprog" +chmodcmd="" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +ext="" +src="" +dst="" +while [ "x$1" != "x" ]; do + case $1 in + -c) instcmd="$cpprog" + shift; continue + ;; + -m) chmodcmd="$chmodprog $2" + shift; shift; continue + ;; + -o) chowncmd="$chownprog $2" + shift; shift; continue + ;; + -g) chgrpcmd="$chgrpprog $2" + shift; shift; continue + ;; + -s) stripcmd="$stripprog" + shift; continue + ;; + -S) stripcmd="$stripprog $2" + shift; shift; continue + ;; + -e) ext="$2" + shift; shift; continue + ;; + *) if [ "x$src" = "x" ]; then + src=$1 + else + dst=$1 + fi + shift; continue + ;; + esac +done +if [ "x$src" = "x" ]; then + echo "install.sh: no input file specified" + exit 1 +fi +if [ "x$dst" = "x" ]; then + echo "install.sh: no destination specified" + exit 1 +fi + +# +# If destination is a directory, append the input filename; if +# your system does not like double slashes in filenames, you may +# need to add some logic +# +if [ -d $dst ]; then + dst="$dst/`basename $src`" +fi + +# Add a possible extension (such as ".exe") to src and dst +src="$src$ext" +dst="$dst$ext" + +# Make a temp file name in the proper directory. +dstdir=`dirname $dst` +dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name +$instcmd $src $dsttmp + +# And set any options; do chmod last to preserve setuid bits +if [ "x$chowncmd" != "x" ]; then $chowncmd $dsttmp; fi +if [ "x$chgrpcmd" != "x" ]; then $chgrpcmd $dsttmp; fi +if [ "x$stripcmd" != "x" ]; then $stripcmd $dsttmp; fi +if [ "x$chmodcmd" != "x" ]; then $chmodcmd $dsttmp; fi + +# Now rename the file to the real destination. +$rmcmd $dst +$mvcmd $dsttmp $dst + +exit 0 + +#!/bin/sh +## +## install.sh -- install a program, script or datafile +## +## Based on `install-sh' from the X Consortium's X11R5 distribution +## as of 89/12/18 which is freely available. +## Cleaned up for Apache's Autoconf-style Interface (APACI) +## by Ralf S. Engelschall +## +# +# This script falls under the Apache License. +# See http://www.apache.org/docs/LICENSE + + +# +# put in absolute paths if you don't have them in your path; +# or use env. vars. +# +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" + +# +# parse argument line +# +instcmd="$mvprog" +chmodcmd="" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +ext="" +src="" +dst="" +while [ "x$1" != "x" ]; do + case $1 in + -c) instcmd="$cpprog" + shift; continue + ;; + -m) chmodcmd="$chmodprog $2" + shift; shift; continue + ;; + -o) chowncmd="$chownprog $2" + shift; shift; continue + ;; + -g) chgrpcmd="$chgrpprog $2" + shift; shift; continue + ;; + -s) stripcmd="$stripprog" + shift; continue + ;; + -S) stripcmd="$stripprog $2" + shift; shift; continue + ;; + -e) ext="$2" + shift; shift; continue + ;; + *) if [ "x$src" = "x" ]; then + src=$1 + else + dst=$1 + fi + shift; continue + ;; + esac +done +if [ "x$src" = "x" ]; then + echo "install.sh: no input file specified" + exit 1 +fi +if [ "x$dst" = "x" ]; then + echo "install.sh: no destination specified" + exit 1 +fi + +# +# If destination is a directory, append the input filename; if +# your system does not like double slashes in filenames, you may +# need to add some logic +# +if [ -d $dst ]; then + dst="$dst/`basename $src`" +fi + +# Add a possible extension (such as ".exe") to src and dst +src="$src$ext" +dst="$dst$ext" + +# Make a temp file name in the proper directory. +dstdir=`dirname $dst` +dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name +$instcmd $src $dsttmp + +# And set any options; do chmod last to preserve setuid bits +if [ "x$chowncmd" != "x" ]; then $chowncmd $dsttmp; fi +if [ "x$chgrpcmd" != "x" ]; then $chgrpcmd $dsttmp; fi +if [ "x$stripcmd" != "x" ]; then $stripcmd $dsttmp; fi +if [ "x$chmodcmd" != "x" ]; then $chmodcmd $dsttmp; fi + +# Now rename the file to the real destination. +$rmcmd $dst +$mvcmd $dsttmp $dst + +exit 0 + diff --git a/apache2/build/libtool.m4 b/apache2/build/libtool.m4 new file mode 100644 index 0000000..e58eac9 --- /dev/null +++ b/apache2/build/libtool.m4 @@ -0,0 +1,7373 @@ +# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008 Free Software Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +m4_define([_LT_COPYING], [dnl +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008 Free Software Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is part of GNU Libtool. +# +# GNU Libtool is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, or +# obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +]) + +# serial 56 LT_INIT + + +# LT_PREREQ(VERSION) +# ------------------ +# Complain and exit if this libtool version is less that VERSION. +m4_defun([LT_PREREQ], +[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, + [m4_default([$3], + [m4_fatal([Libtool version $1 or higher is required], + 63)])], + [$2])]) + + +# _LT_CHECK_BUILDDIR +# ------------------ +# Complain if the absolute build directory name contains unusual characters +m4_defun([_LT_CHECK_BUILDDIR], +[case `pwd` in + *\ * | *\ *) + AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; +esac +]) + + +# LT_INIT([OPTIONS]) +# ------------------ +AC_DEFUN([LT_INIT], +[AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT +AC_BEFORE([$0], [LT_LANG])dnl +AC_BEFORE([$0], [LT_OUTPUT])dnl +AC_BEFORE([$0], [LTDL_INIT])dnl +m4_require([_LT_CHECK_BUILDDIR])dnl + +dnl Autoconf doesn't catch unexpanded LT_ macros by default: +m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl +m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl +dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 +dnl unless we require an AC_DEFUNed macro: +AC_REQUIRE([LTOPTIONS_VERSION])dnl +AC_REQUIRE([LTSUGAR_VERSION])dnl +AC_REQUIRE([LTVERSION_VERSION])dnl +AC_REQUIRE([LTOBSOLETE_VERSION])dnl +m4_require([_LT_PROG_LTMAIN])dnl + +dnl Parse OPTIONS +_LT_SET_OPTIONS([$0], [$1]) + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ltmain" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(apr_builddir)/libtool' +AC_SUBST(LIBTOOL)dnl + +_LT_SETUP + +# Only expand once: +m4_define([LT_INIT]) +])# LT_INIT + +# Old names: +AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) +AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PROG_LIBTOOL], []) +dnl AC_DEFUN([AM_PROG_LIBTOOL], []) + + +# _LT_CC_BASENAME(CC) +# ------------------- +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +m4_defun([_LT_CC_BASENAME], +[for cc_temp in $1""; do + case $cc_temp in + compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; + distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` +]) + + +# _LT_FILEUTILS_DEFAULTS +# ---------------------- +# It is okay to use these file commands and assume they have been set +# sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'. +m4_defun([_LT_FILEUTILS_DEFAULTS], +[: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} +])# _LT_FILEUTILS_DEFAULTS + + +# _LT_SETUP +# --------- +m4_defun([_LT_SETUP], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +_LT_DECL([], [host_alias], [0], [The host system])dnl +_LT_DECL([], [host], [0])dnl +_LT_DECL([], [host_os], [0])dnl +dnl +_LT_DECL([], [build_alias], [0], [The build system])dnl +_LT_DECL([], [build], [0])dnl +_LT_DECL([], [build_os], [0])dnl +dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +dnl +AC_REQUIRE([AC_PROG_LN_S])dnl +test -z "$LN_S" && LN_S="ln -s" +_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl +dnl +AC_REQUIRE([LT_CMD_MAX_LEN])dnl +_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl +_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl +dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_CHECK_SHELL_FEATURES])dnl +m4_require([_LT_CMD_RELOAD])dnl +m4_require([_LT_CHECK_MAGIC_METHOD])dnl +m4_require([_LT_CMD_OLD_ARCHIVE])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl + +_LT_CONFIG_LIBTOOL_INIT([ +# See if we are running on zsh, and set the options which allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi +]) +if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + +_LT_CHECK_OBJDIR + +m4_require([_LT_TAG_COMPILER])dnl +_LT_PROG_ECHO_BACKSLASH + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\([["`\\]]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a + +with_gnu_ld="$lt_cv_prog_gnu_ld" + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +_LT_CC_BASENAME([$compiler]) + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + _LT_PATH_MAGIC + fi + ;; +esac + +# Use C for the default configuration in the libtool script +LT_SUPPORTED_TAG([CC]) +_LT_LANG_C_CONFIG +_LT_LANG_DEFAULT_CONFIG +_LT_CONFIG_COMMANDS +])# _LT_SETUP + + +# _LT_PROG_LTMAIN +# --------------- +# Note that this code is called both from `configure', and `config.status' +# now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, +# `config.status' has no value for ac_aux_dir unless we are using Automake, +# so we pass a copy along to make sure it has a sensible value anyway. +m4_defun([_LT_PROG_LTMAIN], +[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl +_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) +ltmain="$ac_aux_dir/ltmain.sh" +])# _LT_PROG_LTMAIN + + +## ------------------------------------- ## +## Accumulate code for creating libtool. ## +## ------------------------------------- ## + +# So that we can recreate a full libtool script including additional +# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS +# in macros and then make a single call at the end using the `libtool' +# label. + + +# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) +# ---------------------------------------- +# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL_INIT], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_INIT], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_INIT]) + + +# _LT_CONFIG_LIBTOOL([COMMANDS]) +# ------------------------------ +# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) + + +# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) +# ----------------------------------------------------- +m4_defun([_LT_CONFIG_SAVE_COMMANDS], +[_LT_CONFIG_LIBTOOL([$1]) +_LT_CONFIG_LIBTOOL_INIT([$2]) +]) + + +# _LT_FORMAT_COMMENT([COMMENT]) +# ----------------------------- +# Add leading comment marks to the start of each line, and a trailing +# full-stop to the whole comment if one is not present already. +m4_define([_LT_FORMAT_COMMENT], +[m4_ifval([$1], [ +m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], + [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) +)]) + + + +## ------------------------ ## +## FIXME: Eliminate VARNAME ## +## ------------------------ ## + + +# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) +# ------------------------------------------------------------------- +# CONFIGNAME is the name given to the value in the libtool script. +# VARNAME is the (base) name used in the configure script. +# VALUE may be 0, 1 or 2 for a computed quote escaped value based on +# VARNAME. Any other value will be used directly. +m4_define([_LT_DECL], +[lt_if_append_uniq([lt_decl_varnames], [$2], [, ], + [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], + [m4_ifval([$1], [$1], [$2])]) + lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) + m4_ifval([$4], + [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) + lt_dict_add_subkey([lt_decl_dict], [$2], + [tagged?], [m4_ifval([$5], [yes], [no])])]) +]) + + +# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) +# -------------------------------------------------------- +m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) + + +# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_tag_varnames], +[_lt_decl_filter([tagged?], [yes], $@)]) + + +# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) +# --------------------------------------------------------- +m4_define([_lt_decl_filter], +[m4_case([$#], + [0], [m4_fatal([$0: too few arguments: $#])], + [1], [m4_fatal([$0: too few arguments: $#: $1])], + [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], + [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], + [lt_dict_filter([lt_decl_dict], $@)])[]dnl +]) + + +# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) +# -------------------------------------------------- +m4_define([lt_decl_quote_varnames], +[_lt_decl_filter([value], [1], $@)]) + + +# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_dquote_varnames], +[_lt_decl_filter([value], [2], $@)]) + + +# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_varnames_tagged], +[m4_assert([$# <= 2])dnl +_$0(m4_quote(m4_default([$1], [[, ]])), + m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), + m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) +m4_define([_lt_decl_varnames_tagged], +[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) + + +# lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_all_varnames], +[_$0(m4_quote(m4_default([$1], [[, ]])), + m4_if([$2], [], + m4_quote(lt_decl_varnames), + m4_quote(m4_shift($@))))[]dnl +]) +m4_define([_lt_decl_all_varnames], +[lt_join($@, lt_decl_varnames_tagged([$1], + lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl +]) + + +# _LT_CONFIG_STATUS_DECLARE([VARNAME]) +# ------------------------------------ +# Quote a variable value, and forward it to `config.status' so that its +# declaration there will have the same value as in `configure'. VARNAME +# must have a single quote delimited value for this to work. +m4_define([_LT_CONFIG_STATUS_DECLARE], +[$1='`$ECHO "X$][$1" | $Xsed -e "$delay_single_quote_subst"`']) + + +# _LT_CONFIG_STATUS_DECLARATIONS +# ------------------------------ +# We delimit libtool config variables with single quotes, so when +# we write them to config.status, we have to be sure to quote all +# embedded single quotes properly. In configure, this macro expands +# each variable declared with _LT_DECL (and _LT_TAGDECL) into: +# +# ='`$ECHO "X$" | $Xsed -e "$delay_single_quote_subst"`' +m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], +[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), + [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAGS +# ---------------- +# Output comment and list of tags supported by the script +m4_defun([_LT_LIBTOOL_TAGS], +[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl +available_tags="_LT_TAGS"dnl +]) + + +# _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) +# ----------------------------------- +# Extract the dictionary values for VARNAME (optionally with TAG) and +# expand to a commented shell variable setting: +# +# # Some comment about what VAR is for. +# visible_name=$lt_internal_name +m4_define([_LT_LIBTOOL_DECLARE], +[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], + [description])))[]dnl +m4_pushdef([_libtool_name], + m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl +m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), + [0], [_libtool_name=[$]$1], + [1], [_libtool_name=$lt_[]$1], + [2], [_libtool_name=$lt_[]$1], + [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl +m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl +]) + + +# _LT_LIBTOOL_CONFIG_VARS +# ----------------------- +# Produce commented declarations of non-tagged libtool config variables +# suitable for insertion in the LIBTOOL CONFIG section of the `libtool' +# script. Tagged libtool config variables (even for the LIBTOOL CONFIG +# section) are produced by _LT_LIBTOOL_TAG_VARS. +m4_defun([_LT_LIBTOOL_CONFIG_VARS], +[m4_foreach([_lt_var], + m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAG_VARS(TAG) +# ------------------------- +m4_define([_LT_LIBTOOL_TAG_VARS], +[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) + + +# _LT_TAGVAR(VARNAME, [TAGNAME]) +# ------------------------------ +m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) + + +# _LT_CONFIG_COMMANDS +# ------------------- +# Send accumulated output to $CONFIG_STATUS. Thanks to the lists of +# variables for single and double quote escaping we saved from calls +# to _LT_DECL, we can put quote escaped variables declarations +# into `config.status', and then the shell code to quote escape them in +# for loops in `config.status'. Finally, any additional code accumulated +# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. +m4_defun([_LT_CONFIG_COMMANDS], +[AC_PROVIDE_IFELSE([LT_OUTPUT], + dnl If the libtool generation code has been placed in $CONFIG_LT, + dnl instead of duplicating it all over again into config.status, + dnl then we will have config.status run $CONFIG_LT later, so it + dnl needs to know what name is stored there: + [AC_CONFIG_COMMANDS([libtool], + [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], + dnl If the libtool generation code is destined for config.status, + dnl expand the accumulated commands and init code now: + [AC_CONFIG_COMMANDS([libtool], + [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) +])#_LT_CONFIG_COMMANDS + + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], +[ + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +_LT_CONFIG_STATUS_DECLARATIONS +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# Quote evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_quote_varnames); do + case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_dquote_varnames); do + case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Fix-up fallback echo if it was mangled by the above quoting rules. +case \$lt_ECHO in +*'\\\[$]0 --fallback-echo"')dnl " + lt_ECHO=\`\$ECHO "X\$lt_ECHO" | \$Xsed -e 's/\\\\\\\\\\\\\\\[$]0 --fallback-echo"\[$]/\[$]0 --fallback-echo"/'\` + ;; +esac + +_LT_OUTPUT_LIBTOOL_INIT +]) + + +# LT_OUTPUT +# --------- +# This macro allows early generation of the libtool script (before +# AC_OUTPUT is called), incase it is used in configure for compilation +# tests. +AC_DEFUN([LT_OUTPUT], +[: ${CONFIG_LT=./config.lt} +AC_MSG_NOTICE([creating $CONFIG_LT]) +cat >"$CONFIG_LT" <<_LTEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate a libtool stub with the current configuration. + +lt_cl_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_LTEOF + +cat >>"$CONFIG_LT" <<\_LTEOF +AS_SHELL_SANITIZE +_AS_PREPARE + +exec AS_MESSAGE_FD>&1 +exec AS_MESSAGE_LOG_FD>>config.log +{ + echo + AS_BOX([Running $as_me.]) +} >&AS_MESSAGE_LOG_FD + +lt_cl_help="\ +\`$as_me' creates a local libtool stub from the current configuration, +for use in further configure time tests before the real libtool is +generated. + +Usage: $[0] [[OPTIONS]] + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + +Report bugs to ." + +lt_cl_version="\ +m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl +m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) +configured by $[0], generated by m4_PACKAGE_STRING. + +Copyright (C) 2008 Free Software Foundation, Inc. +This config.lt script is free software; the Free Software Foundation +gives unlimited permision to copy, distribute and modify it." + +while test $[#] != 0 +do + case $[1] in + --version | --v* | -V ) + echo "$lt_cl_version"; exit 0 ;; + --help | --h* | -h ) + echo "$lt_cl_help"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --quiet | --q* | --silent | --s* | -q ) + lt_cl_silent=: ;; + + -*) AC_MSG_ERROR([unrecognized option: $[1] +Try \`$[0] --help' for more information.]) ;; + + *) AC_MSG_ERROR([unrecognized argument: $[1] +Try \`$[0] --help' for more information.]) ;; + esac + shift +done + +if $lt_cl_silent; then + exec AS_MESSAGE_FD>/dev/null +fi +_LTEOF + +cat >>"$CONFIG_LT" <<_LTEOF +_LT_OUTPUT_LIBTOOL_COMMANDS_INIT +_LTEOF + +cat >>"$CONFIG_LT" <<\_LTEOF +AC_MSG_NOTICE([creating $ofile]) +_LT_OUTPUT_LIBTOOL_COMMANDS +AS_EXIT(0) +_LTEOF +chmod +x "$CONFIG_LT" + +# configure is writing to config.log, but config.lt does its own redirection, +# appending to config.log, which fails on DOS, as config.log is still kept +# open by configure. Here we exec the FD to /dev/null, effectively closing +# config.log, so it can be properly (re)opened and appended to by config.lt. +if test "$no_create" != yes; then + lt_cl_success=: + test "$silent" = yes && + lt_config_lt_args="$lt_config_lt_args --quiet" + exec AS_MESSAGE_LOG_FD>/dev/null + $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false + exec AS_MESSAGE_LOG_FD>>config.log + $lt_cl_success || AS_EXIT(1) +fi +])# LT_OUTPUT + + +# _LT_CONFIG(TAG) +# --------------- +# If TAG is the built-in tag, create an initial libtool script with a +# default configuration from the untagged config vars. Otherwise add code +# to config.status for appending the configuration named by TAG from the +# matching tagged config vars. +m4_defun([_LT_CONFIG], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_CONFIG_SAVE_COMMANDS([ + m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl + m4_if(_LT_TAG, [C], [ + # See if we are running on zsh, and set the options which allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + + cfgfile="${ofile}T" + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL + +# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +_LT_COPYING +_LT_LIBTOOL_TAGS + +# ### BEGIN LIBTOOL CONFIG +_LT_LIBTOOL_CONFIG_VARS +_LT_LIBTOOL_TAG_VARS +# ### END LIBTOOL CONFIG + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + _LT_PROG_LTMAIN + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + _LT_PROG_XSI_SHELLFNS + + sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" +], +[cat <<_LT_EOF >> "$ofile" + +dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded +dnl in a comment (ie after a #). +# ### BEGIN LIBTOOL TAG CONFIG: $1 +_LT_LIBTOOL_TAG_VARS(_LT_TAG) +# ### END LIBTOOL TAG CONFIG: $1 +_LT_EOF +])dnl /m4_if +], +[m4_if([$1], [], [ + PACKAGE='$PACKAGE' + VERSION='$VERSION' + TIMESTAMP='$TIMESTAMP' + RM='$RM' + ofile='$ofile'], []) +])dnl /_LT_CONFIG_SAVE_COMMANDS +])# _LT_CONFIG + + +# LT_SUPPORTED_TAG(TAG) +# --------------------- +# Trace this macro to discover what tags are supported by the libtool +# --tag option, using: +# autoconf --trace 'LT_SUPPORTED_TAG:$1' +AC_DEFUN([LT_SUPPORTED_TAG], []) + + +# C support is built-in for now +m4_define([_LT_LANG_C_enabled], []) +m4_define([_LT_TAGS], []) + + +# LT_LANG(LANG) +# ------------- +# Enable libtool support for the given language if not already enabled. +AC_DEFUN([LT_LANG], +[AC_BEFORE([$0], [LT_OUTPUT])dnl +m4_case([$1], + [C], [_LT_LANG(C)], + [C++], [_LT_LANG(CXX)], + [Java], [_LT_LANG(GCJ)], + [Fortran 77], [_LT_LANG(F77)], + [Fortran], [_LT_LANG(FC)], + [Windows Resource], [_LT_LANG(RC)], + [m4_ifdef([_LT_LANG_]$1[_CONFIG], + [_LT_LANG($1)], + [m4_fatal([$0: unsupported language: "$1"])])])dnl +])# LT_LANG + + +# _LT_LANG(LANGNAME) +# ------------------ +m4_defun([_LT_LANG], +[m4_ifdef([_LT_LANG_]$1[_enabled], [], + [LT_SUPPORTED_TAG([$1])dnl + m4_append([_LT_TAGS], [$1 ])dnl + m4_define([_LT_LANG_]$1[_enabled], [])dnl + _LT_LANG_$1_CONFIG($1)])dnl +])# _LT_LANG + + +# _LT_LANG_DEFAULT_CONFIG +# ----------------------- +m4_defun([_LT_LANG_DEFAULT_CONFIG], +[AC_PROVIDE_IFELSE([AC_PROG_CXX], + [LT_LANG(CXX)], + [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) + +AC_PROVIDE_IFELSE([AC_PROG_F77], + [LT_LANG(F77)], + [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) + +AC_PROVIDE_IFELSE([AC_PROG_FC], + [LT_LANG(FC)], + [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) + +dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal +dnl pulling things in needlessly. +AC_PROVIDE_IFELSE([AC_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([LT_PROG_GCJ], + [LT_LANG(GCJ)], + [m4_ifdef([AC_PROG_GCJ], + [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([A][M_PROG_GCJ], + [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([LT_PROG_GCJ], + [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) + +AC_PROVIDE_IFELSE([LT_PROG_RC], + [LT_LANG(RC)], + [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) +])# _LT_LANG_DEFAULT_CONFIG + +# Obsolete macros: +AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) +AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) +AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) +AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_CXX], []) +dnl AC_DEFUN([AC_LIBTOOL_F77], []) +dnl AC_DEFUN([AC_LIBTOOL_FC], []) +dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) + + +# _LT_TAG_COMPILER +# ---------------- +m4_defun([_LT_TAG_COMPILER], +[AC_REQUIRE([AC_PROG_CC])dnl + +_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl +_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl +_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl +_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC +])# _LT_TAG_COMPILER + + +# _LT_COMPILER_BOILERPLATE +# ------------------------ +# Check for compiler boilerplate output or warnings with +# the simple compiler test code. +m4_defun([_LT_COMPILER_BOILERPLATE], +[m4_require([_LT_DECL_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* +])# _LT_COMPILER_BOILERPLATE + + +# _LT_LINKER_BOILERPLATE +# ---------------------- +# Check for linker boilerplate output or warnings with +# the simple link test code. +m4_defun([_LT_LINKER_BOILERPLATE], +[m4_require([_LT_DECL_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* +])# _LT_LINKER_BOILERPLATE + +# _LT_REQUIRED_DARWIN_CHECKS +# ------------------------- +m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ + case $host_os in + rhapsody* | darwin*) + AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) + AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) + AC_CHECK_TOOL([LIPO], [lipo], [:]) + AC_CHECK_TOOL([OTOOL], [otool], [:]) + AC_CHECK_TOOL([OTOOL64], [otool64], [:]) + _LT_DECL([], [DSYMUTIL], [1], + [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) + _LT_DECL([], [NMEDIT], [1], + [Tool to change global to local symbols on Mac OS X]) + _LT_DECL([], [LIPO], [1], + [Tool to manipulate fat objects and archives on Mac OS X]) + _LT_DECL([], [OTOOL], [1], + [ldd/readelf like tool for Mach-O binaries on Mac OS X]) + _LT_DECL([], [OTOOL64], [1], + [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) + + AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], + [lt_cv_apple_cc_single_mod=no + if test -z "${LT_MULTI_MODULE}"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&AS_MESSAGE_LOG_FD + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi]) + AC_CACHE_CHECK([for -exported_symbols_list linker flag], + [lt_cv_ld_exported_symbols_list], + [lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [lt_cv_ld_exported_symbols_list=yes], + [lt_cv_ld_exported_symbols_list=no]) + LDFLAGS="$save_LDFLAGS" + ]) + case $host_os in + rhapsody* | darwin1.[[012]]) + _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + darwin*) # darwin 5.x on + # if running on 10.5 or later, the deployment target defaults + # to the OS version, if on x86, and 10.4, the deployment + # target defaults to 10.4. Don't you love it? + case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in + 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + 10.[[012]]*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + 10.*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test "$lt_cv_apple_cc_single_mod" = "yes"; then + _lt_dar_single_mod='$single_module' + fi + if test "$lt_cv_ld_exported_symbols_list" = "yes"; then + _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + if test "$DSYMUTIL" != ":"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac +]) + + +# _LT_DARWIN_LINKER_FEATURES +# -------------------------- +# Checks for linker and compiler features on darwin +m4_defun([_LT_DARWIN_LINKER_FEATURES], +[ + m4_require([_LT_REQUIRED_DARWIN_CHECKS]) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_automatic, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_TAGVAR(whole_archive_flag_spec, $1)='' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=echo + _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + m4_if([$1], [CXX], +[ if test "$lt_cv_apple_cc_single_mod" != "yes"; then + _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" + _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" + fi +],[]) + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi +]) + +# _LT_SYS_MODULE_PATH_AIX +# ----------------------- +# Links a minimal program and checks the executable +# for the system default hardcoded library path. In most cases, +# this is /usr/lib:/lib, but when the MPI compilers are used +# the location of the communication and MPI libs are included too. +# If we don't find anything, use the default library path according +# to the aix ld manual. +m4_defun([_LT_SYS_MODULE_PATH_AIX], +[m4_require([_LT_DECL_SED])dnl +AC_LINK_IFELSE(AC_LANG_PROGRAM,[ +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi],[]) +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi +])# _LT_SYS_MODULE_PATH_AIX + + +# _LT_SHELL_INIT(ARG) +# ------------------- +m4_define([_LT_SHELL_INIT], +[ifdef([AC_DIVERSION_NOTICE], + [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)], + [AC_DIVERT_PUSH(NOTICE)]) +$1 +AC_DIVERT_POP +])# _LT_SHELL_INIT + + +# _LT_PROG_ECHO_BACKSLASH +# ----------------------- +# Add some code to the start of the generated configure script which +# will find an echo command which doesn't interpret backslashes. +m4_defun([_LT_PROG_ECHO_BACKSLASH], +[_LT_SHELL_INIT([ +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} + +case X$lt_ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$lt_ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','` + ;; +esac + +ECHO=${lt_ECHO-echo} +if test "X[$]1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X[$]1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' ; then + # Yippee, $ECHO works! + : +else + # Restart under the correct shell. + exec $SHELL "[$]0" --no-reexec ${1+"[$]@"} +fi + +if test "X[$]1" = X--fallback-echo; then + # used as fallback echo + shift + cat <<_LT_EOF +[$]* +_LT_EOF + exit 0 +fi + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +if test -z "$lt_ECHO"; then + if test "X${echo_test_string+set}" != Xset; then + # find a string as large as possible, as long as the shell can cope with it + for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do + # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... + if { echo_test_string=`eval $cmd`; } 2>/dev/null && + { test "X$echo_test_string" = "X$echo_test_string"; } 2>/dev/null + then + break + fi + done + fi + + if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : + else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for dir in $PATH /usr/ucb; do + IFS="$lt_save_ifs" + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + ECHO="$dir/echo" + break + fi + done + IFS="$lt_save_ifs" + + if test "X$ECHO" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`{ print -r '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ print -r "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + ECHO='print -r' + elif { test -f /bin/ksh || test -f /bin/ksh$ac_exeext; } && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} + else + # Try using printf. + ECHO='printf %s\n' + if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + ECHO="$CONFIG_SHELL [$]0 --fallback-echo" + elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + ECHO="$CONFIG_SHELL [$]0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do + if { test "X$echo_test_string" = "X`eval $cmd`"; } 2>/dev/null + then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "[$]0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} + else + # Oops. We lost completely, so just stick with echo. + ECHO=echo + fi + fi + fi + fi + fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +lt_ECHO=$ECHO +if test "X$lt_ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then + lt_ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo" +fi + +AC_SUBST(lt_ECHO) +]) +_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) +_LT_DECL([], [ECHO], [1], + [An echo program that does not interpret backslashes]) +])# _LT_PROG_ECHO_BACKSLASH + + +# _LT_ENABLE_LOCK +# --------------- +m4_defun([_LT_ENABLE_LOCK], +[AC_ARG_ENABLE([libtool-lock], + [AS_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '[#]line __oline__ "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*|powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_LANG_PUSH(C) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) + AC_LANG_POP]) + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +sparc*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) LD="${LD-ld} -m elf64_sparc" ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks="$enable_libtool_lock" +])# _LT_ENABLE_LOCK + + +# _LT_CMD_OLD_ARCHIVE +# ------------------- +m4_defun([_LT_CMD_OLD_ARCHIVE], +[AC_CHECK_TOOL(AR, ar, false) +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru +_LT_DECL([], [AR], [1], [The archiver]) +_LT_DECL([], [AR_FLAGS], [1]) + +AC_CHECK_TOOL(STRIP, strip, :) +test -z "$STRIP" && STRIP=: +_LT_DECL([], [STRIP], [1], [A symbol stripping program]) + +AC_CHECK_TOOL(RANLIB, ranlib, :) +test -z "$RANLIB" && RANLIB=: +_LT_DECL([], [RANLIB], [1], + [Commands used to install an old-style archive]) + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi +_LT_DECL([], [old_postinstall_cmds], [2]) +_LT_DECL([], [old_postuninstall_cmds], [2]) +_LT_TAGDECL([], [old_archive_cmds], [2], + [Commands used to build an old-style archive]) +])# _LT_CMD_OLD_ARCHIVE + + +# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------------------- +# Check whether the given compiler option works +AC_DEFUN([_LT_COMPILER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$3" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + fi + $RM conftest* +]) + +if test x"[$]$2" = xyes; then + m4_if([$5], , :, [$5]) +else + m4_if([$6], , :, [$6]) +fi +])# _LT_COMPILER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) + + +# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------- +# Check whether the given linker option works +AC_DEFUN([_LT_LINKER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $3" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&AS_MESSAGE_LOG_FD + $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + else + $2=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" +]) + +if test x"[$]$2" = xyes; then + m4_if([$4], , :, [$4]) +else + m4_if([$5], , :, [$5]) +fi +])# _LT_LINKER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) + + +# LT_CMD_MAX_LEN +#--------------- +AC_DEFUN([LT_CMD_MAX_LEN], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +# find the maximum length of command line arguments +AC_MSG_CHECKING([the maximum length of command line arguments]) +AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw* | cegcc*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8 ; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test "X"`$SHELL [$]0 --fallback-echo "X$teststring$teststring" 2>/dev/null` \ + = "XX$teststring$teststring"; } >/dev/null 2>&1 && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + teststring= + # Add a significant safety factor because C++ compilers can tack on + # massive amounts of additional arguments before passing them to the + # linker. It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac +]) +if test -n $lt_cv_sys_max_cmd_len ; then + AC_MSG_RESULT($lt_cv_sys_max_cmd_len) +else + AC_MSG_RESULT(none) +fi +max_cmd_len=$lt_cv_sys_max_cmd_len +_LT_DECL([], [max_cmd_len], [0], + [What is the maximum length of a command?]) +])# LT_CMD_MAX_LEN + +# Old name: +AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) + + +# _LT_HEADER_DLFCN +# ---------------- +m4_defun([_LT_HEADER_DLFCN], +[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl +])# _LT_HEADER_DLFCN + + +# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, +# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) +# ---------------------------------------------------------------- +m4_defun([_LT_TRY_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test "$cross_compiling" = yes; then : + [$4] +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +[#line __oline__ "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +}] +_LT_EOF + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) $1 ;; + x$lt_dlneed_uscore) $2 ;; + x$lt_dlunknown|x*) $3 ;; + esac + else : + # compilation failed + $3 + fi +fi +rm -fr conftest* +])# _LT_TRY_DLOPEN_SELF + + +# LT_SYS_DLOPEN_SELF +# ------------------ +AC_DEFUN([LT_SYS_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32* | cegcc*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ]) + ;; + + *) + AC_CHECK_FUNC([shl_load], + [lt_cv_dlopen="shl_load"], + [AC_CHECK_LIB([dld], [shl_load], + [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"], + [AC_CHECK_FUNC([dlopen], + [lt_cv_dlopen="dlopen"], + [AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], + [AC_CHECK_LIB([svld], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], + [AC_CHECK_LIB([dld], [dld_link], + [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"]) + ]) + ]) + ]) + ]) + ]) + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + AC_CACHE_CHECK([whether a program can dlopen itself], + lt_cv_dlopen_self, [dnl + _LT_TRY_DLOPEN_SELF( + lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, + lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) + ]) + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + AC_CACHE_CHECK([whether a statically linked program can dlopen itself], + lt_cv_dlopen_self_static, [dnl + _LT_TRY_DLOPEN_SELF( + lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, + lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) + ]) + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi +_LT_DECL([dlopen_support], [enable_dlopen], [0], + [Whether dlopen is supported]) +_LT_DECL([dlopen_self], [enable_dlopen_self], [0], + [Whether dlopen of programs is supported]) +_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], + [Whether dlopen of statically linked programs is supported]) +])# LT_SYS_DLOPEN_SELF + +# Old name: +AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) + + +# _LT_COMPILER_C_O([TAGNAME]) +# --------------------------- +# Check to see if options -c and -o are simultaneously supported by compiler. +# This macro does not hard code the compiler like AC_PROG_CC_C_O. +m4_defun([_LT_COMPILER_C_O], +[m4_require([_LT_DECL_SED])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + fi + fi + chmod u+w . 2>&AS_MESSAGE_LOG_FD + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* +]) +_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], + [Does compiler simultaneously support -c and -o options?]) +])# _LT_COMPILER_C_O + + +# _LT_COMPILER_FILE_LOCKS([TAGNAME]) +# ---------------------------------- +# Check to see if we can do hard links to lock some files if needed +m4_defun([_LT_COMPILER_FILE_LOCKS], +[m4_require([_LT_ENABLE_LOCK])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_COMPILER_C_O([$1]) + +hard_links="nottested" +if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + AC_MSG_CHECKING([if we can lock with hard links]) + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + AC_MSG_RESULT([$hard_links]) + if test "$hard_links" = no; then + AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) + need_locks=warn + fi +else + need_locks=no +fi +_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) +])# _LT_COMPILER_FILE_LOCKS + + +# _LT_CHECK_OBJDIR +# ---------------- +m4_defun([_LT_CHECK_OBJDIR], +[AC_CACHE_CHECK([for objdir], [lt_cv_objdir], +[rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null]) +objdir=$lt_cv_objdir +_LT_DECL([], [objdir], [0], + [The name of the directory that contains temporary libtool files])dnl +m4_pattern_allow([LT_OBJDIR])dnl +AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/", + [Define to the sub-directory in which libtool stores uninstalled libraries.]) +])# _LT_CHECK_OBJDIR + + +# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) +# -------------------------------------- +# Check hardcoding attributes. +m4_defun([_LT_LINKER_HARDCODE_LIBPATH], +[AC_MSG_CHECKING([how to hardcode library paths into programs]) +_LT_TAGVAR(hardcode_action, $1)= +if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || + test -n "$_LT_TAGVAR(runpath_var, $1)" || + test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$_LT_TAGVAR(hardcode_direct, $1)" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no && + test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then + # Linking always hardcodes the temporary library directory. + _LT_TAGVAR(hardcode_action, $1)=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + _LT_TAGVAR(hardcode_action, $1)=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + _LT_TAGVAR(hardcode_action, $1)=unsupported +fi +AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) + +if test "$_LT_TAGVAR(hardcode_action, $1)" = relink || + test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi +_LT_TAGDECL([], [hardcode_action], [0], + [How to hardcode a shared library path into an executable]) +])# _LT_LINKER_HARDCODE_LIBPATH + + +# _LT_CMD_STRIPLIB +# ---------------- +m4_defun([_LT_CMD_STRIPLIB], +[m4_require([_LT_DECL_EGREP]) +striplib= +old_striplib= +AC_MSG_CHECKING([whether stripping libraries is possible]) +if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac +fi +_LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) +_LT_DECL([], [striplib], [1]) +])# _LT_CMD_STRIPLIB + + +# _LT_SYS_DYNAMIC_LINKER([TAG]) +# ----------------------------- +# PORTME Fill in your ld.so characteristics +m4_defun([_LT_SYS_DYNAMIC_LINKER], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_OBJDUMP])dnl +m4_require([_LT_DECL_SED])dnl +AC_MSG_CHECKING([dynamic linker characteristics]) +m4_if([$1], + [], [ +if test "$GCC" = yes; then + case $host_os in + darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; + *) lt_awk_arg="/^libraries:/" ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if $ECHO "$lt_search_path_spec" | $GREP ';' >/dev/null ; then + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e 's/;/ /g'` + else + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary. + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path/$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" + else + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`$ECHO $lt_tmp_lt_search_path_spec | awk ' +BEGIN {RS=" "; FS="/|\n";} { + lt_foo=""; + lt_count=0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo="/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[[lt_foo]]++; } + if (lt_freq[[lt_foo]] == 1) { print lt_foo; } +}'` + sys_lib_search_path_spec=`$ECHO $lt_search_path_spec` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi]) +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[[4-9]]*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[[01]] | aix4.[[01]].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[[45]]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' +m4_if([$1], [],[ + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[[123]]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[[01]]* | freebsdelf3.[[01]]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ + freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +interix[[3-9]]*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # Some binutils ld are patched to set DT_RUNPATH + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ + LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], + [shlibpath_overrides_runpath=yes])]) + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[[89]] | openbsd2.[[89]].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +AC_MSG_RESULT([$dynamic_linker]) +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + +_LT_DECL([], [variables_saved_for_relink], [1], + [Variables whose values should be saved in libtool wrapper scripts and + restored at link time]) +_LT_DECL([], [need_lib_prefix], [0], + [Do we need the "lib" prefix for modules?]) +_LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) +_LT_DECL([], [version_type], [0], [Library versioning type]) +_LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) +_LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) +_LT_DECL([], [shlibpath_overrides_runpath], [0], + [Is shlibpath searched before the hard-coded library search path?]) +_LT_DECL([], [libname_spec], [1], [Format of library name prefix]) +_LT_DECL([], [library_names_spec], [1], + [[List of archive names. First name is the real one, the rest are links. + The last name is the one that the linker finds with -lNAME]]) +_LT_DECL([], [soname_spec], [1], + [[The coded name of the library, if different from the real name]]) +_LT_DECL([], [postinstall_cmds], [2], + [Command to use after installation of a shared archive]) +_LT_DECL([], [postuninstall_cmds], [2], + [Command to use after uninstallation of a shared archive]) +_LT_DECL([], [finish_cmds], [2], + [Commands used to finish a libtool library installation in a directory]) +_LT_DECL([], [finish_eval], [1], + [[As "finish_cmds", except a single script fragment to be evaled but + not shown]]) +_LT_DECL([], [hardcode_into_libs], [0], + [Whether we should hardcode library paths into libraries]) +_LT_DECL([], [sys_lib_search_path_spec], [2], + [Compile-time system search path for libraries]) +_LT_DECL([], [sys_lib_dlsearch_path_spec], [2], + [Run-time system search path for libraries]) +])# _LT_SYS_DYNAMIC_LINKER + + +# _LT_PATH_TOOL_PREFIX(TOOL) +# -------------------------- +# find a file program which can recognize shared library +AC_DEFUN([_LT_PATH_TOOL_PREFIX], +[m4_require([_LT_DECL_EGREP])dnl +AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, +[case $MAGIC_CMD in +[[\\/*] | ?:[\\/]*]) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="m4_if([$2], , $PATH, [$2])" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$1; then + lt_cv_path_MAGIC_CMD="$ac_dir/$1" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac]) +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + AC_MSG_RESULT($MAGIC_CMD) +else + AC_MSG_RESULT(no) +fi +_LT_DECL([], [MAGIC_CMD], [0], + [Used to examine libraries when file_magic_cmd begins with "file"])dnl +])# _LT_PATH_TOOL_PREFIX + +# Old name: +AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) + + +# _LT_PATH_MAGIC +# -------------- +# find a file program which can recognize a shared library +m4_defun([_LT_PATH_MAGIC], +[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) + else + MAGIC_CMD=: + fi +fi +])# _LT_PATH_MAGIC + + +# LT_PATH_LD +# ---------- +# find the pathname to the GNU or non-GNU linker +AC_DEFUN([LT_PATH_LD], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl + +AC_ARG_WITH([gnu-ld], + [AS_HELP_STRING([--with-gnu-ld], + [assume the C compiler uses GNU ld @<:@default=no@:>@])], + [test "$withval" = no || with_gnu_ld=yes], + [with_gnu_ld=no])dnl + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by $CC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]]* | ?:[[\\/]]*) + re_direlt='/[[^/]][[^/]]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(lt_cv_path_LD, +[if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'] + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[[3-9]]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +esac +]) +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + +_LT_DECL([], [deplibs_check_method], [1], + [Method to check whether dependent libraries are shared objects]) +_LT_DECL([], [file_magic_cmd], [1], + [Command to use when deplibs_check_method == "file_magic"]) +])# _LT_CHECK_MAGIC_METHOD + + +# LT_PATH_NM +# ---------- +# find the pathname to a BSD- or MS-compatible name lister +AC_DEFUN([LT_PATH_NM], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + : ${lt_cv_path_NM=no} +fi]) +if test "$lt_cv_path_NM" != "no"; then + NM="$lt_cv_path_NM" +else + # Didn't find any BSD compatible name lister, look for dumpbin. + AC_CHECK_TOOLS(DUMPBIN, ["dumpbin -symbols" "link -dump -symbols"], :) + AC_SUBST([DUMPBIN]) + if test "$DUMPBIN" != ":"; then + NM="$DUMPBIN" + fi +fi +test -z "$NM" && NM=nm +AC_SUBST([NM]) +_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl + +AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], + [lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:__oline__: $ac_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:__oline__: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:__oline__: output\"" >&AS_MESSAGE_LOG_FD) + cat conftest.out >&AS_MESSAGE_LOG_FD + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest*]) +])# LT_PATH_NM + +# Old names: +AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) +AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_PROG_NM], []) +dnl AC_DEFUN([AC_PROG_NM], []) + + +# LT_LIB_M +# -------- +# check for math library +AC_DEFUN([LT_LIB_M], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*) + # These system don't have libm, or don't need it + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") + AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, cos, LIBM="-lm") + ;; +esac +AC_SUBST([LIBM]) +])# LT_LIB_M + +# Old name: +AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_CHECK_LIBM], []) + + +# _LT_COMPILER_NO_RTTI([TAGNAME]) +# ------------------------------- +m4_defun([_LT_COMPILER_NO_RTTI], +[m4_require([_LT_TAG_COMPILER])dnl + +_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + +if test "$GCC" = yes; then + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + + _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], + lt_cv_prog_compiler_rtti_exceptions, + [-fno-rtti -fno-exceptions], [], + [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) +fi +_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], + [Compiler flag to turn off builtin functions]) +])# _LT_COMPILER_NO_RTTI + + +# _LT_CMD_GLOBAL_SYMBOLS +# ---------------------- +m4_defun([_LT_CMD_GLOBAL_SYMBOLS], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([LT_PATH_NM])dnl +AC_REQUIRE([LT_PATH_LD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_TAG_COMPILER])dnl + +# Check for command to grab the raw symbol name followed by C symbol from nm. +AC_MSG_CHECKING([command to parse $NM output from $compiler object]) +AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], +[ +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[[BCDEGRST]]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[[BCDT]]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[[ABCDGISTW]]' + ;; +hpux*) + if test "$host_cpu" = ia64; then + symcode='[[ABCDEGRST]]' + fi + ;; +irix* | nonstopux*) + symcode='[[BCDEGRST]]' + ;; +osf*) + symcode='[[BCDEGQRST]]' + ;; +solaris*) + symcode='[[BDRT]]' + ;; +sco3.2v5*) + symcode='[[DT]]' + ;; +sysv4.2uw2*) + symcode='[[DT]]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[[ABDT]]' + ;; +sysv4) + symcode='[[DFNSTU]]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[[ABCDGIRSTW]]' ;; +esac + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'" +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'" + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# Try without a prefix underscore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function + # and D for any global variable. + # Also find C++ and __fastcall symbols from MSVC++, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK ['"\ +" {last_section=section; section=\$ 3};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ +" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ +" s[1]~/^[@?]/{print s[1], s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx]" + else + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if AC_TRY_EVAL(ac_compile); then + # Now try to grab the symbols. + nlist=conftest.nm + if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if $GREP ' nm_test_var$' "$nlist" >/dev/null; then + if $GREP ' nm_test_func$' "$nlist" >/dev/null; then + cat <<_LT_EOF > conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[[]] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_save_LIBS="$LIBS" + lt_save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS="$lt_save_LIBS" + CFLAGS="$lt_save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD + fi + else + echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done +]) +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + AC_MSG_RESULT(failed) +else + AC_MSG_RESULT(ok) +fi + +_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], + [Take the output of nm and produce a listing of raw symbols and C names]) +_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], + [Transform the output of nm in a proper C declaration]) +_LT_DECL([global_symbol_to_c_name_address], + [lt_cv_sys_global_symbol_to_c_name_address], [1], + [Transform the output of nm in a C name address pair]) +_LT_DECL([global_symbol_to_c_name_address_lib_prefix], + [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], + [Transform the output of nm in a C name address pair when lib prefix is needed]) +]) # _LT_CMD_GLOBAL_SYMBOLS + + +# _LT_COMPILER_PIC([TAGNAME]) +# --------------------------- +m4_defun([_LT_COMPILER_PIC], +[m4_require([_LT_TAG_COMPILER])dnl +_LT_TAGVAR(lt_prog_compiler_wl, $1)= +_LT_TAGVAR(lt_prog_compiler_pic, $1)= +_LT_TAGVAR(lt_prog_compiler_static, $1)= + +AC_MSG_CHECKING([for $compiler option to produce PIC]) +m4_if([$1], [CXX], [ + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + case $host_os in + aix[[4-9]]*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + dgux*) + case $cc_basename in + ec++*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + if test "$host_cpu" != ia64; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + fi + ;; + aCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux* | k*bsd*-gnu) + case $cc_basename in + KCC*) + # KAI C++ Compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + ecpc* ) + # old Intel C++ for x86_64 which still supported -KPIC. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + icpc* ) + # Intel C++, used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xlc* | xlC*) + # IBM XL 8.0 on PPC + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + esac + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd* | netbsdelf*-gnu) + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + cxx*) + # Digital/Compaq C++ + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + lcc*) + # Lucid + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + *) + ;; + esac + ;; + vxworks*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +], +[ + if test "$GCC" = yes; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + enable_shared=no + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + + hpux9* | hpux10* | hpux11*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC (with -KPIC) is the default. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + linux* | k*bsd*-gnu) + case $cc_basename in + # old Intel for x86_64 which still supported -KPIC. + ecc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' + _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' + ;; + pgcc* | pgf77* | pgf90* | pgf95*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + ccc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All Alpha code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xl*) + # IBM XL C 8.0/Fortran 10.1 on PPC + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + ;; + *Sun\ F*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='' + ;; + esac + ;; + esac + ;; + + newsos6) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + osf3* | osf4* | osf5*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All OSF/1 code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + rdos*) + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + solaris*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + case $cc_basename in + f77* | f90* | f95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; + *) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; + esac + ;; + + sunos4*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + unicos*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + + uts4*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +]) +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" + ;; +esac +AC_MSG_RESULT([$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) +_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], + [How to pass a linker flag through the compiler]) + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then + _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], + [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], + [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], + [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in + "" | " "*) ;; + *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; + esac], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) +fi +_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], + [Additional compiler flags for building library objects]) + +# +# Check to make sure the static flag actually works. +# +wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" +_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], + _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), + $lt_tmp_static_flag, + [], + [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) +_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], + [Compiler flag to prevent dynamic linking]) +])# _LT_COMPILER_PIC + + +# _LT_LINKER_SHLIBS([TAGNAME]) +# ---------------------------- +# See if the linker supports building shared libraries. +m4_defun([_LT_LINKER_SHLIBS], +[AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +m4_if([$1], [CXX], [ + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + case $host_os in + aix[[4-9]]*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" + ;; + cygwin* | mingw* | cegcc*) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;/^.*[[ ]]__nm__/s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' + ;; + linux* | k*bsd*-gnu) + _LT_TAGVAR(link_all_deplibs, $1)=no + ;; + *) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] +], [ + runpath_var= + _LT_TAGVAR(allow_undefined_flag, $1)= + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(archive_cmds, $1)= + _LT_TAGVAR(archive_expsym_cmds, $1)= + _LT_TAGVAR(compiler_needs_object, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(hardcode_automatic, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= + _LT_TAGVAR(hardcode_libdir_separator, $1)= + _LT_TAGVAR(hardcode_minus_L, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_TAGVAR(inherit_rpath, $1)=no + _LT_TAGVAR(link_all_deplibs, $1)=unknown + _LT_TAGVAR(module_cmds, $1)= + _LT_TAGVAR(module_expsym_cmds, $1)= + _LT_TAGVAR(old_archive_from_new_cmds, $1)= + _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= + _LT_TAGVAR(thread_safe_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + _LT_TAGVAR(include_expsyms, $1)= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. +dnl Note also adjust exclude_expsyms for C++ above. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + _LT_TAGVAR(ld_shlibs, $1)=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + supports_anon_versioning=no + case `$LD -v 2>&1` in + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[[3-9]]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | tpf* | k*bsd*-gnu) + tmp_diet=no + if test "$host_os" = linux-dietlibc; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test "$tmp_diet" = no + then + tmp_addflag= + tmp_sharedflag='-shared' + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + lf95*) # Lahey Fortran 8.1 + _LT_TAGVAR(whole_archive_flag_spec, $1)= + tmp_sharedflag='--shared' ;; + xl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + + case $cc_basename in + xlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir' + _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + sunos4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + + if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then + runpath_var= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + _LT_TAGVAR(hardcode_direct, $1)=unsupported + fi + ;; + + aix[[4-9]]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' + + if test "$GCC" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + _LT_TAGVAR(link_all_deplibs, $1)=no + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared libraries. + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + bsdi[[45]]*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `$ECHO "X$deplibs" | $Xsed -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + # FIXME: Should let the user specify the lib program. + _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' + _LT_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + dgux*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + freebsd1*) + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + hpux9*) + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" + AC_LINK_IFELSE(int foo(void) {}, + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' + ) + LDFLAGS="$save_LDFLAGS" + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + newsos6) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *nto* | *qnx*) + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + else + case $host_os in + openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + ;; + esac + fi + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + os2*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$ECHO DATA >> $output_objdir/$libname.def~$ECHO " SINGLE NONSHARED" >> $output_objdir/$libname.def~$ECHO EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' + + # Both c and cxx compiler support -rpath directly + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + solaris*) + _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' + if test "$GCC" = yes; then + wlarc='${wl}' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + wlarc='' + _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + ;; + *) + wlarc='${wl}' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. GCC discards it without `$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test "$GCC" = yes; then + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + fi + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4) + case $host_vendor in + sni) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' + _LT_TAGVAR(hardcode_direct, $1)=no + ;; + motorola) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4.3*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + _LT_TAGVAR(ld_shlibs, $1)=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + if test x$host_vendor = xsni; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym' + ;; + esac + fi + fi +]) +AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) +test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld + +_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl +_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl +_LT_DECL([], [extract_expsyms_cmds], [2], + [The commands to extract the exported symbol list from a shared archive]) + +# +# Do we need to explicitly link libc? +# +case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in +x|xyes) + # Assume -lc should be added + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $_LT_TAGVAR(archive_cmds, $1) in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + AC_MSG_CHECKING([whether -lc should be explicitly linked in]) + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if AC_TRY_EVAL(ac_compile) 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) + pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) + _LT_TAGVAR(allow_undefined_flag, $1)= + if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) + then + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + else + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + fi + _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + AC_MSG_RESULT([$_LT_TAGVAR(archive_cmds_need_lc, $1)]) + ;; + esac + fi + ;; +esac + +_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], + [Whether or not to add -lc for building shared libraries]) +_LT_TAGDECL([allow_libtool_libs_with_static_runtimes], + [enable_shared_with_static_runtimes], [0], + [Whether or not to disallow shared libs when runtime libs are static]) +_LT_TAGDECL([], [export_dynamic_flag_spec], [1], + [Compiler flag to allow reflexive dlopens]) +_LT_TAGDECL([], [whole_archive_flag_spec], [1], + [Compiler flag to generate shared objects directly from archives]) +_LT_TAGDECL([], [compiler_needs_object], [1], + [Whether the compiler copes with passing no objects directly]) +_LT_TAGDECL([], [old_archive_from_new_cmds], [2], + [Create an old-style archive from a shared archive]) +_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], + [Create a temporary old-style archive to link instead of a shared archive]) +_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) +_LT_TAGDECL([], [archive_expsym_cmds], [2]) +_LT_TAGDECL([], [module_cmds], [2], + [Commands used to build a loadable module if different from building + a shared archive.]) +_LT_TAGDECL([], [module_expsym_cmds], [2]) +_LT_TAGDECL([], [with_gnu_ld], [1], + [Whether we are building with GNU ld or not]) +_LT_TAGDECL([], [allow_undefined_flag], [1], + [Flag that allows shared libraries with undefined symbols to be built]) +_LT_TAGDECL([], [no_undefined_flag], [1], + [Flag that enforces no undefined symbols]) +_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], + [Flag to hardcode $libdir into a binary during linking. + This must work even if $libdir does not exist]) +_LT_TAGDECL([], [hardcode_libdir_flag_spec_ld], [1], + [[If ld is used when linking, flag to hardcode $libdir into a binary + during linking. This must work even if $libdir does not exist]]) +_LT_TAGDECL([], [hardcode_libdir_separator], [1], + [Whether we need a single "-rpath" flag with a separated argument]) +_LT_TAGDECL([], [hardcode_direct], [0], + [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes + DIR into the resulting binary]) +_LT_TAGDECL([], [hardcode_direct_absolute], [0], + [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes + DIR into the resulting binary and the resulting library dependency is + "absolute", i.e impossible to change by setting ${shlibpath_var} if the + library is relocated]) +_LT_TAGDECL([], [hardcode_minus_L], [0], + [Set to "yes" if using the -LDIR flag during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_shlibpath_var], [0], + [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_automatic], [0], + [Set to "yes" if building a shared library automatically hardcodes DIR + into the library and all subsequent libraries and executables linked + against it]) +_LT_TAGDECL([], [inherit_rpath], [0], + [Set to yes if linker adds runtime paths of dependent libraries + to runtime path list]) +_LT_TAGDECL([], [link_all_deplibs], [0], + [Whether libtool must link a program against all its dependency libraries]) +_LT_TAGDECL([], [fix_srcfile_path], [1], + [Fix the shell variable $srcfile for the compiler]) +_LT_TAGDECL([], [always_export_symbols], [0], + [Set to "yes" if exported symbols are required]) +_LT_TAGDECL([], [export_symbols_cmds], [2], + [The commands to list exported symbols]) +_LT_TAGDECL([], [exclude_expsyms], [1], + [Symbols that should not be listed in the preloaded symbols]) +_LT_TAGDECL([], [include_expsyms], [1], + [Symbols that must always be exported]) +_LT_TAGDECL([], [prelink_cmds], [2], + [Commands necessary for linking programs (against libraries) with templates]) +_LT_TAGDECL([], [file_list_spec], [1], + [Specify filename containing input files]) +dnl FIXME: Not yet implemented +dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], +dnl [Compiler flag to generate thread safe objects]) +])# _LT_LINKER_SHLIBS + + +# _LT_LANG_C_CONFIG([TAG]) +# ------------------------ +# Ensure that the configuration variables for a C compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to `libtool'. +m4_defun([_LT_LANG_C_CONFIG], +[m4_require([_LT_DECL_EGREP])dnl +lt_save_CC="$CC" +AC_LANG_PUSH(C) + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + +_LT_TAG_COMPILER +# Save the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$CC + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + LT_SYS_DLOPEN_SELF + _LT_CMD_STRIPLIB + + # Report which library types will actually be built + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_CONFIG($1) +fi +AC_LANG_POP +CC="$lt_save_CC" +])# _LT_LANG_C_CONFIG + + +# _LT_PROG_CXX +# ------------ +# Since AC_PROG_CXX is broken, in that it returns g++ if there is no c++ +# compiler, we have our own version here. +m4_defun([_LT_PROG_CXX], +[ +pushdef([AC_MSG_ERROR], [_lt_caught_CXX_error=yes]) +AC_PROG_CXX +if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + AC_PROG_CXXCPP +else + _lt_caught_CXX_error=yes +fi +popdef([AC_MSG_ERROR]) +])# _LT_PROG_CXX + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([_LT_PROG_CXX], []) + + +# _LT_LANG_CXX_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a C++ compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to `libtool'. +m4_defun([_LT_LANG_CXX_CONFIG], +[AC_REQUIRE([_LT_PROG_CXX])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl + +AC_LANG_PUSH(C++) +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(compiler_needs_object, $1)=no +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the CXX compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_caught_CXX_error" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="int some_variable = 0;" + + # Code to be used in simple link tests + lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_LD=$LD + lt_save_GCC=$GCC + GCC=$GXX + lt_save_with_gnu_ld=$with_gnu_ld + lt_save_path_LD=$lt_cv_path_LD + if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx + else + $as_unset lt_cv_prog_gnu_ld + fi + if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX + else + $as_unset lt_cv_path_LD + fi + test -z "${LDCXX+set}" || LD=$LDCXX + CC=${CXX-"c++"} + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + # We don't want -fno-exception when compiling C++ code, so set the + # no_builtin_flag separately + if test "$GXX" = yes; then + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + else + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + fi + + if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + LT_PATH_LD + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | + $GREP 'no-whole-archive' > /dev/null; then + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + + else + GXX=no + with_gnu_ld=no + wlarc= + fi + + # PORTME: fill in a description of your system's C++ link characteristics + AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) + _LT_TAGVAR(ld_shlibs, $1)=yes + case $host_os in + aix3*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aix[[4-9]]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' + + if test "$GXX" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to + # export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty + # executable. + _LT_SYS_MODULE_PATH_AIX + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared + # libraries. + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + freebsd[[12]]*) + # C++ shared libraries reported to be fairly broken before + # switch to ELF + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + freebsd-elf*) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + + freebsd* | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + gnu*) + ;; + + hpux9*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + *) + if test "$GXX" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` -o $lib' + fi + fi + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + esac + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + ;; + + linux* | k*bsd*-gnu) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc* | ecpc* ) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + case `$CC -V` in + *pgCC\ [[1-5]]* | *pgcpp\ [[1-5]]*) + _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ + compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"' + _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ + $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~ + $RANLIB $oldlib' + _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + *) # Version 6 will use weak symbols + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + ;; + cxx*) + # Compaq C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + xl*) + # IBM XL 8.0 on PPC, with GNU ld + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + + # Not sure whether something based on + # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 + # would be better. + output_verbose_link_cmd='echo' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + esac + ;; + esac + ;; + + lynxos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + m88k*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + + *nto* | *qnx*) + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + openbsd2*) + # C++ shared libraries are fairly broken + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + fi + output_verbose_link_cmd=echo + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + case $host in + osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; + *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; + esac + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + cxx*) + case $host in + osf3*) + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && $ECHO "X${wl}-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + ;; + *) + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~ + $RM $lib.exp' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + case $host in + osf3*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + psos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(archive_cmds_need_lc,$1)=yes + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. + # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + + output_verbose_link_cmd='echo' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' + if $CC --version | $GREP -v '^2\.7' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + fi + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + ;; + esac + fi + ;; + esac + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + vxworks*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) + test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + + _LT_TAGVAR(GCC, $1)="$GXX" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + CC=$lt_save_CC + LDCXX=$LD + LD=$lt_save_LD + GCC=$lt_save_GCC + with_gnu_ld=$lt_save_with_gnu_ld + lt_cv_path_LDCXX=$lt_cv_path_LD + lt_cv_path_LD=$lt_save_path_LD + lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld + lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +fi # test "$_lt_caught_CXX_error" != yes + +AC_LANG_POP +])# _LT_LANG_CXX_CONFIG + + +# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) +# --------------------------------- +# Figure out "hidden" library dependencies from verbose +# compiler output when linking a shared library. +# Parse the compiler output and extract the necessary +# objects, libraries and library flags. +m4_defun([_LT_SYS_HIDDEN_LIBDEPS], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +# Dependencies to place before and after the object being linked: +_LT_TAGVAR(predep_objects, $1)= +_LT_TAGVAR(postdep_objects, $1)= +_LT_TAGVAR(predeps, $1)= +_LT_TAGVAR(postdeps, $1)= +_LT_TAGVAR(compiler_lib_search_path, $1)= + +dnl we can't use the lt_simple_compile_test_code here, +dnl because it contains code intended for an executable, +dnl not a library. It's possible we should let each +dnl tag define a new lt_????_link_test_code variable, +dnl but it's only used here... +m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF +int a; +void foo (void) { a = 0; } +_LT_EOF +], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF +class Foo +{ +public: + Foo (void) { a = 0; } +private: + int a; +}; +_LT_EOF +], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer*4 a + a=0 + return + end +_LT_EOF +], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer a + a=0 + return + end +_LT_EOF +], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF +public class foo { + private int a; + public void bar (void) { + a = 0; + } +}; +_LT_EOF +]) +dnl Parse the compiler output and extract the necessary +dnl objects, libraries and library flags. +if AC_TRY_EVAL(ac_compile); then + # Parse the compiler output and extract the necessary + # objects, libraries and library flags. + + # Sentinel used to keep track of whether or not we are before + # the conftest object file. + pre_test_object_deps_done=no + + for p in `eval "$output_verbose_link_cmd"`; do + case $p in + + -L* | -R* | -l*) + # Some compilers place space between "-{L,R}" and the path. + # Remove the space. + if test $p = "-L" || + test $p = "-R"; then + prev=$p + continue + else + prev= + fi + + if test "$pre_test_object_deps_done" = no; then + case $p in + -L* | -R*) + # Internal compiler library paths should come after those + # provided the user. The postdeps already come after the + # user supplied libs so there is no need to process them. + if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then + _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}" + else + _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}" + fi + ;; + # The "-l" case would never come before the object being + # linked, so don't bother handling this case. + esac + else + if test -z "$_LT_TAGVAR(postdeps, $1)"; then + _LT_TAGVAR(postdeps, $1)="${prev}${p}" + else + _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}" + fi + fi + ;; + + *.$objext) + # This assumes that the test object file only shows up + # once in the compiler output. + if test "$p" = "conftest.$objext"; then + pre_test_object_deps_done=yes + continue + fi + + if test "$pre_test_object_deps_done" = no; then + if test -z "$_LT_TAGVAR(predep_objects, $1)"; then + _LT_TAGVAR(predep_objects, $1)="$p" + else + _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" + fi + else + if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then + _LT_TAGVAR(postdep_objects, $1)="$p" + else + _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" + fi + fi + ;; + + *) ;; # Ignore the rest. + + esac + done + + # Clean up. + rm -f a.out a.exe +else + echo "libtool.m4: error: problem compiling $1 test program" +fi + +$RM -f confest.$objext + +# PORTME: override above test on systems where it is broken +m4_if([$1], [CXX], +[case $host_os in +interix[[3-9]]*) + # Interix 3.5 installs completely hosed .la files for C++, so rather than + # hack all around it, let's just trust "g++" to DTRT. + _LT_TAGVAR(predep_objects,$1)= + _LT_TAGVAR(postdep_objects,$1)= + _LT_TAGVAR(postdeps,$1)= + ;; + +linux*) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + if test "$solaris_use_stlport4" != yes; then + _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' + fi + ;; + esac + ;; + +solaris*) + case $cc_basename in + CC*) + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + # Adding this requires a known-good setup of shared libraries for + # Sun compiler versions before 5.6, else PIC objects from an old + # archive will be linked into the output, leading to subtle bugs. + if test "$solaris_use_stlport4" != yes; then + _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' + fi + ;; + esac + ;; +esac +]) + +case " $_LT_TAGVAR(postdeps, $1) " in +*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; +esac + _LT_TAGVAR(compiler_lib_search_dirs, $1)= +if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then + _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` +fi +_LT_TAGDECL([], [compiler_lib_search_dirs], [1], + [The directories searched by this compiler when creating a shared library]) +_LT_TAGDECL([], [predep_objects], [1], + [Dependencies to place before and after the objects being linked to + create a shared library]) +_LT_TAGDECL([], [postdep_objects], [1]) +_LT_TAGDECL([], [predeps], [1]) +_LT_TAGDECL([], [postdeps], [1]) +_LT_TAGDECL([], [compiler_lib_search_path], [1], + [The library search path used internally by the compiler when linking + a shared library]) +])# _LT_SYS_HIDDEN_LIBDEPS + + +# _LT_PROG_F77 +# ------------ +# Since AC_PROG_F77 is broken, in that it returns the empty string +# if there is no fortran compiler, we have our own version here. +m4_defun([_LT_PROG_F77], +[ +pushdef([AC_MSG_ERROR], [_lt_disable_F77=yes]) +AC_PROG_F77 +if test -z "$F77" || test "X$F77" = "Xno"; then + _lt_disable_F77=yes +fi +popdef([AC_MSG_ERROR]) +])# _LT_PROG_F77 + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([_LT_PROG_F77], []) + + +# _LT_LANG_F77_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a Fortran 77 compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_F77_CONFIG], +[AC_REQUIRE([_LT_PROG_F77])dnl +AC_LANG_PUSH(Fortran 77) + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for f77 test sources. +ac_ext=f + +# Object file extension for compiled f77 test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the F77 compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_disable_F77" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="\ + subroutine t + return + end +" + + # Code to be used in simple link tests + lt_simple_link_test_code="\ + program t + end +" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC="$CC" + lt_save_GCC=$GCC + CC=${F77-"f77"} + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + GCC=$G77 + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)="$G77" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC="$lt_save_CC" +fi # test "$_lt_disable_F77" != yes + +AC_LANG_POP +])# _LT_LANG_F77_CONFIG + + +# _LT_PROG_FC +# ----------- +# Since AC_PROG_FC is broken, in that it returns the empty string +# if there is no fortran compiler, we have our own version here. +m4_defun([_LT_PROG_FC], +[ +pushdef([AC_MSG_ERROR], [_lt_disable_FC=yes]) +AC_PROG_FC +if test -z "$FC" || test "X$FC" = "Xno"; then + _lt_disable_FC=yes +fi +popdef([AC_MSG_ERROR]) +])# _LT_PROG_FC + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([_LT_PROG_FC], []) + + +# _LT_LANG_FC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for a Fortran compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_FC_CONFIG], +[AC_REQUIRE([_LT_PROG_FC])dnl +AC_LANG_PUSH(Fortran) + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for fc test sources. +ac_ext=${ac_fc_srcext-f} + +# Object file extension for compiled fc test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the FC compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_disable_FC" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="\ + subroutine t + return + end +" + + # Code to be used in simple link tests + lt_simple_link_test_code="\ + program t + end +" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC="$CC" + lt_save_GCC=$GCC + CC=${FC-"f95"} + compiler=$CC + GCC=$ac_cv_fc_compiler_gnu + + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC="$lt_save_CC" +fi # test "$_lt_disable_FC" != yes + +AC_LANG_POP +])# _LT_LANG_FC_CONFIG + + +# _LT_LANG_GCJ_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for the GNU Java Compiler compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_GCJ_CONFIG], +[AC_REQUIRE([LT_PROG_GCJ])dnl +AC_LANG_SAVE + +# Source file extension for Java test sources. +ac_ext=java + +# Object file extension for compiled Java test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="class foo {}" + +# Code to be used in simple link tests +lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +lt_save_GCC=$GCC +GCC=yes +CC=${GCJ-"gcj"} +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_TAGVAR(LD, $1)="$LD" +_LT_CC_BASENAME([$compiler]) + +# GCJ did not exist at the time GCC didn't implicitly link libc in. +_LT_TAGVAR(archive_cmds_need_lc, $1)=no + +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) +fi + +AC_LANG_RESTORE + +GCC=$lt_save_GCC +CC="$lt_save_CC" +])# _LT_LANG_GCJ_CONFIG + + +# _LT_LANG_RC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for the Windows resource compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_RC_CONFIG], +[AC_REQUIRE([LT_PROG_RC])dnl +AC_LANG_SAVE + +# Source file extension for RC test sources. +ac_ext=rc + +# Object file extension for compiled RC test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' + +# Code to be used in simple link tests +lt_simple_link_test_code="$lt_simple_compile_test_code" + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +lt_save_GCC=$GCC +GCC= +CC=${RC-"windres"} +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_CC_BASENAME([$compiler]) +_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + +if test -n "$compiler"; then + : + _LT_CONFIG($1) +fi + +GCC=$lt_save_GCC +AC_LANG_RESTORE +CC="$lt_save_CC" +])# _LT_LANG_RC_CONFIG + + +# LT_PROG_GCJ +# ----------- +AC_DEFUN([LT_PROG_GCJ], +[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], + [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], + [AC_CHECK_TOOL(GCJ, gcj,) + test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" + AC_SUBST(GCJFLAGS)])])[]dnl +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_GCJ], []) + + +# LT_PROG_RC +# ---------- +AC_DEFUN([LT_PROG_RC], +[AC_CHECK_TOOL(RC, windres,) +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_RC], []) + + +# _LT_DECL_EGREP +# -------------- +# If we don't have a new enough Autoconf to choose the best grep +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_EGREP], +[AC_REQUIRE([AC_PROG_EGREP])dnl +AC_REQUIRE([AC_PROG_FGREP])dnl +test -z "$GREP" && GREP=grep +_LT_DECL([], [GREP], [1], [A grep program that handles long lines]) +_LT_DECL([], [EGREP], [1], [An ERE matcher]) +_LT_DECL([], [FGREP], [1], [A literal string matcher]) +dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too +AC_SUBST([GREP]) +]) + + +# _LT_DECL_OBJDUMP +# -------------- +# If we don't have a new enough Autoconf to choose the best objdump +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_OBJDUMP], +[AC_CHECK_TOOL(OBJDUMP, objdump, false) +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) +AC_SUBST([OBJDUMP]) +]) + + +# _LT_DECL_SED +# ------------ +# Check for a fully-functional sed program, that truncates +# as few characters as possible. Prefer GNU sed if found. +m4_defun([_LT_DECL_SED], +[AC_PROG_SED +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" +_LT_DECL([], [SED], [1], [A sed program that does not truncate output]) +_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], + [Sed that helps us avoid accidentally triggering echo(1) options like -n]) +])# _LT_DECL_SED + +m4_ifndef([AC_PROG_SED], [ +############################################################ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_SED. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +############################################################ + +m4_defun([AC_PROG_SED], +[AC_MSG_CHECKING([for a sed that does not truncate output]) +AC_CACHE_VAL(lt_cv_path_SED, +[# Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for lt_ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then + lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" + fi + done + done +done +IFS=$as_save_IFS +lt_ac_max=0 +lt_ac_count=0 +# Add /usr/xpg4/bin/sed as it is typically found on Solaris +# along with /bin/sed that truncates output. +for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do + test ! -f $lt_ac_sed && continue + cat /dev/null > conftest.in + lt_ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >conftest.in + # Check for GNU sed and select it if it is found. + if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then + lt_cv_path_SED=$lt_ac_sed + break + fi + while true; do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo >>conftest.nl + $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break + cmp -s conftest.out conftest.nl || break + # 10000 chars as input seems more than enough + test $lt_ac_count -gt 10 && break + lt_ac_count=`expr $lt_ac_count + 1` + if test $lt_ac_count -gt $lt_ac_max; then + lt_ac_max=$lt_ac_count + lt_cv_path_SED=$lt_ac_sed + fi + done +done +]) +SED=$lt_cv_path_SED +AC_SUBST([SED]) +AC_MSG_RESULT([$SED]) +])#AC_PROG_SED +])#m4_ifndef + +# Old name: +AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_SED], []) + + +# _LT_CHECK_SHELL_FEATURES +# ------------------------ +# Find out whether the shell is Bourne or XSI compatible, +# or has some other useful features. +m4_defun([_LT_CHECK_SHELL_FEATURES], +[AC_MSG_CHECKING([whether the shell understands some XSI constructs]) +# Try some XSI features +xsi_shell=no +( _lt_dummy="a/b/c" + test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \ + = c,a/b,, \ + && eval 'test $(( 1 + 1 )) -eq 2 \ + && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ + && xsi_shell=yes +AC_MSG_RESULT([$xsi_shell]) +_LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell']) + +AC_MSG_CHECKING([whether the shell understands "+="]) +lt_shell_append=no +( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \ + >/dev/null 2>&1 \ + && lt_shell_append=yes +AC_MSG_RESULT([$lt_shell_append]) +_LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append']) + +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi +_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl + +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac +_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl +_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl +])# _LT_CHECK_SHELL_FEATURES + + +# _LT_PROG_XSI_SHELLFNS +# --------------------- +# Bourne and XSI compatible variants of some useful shell functions. +m4_defun([_LT_PROG_XSI_SHELLFNS], +[case $xsi_shell in + yes) + cat << \_LT_EOF >> "$cfgfile" + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac +} + +# func_basename file +func_basename () +{ + func_basename_result="${1##*/}" +} + +# func_dirname_and_basename file append nondir_replacement +# perform func_basename and func_dirname in a single function +# call: +# dirname: Compute the dirname of FILE. If nonempty, +# add APPEND to the result, otherwise set result +# to NONDIR_REPLACEMENT. +# value returned in "$func_dirname_result" +# basename: Compute filename of FILE. +# value retuned in "$func_basename_result" +# Implementation must be kept synchronized with func_dirname +# and func_basename. For efficiency, we do not delegate to +# those functions but instead duplicate the functionality here. +func_dirname_and_basename () +{ + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac + func_basename_result="${1##*/}" +} + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +func_stripname () +{ + # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are + # positional parameters, so assign one to ordinary parameter first. + func_stripname_result=${3} + func_stripname_result=${func_stripname_result#"${1}"} + func_stripname_result=${func_stripname_result%"${2}"} +} + +# func_opt_split +func_opt_split () +{ + func_opt_split_opt=${1%%=*} + func_opt_split_arg=${1#*=} +} + +# func_lo2o object +func_lo2o () +{ + case ${1} in + *.lo) func_lo2o_result=${1%.lo}.${objext} ;; + *) func_lo2o_result=${1} ;; + esac +} + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=${1%.*}.lo +} + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=$(( $[*] )) +} + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=${#1} +} + +_LT_EOF + ;; + *) # Bourne compatible functions. + cat << \_LT_EOF >> "$cfgfile" + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + # Extract subdirectory from the argument. + func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi +} + +# func_basename file +func_basename () +{ + func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"` +} + +dnl func_dirname_and_basename +dnl A portable version of this function is already defined in general.m4sh +dnl so there is no need for it here. + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# func_strip_suffix prefix name +func_stripname () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "X${3}" \ + | $Xsed -e "s%^${1}%%" -e "s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "X${3}" \ + | $Xsed -e "s%^${1}%%" -e "s%${2}\$%%"`;; + esac +} + +# sed scripts: +my_sed_long_opt='1s/^\(-[[^=]]*\)=.*/\1/;q' +my_sed_long_arg='1s/^-[[^=]]*=//' + +# func_opt_split +func_opt_split () +{ + func_opt_split_opt=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_opt"` + func_opt_split_arg=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_arg"` +} + +# func_lo2o object +func_lo2o () +{ + func_lo2o_result=`$ECHO "X${1}" | $Xsed -e "$lo2o"` +} + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=`$ECHO "X${1}" | $Xsed -e 's/\.[[^.]]*$/.lo/'` +} + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=`expr "$[@]"` +} + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=`expr "$[1]" : ".*" 2>/dev/null || echo $max_cmd_len` +} + +_LT_EOF +esac + +case $lt_shell_append in + yes) + cat << \_LT_EOF >> "$cfgfile" + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "$[1]+=\$[2]" +} +_LT_EOF + ;; + *) + cat << \_LT_EOF >> "$cfgfile" + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "$[1]=\$$[1]\$[2]" +} + +_LT_EOF + ;; + esac +]) diff --git a/apache2/build/ltmain.sh b/apache2/build/ltmain.sh new file mode 100755 index 0000000..b612e9a --- /dev/null +++ b/apache2/build/ltmain.sh @@ -0,0 +1,8412 @@ +# Generated from ltmain.m4sh. + +# ltmain.sh (GNU libtool) 2.2.6 +# Written by Gordon Matzigkeit , 1996 + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007 2008 Free Software Foundation, Inc. +# This is free software; see the source for copying conditions. There is NO +# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +# GNU Libtool is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, +# or obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# Usage: $progname [OPTION]... [MODE-ARG]... +# +# Provide generalized library-building support services. +# +# --config show all configuration variables +# --debug enable verbose shell tracing +# -n, --dry-run display commands without modifying any files +# --features display basic configuration information and exit +# --mode=MODE use operation mode MODE +# --preserve-dup-deps don't remove duplicate dependency libraries +# --quiet, --silent don't print informational messages +# --tag=TAG use configuration variables from tag TAG +# -v, --verbose print informational messages (default) +# --version print version information +# -h, --help print short or long help message +# +# MODE must be one of the following: +# +# clean remove files from the build directory +# compile compile a source file into a libtool object +# execute automatically set library path, then run a program +# finish complete the installation of libtool libraries +# install install libraries or executables +# link create a library or an executable +# uninstall remove libraries from an installed directory +# +# MODE-ARGS vary depending on the MODE. +# Try `$progname --help --mode=MODE' for a more detailed description of MODE. +# +# When reporting a bug, please describe a test case to reproduce it and +# include the following information: +# +# host-triplet: $host +# shell: $SHELL +# compiler: $LTCC +# compiler flags: $LTCFLAGS +# linker: $LD (gnu? $with_gnu_ld) +# $progname: (GNU libtool) 2.2.6 Debian-2.2.6a-1ubuntu1 +# automake: $automake_version +# autoconf: $autoconf_version +# +# Report bugs to . + +PROGRAM=ltmain.sh +PACKAGE=libtool +VERSION="2.2.6 Debian-2.2.6a-1ubuntu1" +TIMESTAMP="" +package_revision=1.3012 + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# NLS nuisances: We save the old values to restore during execute mode. +# Only set LANG and LC_ALL to C if already set. +# These must not be set unconditionally because not all systems understand +# e.g. LANG=C (notably SCO). +lt_user_locale= +lt_safe_locale= +for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES +do + eval "if test \"\${$lt_var+set}\" = set; then + save_$lt_var=\$$lt_var + $lt_var=C + export $lt_var + lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\" + lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\" + fi" +done + +$lt_unset CDPATH + + + + + +: ${CP="cp -f"} +: ${ECHO="echo"} +: ${EGREP="/bin/grep -E"} +: ${FGREP="/bin/grep -F"} +: ${GREP="/bin/grep"} +: ${LN_S="ln -s"} +: ${MAKE="make"} +: ${MKDIR="mkdir"} +: ${MV="mv -f"} +: ${RM="rm -f"} +: ${SED="/bin/sed"} +: ${SHELL="${CONFIG_SHELL-/bin/sh}"} +: ${Xsed="$SED -e 1s/^X//"} + +# Global variables: +EXIT_SUCCESS=0 +EXIT_FAILURE=1 +EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. +EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. + +exit_status=$EXIT_SUCCESS + +# Make sure IFS has a sensible default +lt_nl=' +' +IFS=" $lt_nl" + +dirname="s,/[^/]*$,," +basename="s,^.*/,," + +# func_dirname_and_basename file append nondir_replacement +# perform func_basename and func_dirname in a single function +# call: +# dirname: Compute the dirname of FILE. If nonempty, +# add APPEND to the result, otherwise set result +# to NONDIR_REPLACEMENT. +# value returned in "$func_dirname_result" +# basename: Compute filename of FILE. +# value retuned in "$func_basename_result" +# Implementation must be kept synchronized with func_dirname +# and func_basename. For efficiency, we do not delegate to +# those functions but instead duplicate the functionality here. +func_dirname_and_basename () +{ + # Extract subdirectory from the argument. + func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi + func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"` +} + +# Generated shell functions inserted here. + +# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh +# is ksh but when the shell is invoked as "sh" and the current value of +# the _XPG environment variable is not equal to 1 (one), the special +# positional parameter $0, within a function call, is the name of the +# function. +progpath="$0" + +# The name of this program: +# In the unlikely event $progname began with a '-', it would play havoc with +# func_echo (imagine progname=-n), so we prepend ./ in that case: +func_dirname_and_basename "$progpath" +progname=$func_basename_result +case $progname in + -*) progname=./$progname ;; +esac + +# Make sure we have an absolute path for reexecution: +case $progpath in + [\\/]*|[A-Za-z]:\\*) ;; + *[\\/]*) + progdir=$func_dirname_result + progdir=`cd "$progdir" && pwd` + progpath="$progdir/$progname" + ;; + *) + save_IFS="$IFS" + IFS=: + for progdir in $PATH; do + IFS="$save_IFS" + test -x "$progdir/$progname" && break + done + IFS="$save_IFS" + test -n "$progdir" || progdir=`pwd` + progpath="$progdir/$progname" + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed="${SED}"' -e 1s/^X//' +sed_quote_subst='s/\([`"$\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Re-`\' parameter expansions in output of double_quote_subst that were +# `\'-ed in input to the same. If an odd number of `\' preceded a '$' +# in input to double_quote_subst, that '$' was protected from expansion. +# Since each input `\' is now two `\'s, look for any number of runs of +# four `\'s followed by two `\'s and then a '$'. `\' that '$'. +bs='\\' +bs2='\\\\' +bs4='\\\\\\\\' +dollar='\$' +sed_double_backslash="\ + s/$bs4/&\\ +/g + s/^$bs2$dollar/$bs&/ + s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g + s/\n//g" + +# Standard options: +opt_dry_run=false +opt_help=false +opt_quiet=false +opt_verbose=false +opt_warning=: + +# func_echo arg... +# Echo program name prefixed message, along with the current mode +# name if it has been set yet. +func_echo () +{ + $ECHO "$progname${mode+: }$mode: $*" +} + +# func_verbose arg... +# Echo program name prefixed message in verbose mode only. +func_verbose () +{ + $opt_verbose && func_echo ${1+"$@"} + + # A bug in bash halts the script if the last line of a function + # fails when set -e is in force, so we need another command to + # work around that: + : +} + +# func_error arg... +# Echo program name prefixed message to standard error. +func_error () +{ + $ECHO "$progname${mode+: }$mode: "${1+"$@"} 1>&2 +} + +# func_warning arg... +# Echo program name prefixed warning message to standard error. +func_warning () +{ + $opt_warning && $ECHO "$progname${mode+: }$mode: warning: "${1+"$@"} 1>&2 + + # bash bug again: + : +} + +# func_fatal_error arg... +# Echo program name prefixed message to standard error, and exit. +func_fatal_error () +{ + func_error ${1+"$@"} + exit $EXIT_FAILURE +} + +# func_fatal_help arg... +# Echo program name prefixed message to standard error, followed by +# a help hint, and exit. +func_fatal_help () +{ + func_error ${1+"$@"} + func_fatal_error "$help" +} +help="Try \`$progname --help' for more information." ## default + + +# func_grep expression filename +# Check whether EXPRESSION matches any line of FILENAME, without output. +func_grep () +{ + $GREP "$1" "$2" >/dev/null 2>&1 +} + + +# func_mkdir_p directory-path +# Make sure the entire path to DIRECTORY-PATH is available. +func_mkdir_p () +{ + my_directory_path="$1" + my_dir_list= + + if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then + + # Protect directory names starting with `-' + case $my_directory_path in + -*) my_directory_path="./$my_directory_path" ;; + esac + + # While some portion of DIR does not yet exist... + while test ! -d "$my_directory_path"; do + # ...make a list in topmost first order. Use a colon delimited + # list incase some portion of path contains whitespace. + my_dir_list="$my_directory_path:$my_dir_list" + + # If the last portion added has no slash in it, the list is done + case $my_directory_path in */*) ;; *) break ;; esac + + # ...otherwise throw away the child directory and loop + my_directory_path=`$ECHO "X$my_directory_path" | $Xsed -e "$dirname"` + done + my_dir_list=`$ECHO "X$my_dir_list" | $Xsed -e 's,:*$,,'` + + save_mkdir_p_IFS="$IFS"; IFS=':' + for my_dir in $my_dir_list; do + IFS="$save_mkdir_p_IFS" + # mkdir can fail with a `File exist' error if two processes + # try to create one of the directories concurrently. Don't + # stop in that case! + $MKDIR "$my_dir" 2>/dev/null || : + done + IFS="$save_mkdir_p_IFS" + + # Bail out if we (or some other process) failed to create a directory. + test -d "$my_directory_path" || \ + func_fatal_error "Failed to create \`$1'" + fi +} + + +# func_mktempdir [string] +# Make a temporary directory that won't clash with other running +# libtool processes, and avoids race conditions if possible. If +# given, STRING is the basename for that directory. +func_mktempdir () +{ + my_template="${TMPDIR-/tmp}/${1-$progname}" + + if test "$opt_dry_run" = ":"; then + # Return a directory name, but don't create it in dry-run mode + my_tmpdir="${my_template}-$$" + else + + # If mktemp works, use that first and foremost + my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` + + if test ! -d "$my_tmpdir"; then + # Failing that, at least try and use $RANDOM to avoid a race + my_tmpdir="${my_template}-${RANDOM-0}$$" + + save_mktempdir_umask=`umask` + umask 0077 + $MKDIR "$my_tmpdir" + umask $save_mktempdir_umask + fi + + # If we're not in dry-run mode, bomb out on failure + test -d "$my_tmpdir" || \ + func_fatal_error "cannot create temporary directory \`$my_tmpdir'" + fi + + $ECHO "X$my_tmpdir" | $Xsed +} + + +# func_quote_for_eval arg +# Aesthetically quote ARG to be evaled later. +# This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT +# is double-quoted, suitable for a subsequent eval, whereas +# FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters +# which are still active within double quotes backslashified. +func_quote_for_eval () +{ + case $1 in + *[\\\`\"\$]*) + func_quote_for_eval_unquoted_result=`$ECHO "X$1" | $Xsed -e "$sed_quote_subst"` ;; + *) + func_quote_for_eval_unquoted_result="$1" ;; + esac + + case $func_quote_for_eval_unquoted_result in + # Double-quote args containing shell metacharacters to delay + # word splitting, command substitution and and variable + # expansion for a subsequent eval. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\"" + ;; + *) + func_quote_for_eval_result="$func_quote_for_eval_unquoted_result" + esac +} + + +# func_quote_for_expand arg +# Aesthetically quote ARG to be evaled later; same as above, +# but do not quote variable references. +func_quote_for_expand () +{ + case $1 in + *[\\\`\"]*) + my_arg=`$ECHO "X$1" | $Xsed \ + -e "$double_quote_subst" -e "$sed_double_backslash"` ;; + *) + my_arg="$1" ;; + esac + + case $my_arg in + # Double-quote args containing shell metacharacters to delay + # word splitting and command substitution for a subsequent eval. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + my_arg="\"$my_arg\"" + ;; + esac + + func_quote_for_expand_result="$my_arg" +} + + +# func_show_eval cmd [fail_exp] +# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. +func_show_eval () +{ + my_cmd="$1" + my_fail_exp="${2-:}" + + ${opt_silent-false} || { + func_quote_for_expand "$my_cmd" + eval "func_echo $func_quote_for_expand_result" + } + + if ${opt_dry_run-false}; then :; else + eval "$my_cmd" + my_status=$? + if test "$my_status" -eq 0; then :; else + eval "(exit $my_status); $my_fail_exp" + fi + fi +} + + +# func_show_eval_locale cmd [fail_exp] +# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. Use the saved locale for evaluation. +func_show_eval_locale () +{ + my_cmd="$1" + my_fail_exp="${2-:}" + + ${opt_silent-false} || { + func_quote_for_expand "$my_cmd" + eval "func_echo $func_quote_for_expand_result" + } + + if ${opt_dry_run-false}; then :; else + eval "$lt_user_locale + $my_cmd" + my_status=$? + eval "$lt_safe_locale" + if test "$my_status" -eq 0; then :; else + eval "(exit $my_status); $my_fail_exp" + fi + fi +} + + + + + +# func_version +# Echo version message to standard output and exit. +func_version () +{ + $SED -n '/^# '$PROGRAM' (GNU /,/# warranty; / { + s/^# // + s/^# *$// + s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/ + p + }' < "$progpath" + exit $? +} + +# func_usage +# Echo short help message to standard output and exit. +func_usage () +{ + $SED -n '/^# Usage:/,/# -h/ { + s/^# // + s/^# *$// + s/\$progname/'$progname'/ + p + }' < "$progpath" + $ECHO + $ECHO "run \`$progname --help | more' for full usage" + exit $? +} + +# func_help +# Echo long help message to standard output and exit. +func_help () +{ + $SED -n '/^# Usage:/,/# Report bugs to/ { + s/^# // + s/^# *$// + s*\$progname*'$progname'* + s*\$host*'"$host"'* + s*\$SHELL*'"$SHELL"'* + s*\$LTCC*'"$LTCC"'* + s*\$LTCFLAGS*'"$LTCFLAGS"'* + s*\$LD*'"$LD"'* + s/\$with_gnu_ld/'"$with_gnu_ld"'/ + s/\$automake_version/'"`(automake --version) 2>/dev/null |$SED 1q`"'/ + s/\$autoconf_version/'"`(autoconf --version) 2>/dev/null |$SED 1q`"'/ + p + }' < "$progpath" + exit $? +} + +# func_missing_arg argname +# Echo program name prefixed message to standard error and set global +# exit_cmd. +func_missing_arg () +{ + func_error "missing argument for $1" + exit_cmd=exit +} + +exit_cmd=: + + + + + +# Check that we have a working $ECHO. +if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X$1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t'; then + # Yippee, $ECHO works! + : +else + # Restart under the correct shell, and then maybe $ECHO will work. + exec $SHELL "$progpath" --no-reexec ${1+"$@"} +fi + +if test "X$1" = X--fallback-echo; then + # used as fallback echo + shift + cat </dev/null 2>&1; then + taglist="$taglist $tagname" + + # Evaluate the configuration. Be careful to quote the path + # and the sed script, to avoid splitting on whitespace, but + # also don't use non-portable quotes within backquotes within + # quotes we have to do it in 2 steps: + extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` + eval "$extractedcf" + else + func_error "ignoring unknown tag $tagname" + fi + ;; + esac +} + +# Parse options once, thoroughly. This comes as soon as possible in +# the script to make things like `libtool --version' happen quickly. +{ + + # Shorthand for --mode=foo, only valid as the first argument + case $1 in + clean|clea|cle|cl) + shift; set dummy --mode clean ${1+"$@"}; shift + ;; + compile|compil|compi|comp|com|co|c) + shift; set dummy --mode compile ${1+"$@"}; shift + ;; + execute|execut|execu|exec|exe|ex|e) + shift; set dummy --mode execute ${1+"$@"}; shift + ;; + finish|finis|fini|fin|fi|f) + shift; set dummy --mode finish ${1+"$@"}; shift + ;; + install|instal|insta|inst|ins|in|i) + shift; set dummy --mode install ${1+"$@"}; shift + ;; + link|lin|li|l) + shift; set dummy --mode link ${1+"$@"}; shift + ;; + uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) + shift; set dummy --mode uninstall ${1+"$@"}; shift + ;; + esac + + # Parse non-mode specific arguments: + while test "$#" -gt 0; do + opt="$1" + shift + + case $opt in + --config) func_config ;; + + --debug) preserve_args="$preserve_args $opt" + func_echo "enabling shell trace mode" + opt_debug='set -x' + $opt_debug + ;; + + -dlopen) test "$#" -eq 0 && func_missing_arg "$opt" && break + execute_dlfiles="$execute_dlfiles $1" + shift + ;; + + --dry-run | -n) opt_dry_run=: ;; + --features) func_features ;; + --finish) mode="finish" ;; + + --mode) test "$#" -eq 0 && func_missing_arg "$opt" && break + case $1 in + # Valid mode arguments: + clean) ;; + compile) ;; + execute) ;; + finish) ;; + install) ;; + link) ;; + relink) ;; + uninstall) ;; + + # Catch anything else as an error + *) func_error "invalid argument for $opt" + exit_cmd=exit + break + ;; + esac + + mode="$1" + shift + ;; + + --preserve-dup-deps) + opt_duplicate_deps=: ;; + + --quiet|--silent) preserve_args="$preserve_args $opt" + opt_silent=: + ;; + + --verbose| -v) preserve_args="$preserve_args $opt" + opt_silent=false + ;; + + --tag) test "$#" -eq 0 && func_missing_arg "$opt" && break + preserve_args="$preserve_args $opt $1" + func_enable_tag "$1" # tagname is set here + shift + ;; + + # Separate optargs to long options: + -dlopen=*|--mode=*|--tag=*) + func_opt_split "$opt" + set dummy "$func_opt_split_opt" "$func_opt_split_arg" ${1+"$@"} + shift + ;; + + -\?|-h) func_usage ;; + --help) opt_help=: ;; + --version) func_version ;; + + -*) func_fatal_help "unrecognized option \`$opt'" ;; + + *) nonopt="$opt" + break + ;; + esac + done + + + case $host in + *cygwin* | *mingw* | *pw32* | *cegcc*) + # don't eliminate duplications in $postdeps and $predeps + opt_duplicate_compiler_generated_deps=: + ;; + *) + opt_duplicate_compiler_generated_deps=$opt_duplicate_deps + ;; + esac + + # Having warned about all mis-specified options, bail out if + # anything was wrong. + $exit_cmd $EXIT_FAILURE +} + +# func_check_version_match +# Ensure that we are using m4 macros, and libtool script from the same +# release of libtool. +func_check_version_match () +{ + if test "$package_revision" != "$macro_revision"; then + if test "$VERSION" != "$macro_version"; then + if test -z "$macro_version"; then + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from an older release. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from $PACKAGE $macro_version. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + fi + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, +$progname: but the definition of this LT_INIT comes from revision $macro_revision. +$progname: You should recreate aclocal.m4 with macros from revision $package_revision +$progname: of $PACKAGE $VERSION and run autoconf again. +_LT_EOF + fi + + exit $EXIT_MISMATCH + fi +} + + +## ----------- ## +## Main. ## +## ----------- ## + +$opt_help || { + # Sanity checks first: + func_check_version_match + + if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then + func_fatal_configuration "not configured to build any kind of library" + fi + + test -z "$mode" && func_fatal_error "error: you must specify a MODE." + + + # Darwin sucks + eval std_shrext=\"$shrext_cmds\" + + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$execute_dlfiles" && test "$mode" != execute; then + func_error "unrecognized option \`-dlopen'" + $ECHO "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Change the help message to a mode-specific one. + generic_help="$help" + help="Try \`$progname --help --mode=$mode' for more information." +} + + +# func_lalib_p file +# True iff FILE is a libtool `.la' library or `.lo' object file. +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_lalib_p () +{ + test -f "$1" && + $SED -e 4q "$1" 2>/dev/null \ + | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 +} + +# func_lalib_unsafe_p file +# True iff FILE is a libtool `.la' library or `.lo' object file. +# This function implements the same check as func_lalib_p without +# resorting to external programs. To this end, it redirects stdin and +# closes it afterwards, without saving the original file descriptor. +# As a safety measure, use it only where a negative result would be +# fatal anyway. Works if `file' does not exist. +func_lalib_unsafe_p () +{ + lalib_p=no + if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then + for lalib_p_l in 1 2 3 4 + do + read lalib_p_line + case "$lalib_p_line" in + \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; + esac + done + exec 0<&5 5<&- + fi + test "$lalib_p" = yes +} + +# func_ltwrapper_script_p file +# True iff FILE is a libtool wrapper script +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_script_p () +{ + func_lalib_p "$1" +} + +# func_ltwrapper_executable_p file +# True iff FILE is a libtool wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_executable_p () +{ + func_ltwrapper_exec_suffix= + case $1 in + *.exe) ;; + *) func_ltwrapper_exec_suffix=.exe ;; + esac + $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 +} + +# func_ltwrapper_scriptname file +# Assumes file is an ltwrapper_executable +# uses $file to determine the appropriate filename for a +# temporary ltwrapper_script. +func_ltwrapper_scriptname () +{ + func_ltwrapper_scriptname_result="" + if func_ltwrapper_executable_p "$1"; then + func_dirname_and_basename "$1" "" "." + func_stripname '' '.exe' "$func_basename_result" + func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper" + fi +} + +# func_ltwrapper_p file +# True iff FILE is a libtool wrapper script or wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_p () +{ + func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" +} + + +# func_execute_cmds commands fail_cmd +# Execute tilde-delimited COMMANDS. +# If FAIL_CMD is given, eval that upon failure. +# FAIL_CMD may read-access the current command in variable CMD! +func_execute_cmds () +{ + $opt_debug + save_ifs=$IFS; IFS='~' + for cmd in $1; do + IFS=$save_ifs + eval cmd=\"$cmd\" + func_show_eval "$cmd" "${2-:}" + done + IFS=$save_ifs +} + + +# func_source file +# Source FILE, adding directory component if necessary. +# Note that it is not necessary on cygwin/mingw to append a dot to +# FILE even if both FILE and FILE.exe exist: automatic-append-.exe +# behavior happens only for exec(3), not for open(2)! Also, sourcing +# `FILE.' does not work on cygwin managed mounts. +func_source () +{ + $opt_debug + case $1 in + */* | *\\*) . "$1" ;; + *) . "./$1" ;; + esac +} + + +# func_infer_tag arg +# Infer tagged configuration to use if any are available and +# if one wasn't chosen via the "--tag" command line option. +# Only attempt this if the compiler in the base compile +# command doesn't match the default compiler. +# arg is usually of the form 'gcc ...' +func_infer_tag () +{ + $opt_debug + if test -n "$available_tags" && test -z "$tagname"; then + CC_quoted= + for arg in $CC; do + func_quote_for_eval "$arg" + CC_quoted="$CC_quoted $func_quote_for_eval_result" + done + case $@ in + # Blanks in the command may have been stripped by the calling shell, + # but not from the CC environment variable when configure was run. + " $CC "* | "$CC "* | " `$ECHO $CC` "* | "`$ECHO $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$ECHO $CC_quoted` "* | "`$ECHO $CC_quoted` "*) ;; + # Blanks at the start of $base_compile will cause this to fail + # if we don't check for them as well. + *) + for z in $available_tags; do + if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then + # Evaluate the configuration. + eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" + CC_quoted= + for arg in $CC; do + # Double-quote args containing other shell metacharacters. + func_quote_for_eval "$arg" + CC_quoted="$CC_quoted $func_quote_for_eval_result" + done + case "$@ " in + " $CC "* | "$CC "* | " `$ECHO $CC` "* | "`$ECHO $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$ECHO $CC_quoted` "* | "`$ECHO $CC_quoted` "*) + # The compiler in the base compile command matches + # the one in the tagged configuration. + # Assume this is the tagged configuration we want. + tagname=$z + break + ;; + esac + fi + done + # If $tagname still isn't set, then no tagged configuration + # was found and let the user know that the "--tag" command + # line option must be used. + if test -z "$tagname"; then + func_echo "unable to infer tagged configuration" + func_fatal_error "specify a tag with \`--tag'" +# else +# func_verbose "using $tagname tagged configuration" + fi + ;; + esac + fi +} + + + +# func_write_libtool_object output_name pic_name nonpic_name +# Create a libtool object file (analogous to a ".la" file), +# but don't create it if we're doing a dry run. +func_write_libtool_object () +{ + write_libobj=${1} + if test "$build_libtool_libs" = yes; then + write_lobj=\'${2}\' + else + write_lobj=none + fi + + if test "$build_old_libs" = yes; then + write_oldobj=\'${3}\' + else + write_oldobj=none + fi + + $opt_dry_run || { + cat >${write_libobj}T <?"'"'"' &()|`$[]' \ + && func_warning "libobj name \`$libobj' may not contain shell special characters." + func_dirname_and_basename "$obj" "/" "" + objname="$func_basename_result" + xdir="$func_dirname_result" + lobj=${xdir}$objdir/$objname + + test -z "$base_compile" && \ + func_fatal_help "you must specify a compilation command" + + # Delete any leftover library objects. + if test "$build_old_libs" = yes; then + removelist="$obj $lobj $libobj ${libobj}T" + else + removelist="$lobj $libobj ${libobj}T" + fi + + # On Cygwin there's no "real" PIC flag so we must build both object types + case $host_os in + cygwin* | mingw* | pw32* | os2* | cegcc*) + pic_mode=default + ;; + esac + if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then + # non-PIC code in shared libraries is not supported + pic_mode=default + fi + + # Calculate the filename of the output object if compiler does + # not support -o with -c + if test "$compiler_c_o" = no; then + output_obj=`$ECHO "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext} + lockfile="$output_obj.lock" + else + output_obj= + need_locks=no + lockfile= + fi + + # Lock this critical section if it is needed + # We use this script file to make the link, it avoids creating a new file + if test "$need_locks" = yes; then + until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do + func_echo "Waiting for $lockfile to be removed" + sleep 2 + done + elif test "$need_locks" = warn; then + if test -f "$lockfile"; then + $ECHO "\ +*** ERROR, $lockfile exists and contains: +`cat $lockfile 2>/dev/null` + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + removelist="$removelist $output_obj" + $ECHO "$srcfile" > "$lockfile" + fi + + $opt_dry_run || $RM $removelist + removelist="$removelist $lockfile" + trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 + + if test -n "$fix_srcfile_path"; then + eval srcfile=\"$fix_srcfile_path\" + fi + func_quote_for_eval "$srcfile" + qsrcfile=$func_quote_for_eval_result + + # Only build a PIC object if we are building libtool libraries. + if test "$build_libtool_libs" = yes; then + # Without this assignment, base_compile gets emptied. + fbsd_hideous_sh_bug=$base_compile + + if test "$pic_mode" != no; then + command="$base_compile $qsrcfile $pic_flag" + else + # Don't build PIC code + command="$base_compile $qsrcfile" + fi + + func_mkdir_p "$xdir$objdir" + + if test -z "$output_obj"; then + # Place PIC objects in $objdir + command="$command -o $lobj" + fi + + func_show_eval_locale "$command" \ + 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' + + if test "$need_locks" = warn && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $ECHO "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed, then go on to compile the next one + if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then + func_show_eval '$MV "$output_obj" "$lobj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + + # Allow error messages only from the first compilation. + if test "$suppress_opt" = yes; then + suppress_output=' >/dev/null 2>&1' + fi + fi + + # Only build a position-dependent object if we build old libraries. + if test "$build_old_libs" = yes; then + if test "$pic_mode" != yes; then + # Don't build PIC code + command="$base_compile $qsrcfile$pie_flag" + else + command="$base_compile $qsrcfile $pic_flag" + fi + if test "$compiler_c_o" = yes; then + command="$command -o $obj" + fi + + # Suppress compiler output if we already did a PIC compilation. + command="$command$suppress_output" + func_show_eval_locale "$command" \ + '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' + + if test "$need_locks" = warn && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $ECHO "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed + if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then + func_show_eval '$MV "$output_obj" "$obj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + fi + + $opt_dry_run || { + func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" + + # Unlock the critical section if it was locked + if test "$need_locks" != no; then + removelist=$lockfile + $RM "$lockfile" + fi + } + + exit $EXIT_SUCCESS +} + +$opt_help || { +test "$mode" = compile && func_mode_compile ${1+"$@"} +} + +func_mode_help () +{ + # We need to display help for each of the modes. + case $mode in + "") + # Generic help is extracted from the usage comments + # at the start of this file. + func_help + ;; + + clean) + $ECHO \ +"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... + +Remove files from the build directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, object or program, all the files associated +with it are deleted. Otherwise, only FILE itself is deleted using RM." + ;; + + compile) + $ECHO \ +"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE + +Compile a source file into a libtool library object. + +This mode accepts the following additional options: + + -o OUTPUT-FILE set the output file name to OUTPUT-FILE + -no-suppress do not suppress compiler output for multiple passes + -prefer-pic try to building PIC objects only + -prefer-non-pic try to building non-PIC objects only + -shared do not build a \`.o' file suitable for static linking + -static only build a \`.o' file suitable for static linking + +COMPILE-COMMAND is a command to be used in creating a \`standard' object file +from the given SOURCEFILE. + +The output file name is determined by removing the directory component from +SOURCEFILE, then substituting the C source code suffix \`.c' with the +library object suffix, \`.lo'." + ;; + + execute) + $ECHO \ +"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... + +Automatically set library path, then run a program. + +This mode accepts the following additional options: + + -dlopen FILE add the directory containing FILE to the library path + +This mode sets the library path environment variable according to \`-dlopen' +flags. + +If any of the ARGS are libtool executable wrappers, then they are translated +into their corresponding uninstalled binary, and any of their required library +directories are added to the library path. + +Then, COMMAND is executed, with ARGS as arguments." + ;; + + finish) + $ECHO \ +"Usage: $progname [OPTION]... --mode=finish [LIBDIR]... + +Complete the installation of libtool libraries. + +Each LIBDIR is a directory that contains libtool libraries. + +The commands that this mode executes may require superuser privileges. Use +the \`--dry-run' option if you just want to see what would be executed." + ;; + + install) + $ECHO \ +"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... + +Install executables or libraries. + +INSTALL-COMMAND is the installation command. The first component should be +either the \`install' or \`cp' program. + +The following components of INSTALL-COMMAND are treated specially: + + -inst-prefix PREFIX-DIR Use PREFIX-DIR as a staging area for installation + +The rest of the components are interpreted as arguments to that command (only +BSD-compatible install options are recognized)." + ;; + + link) + $ECHO \ +"Usage: $progname [OPTION]... --mode=link LINK-COMMAND... + +Link object files or libraries together to form another library, or to +create an executable program. + +LINK-COMMAND is a command using the C compiler that you would use to create +a program from several object files. + +The following components of LINK-COMMAND are treated specially: + + -all-static do not do any dynamic linking at all + -avoid-version do not add a version suffix if possible + -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime + -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols + -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) + -export-symbols SYMFILE + try to export only the symbols listed in SYMFILE + -export-symbols-regex REGEX + try to export only the symbols matching REGEX + -LLIBDIR search LIBDIR for required installed libraries + -lNAME OUTPUT-FILE requires the installed library libNAME + -module build a library that can dlopened + -no-fast-install disable the fast-install mode + -no-install link a not-installable executable + -no-undefined declare that a library does not refer to external symbols + -o OUTPUT-FILE create OUTPUT-FILE from the specified objects + -objectlist FILE Use a list of object files found in FILE to specify objects + -precious-files-regex REGEX + don't remove output files matching REGEX + -release RELEASE specify package release information + -rpath LIBDIR the created library will eventually be installed in LIBDIR + -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries + -shared only do dynamic linking of libtool libraries + -shrext SUFFIX override the standard shared library file extension + -static do not do any dynamic linking of uninstalled libtool libraries + -static-libtool-libs + do not do any dynamic linking of libtool libraries + -version-info CURRENT[:REVISION[:AGE]] + specify library version info [each variable defaults to 0] + -weak LIBNAME declare that the target provides the LIBNAME interface + +All other options (arguments beginning with \`-') are ignored. + +Every other argument is treated as a filename. Files ending in \`.la' are +treated as uninstalled libtool libraries, other files are standard or library +object files. + +If the OUTPUT-FILE ends in \`.la', then a libtool library is created, +only library objects (\`.lo' files) may be specified, and \`-rpath' is +required, except when creating a convenience library. + +If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created +using \`ar' and \`ranlib', or on Windows using \`lib'. + +If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file +is created, otherwise an executable program is created." + ;; + + uninstall) + $ECHO \ +"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... + +Remove libraries from an installation directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, all the files associated with it are deleted. +Otherwise, only FILE itself is deleted using RM." + ;; + + *) + func_fatal_help "invalid operation mode \`$mode'" + ;; + esac + + $ECHO + $ECHO "Try \`$progname --help' for more information about other modes." + + exit $? +} + + # Now that we've collected a possible --mode arg, show help if necessary + $opt_help && func_mode_help + + +# func_mode_execute arg... +func_mode_execute () +{ + $opt_debug + # The first argument is the command name. + cmd="$nonopt" + test -z "$cmd" && \ + func_fatal_help "you must specify a COMMAND" + + # Handle -dlopen flags immediately. + for file in $execute_dlfiles; do + test -f "$file" \ + || func_fatal_help "\`$file' is not a file" + + dir= + case $file in + *.la) + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "\`$lib' is not a valid libtool archive" + + # Read the libtool library. + dlname= + library_names= + func_source "$file" + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && \ + func_warning "\`$file' was not linked with \`-export-dynamic'" + continue + fi + + func_dirname "$file" "" "." + dir="$func_dirname_result" + + if test -f "$dir/$objdir/$dlname"; then + dir="$dir/$objdir" + else + if test ! -f "$dir/$dlname"; then + func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" + fi + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + func_dirname "$file" "" "." + dir="$func_dirname_result" + ;; + + *) + func_warning "\`-dlopen' is ignored for non-libtool libraries and objects" + continue + ;; + esac + + # Get the absolute pathname. + absdir=`cd "$dir" && pwd` + test -n "$absdir" && dir="$absdir" + + # Now add the directory to shlibpath_var. + if eval "test -z \"\$$shlibpath_var\""; then + eval "$shlibpath_var=\"\$dir\"" + else + eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" + fi + done + + # This variable tells wrapper scripts just to set shlibpath_var + # rather than running their programs. + libtool_execute_magic="$magic" + + # Check if any of the arguments is a wrapper script. + args= + for file + do + case $file in + -*) ;; + *) + # Do a test to see if this is really a libtool program. + if func_ltwrapper_script_p "$file"; then + func_source "$file" + # Transform arg to wrapped name. + file="$progdir/$program" + elif func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + func_source "$func_ltwrapper_scriptname_result" + # Transform arg to wrapped name. + file="$progdir/$program" + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + func_quote_for_eval "$file" + args="$args $func_quote_for_eval_result" + done + + if test "X$opt_dry_run" = Xfalse; then + if test -n "$shlibpath_var"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + fi + + # Restore saved environment variables + for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES + do + eval "if test \"\${save_$lt_var+set}\" = set; then + $lt_var=\$save_$lt_var; export $lt_var + else + $lt_unset $lt_var + fi" + done + + # Now prepare to actually exec the command. + exec_cmd="\$cmd$args" + else + # Display what would be done. + if test -n "$shlibpath_var"; then + eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" + $ECHO "export $shlibpath_var" + fi + $ECHO "$cmd$args" + exit $EXIT_SUCCESS + fi +} + +test "$mode" = execute && func_mode_execute ${1+"$@"} + + +# func_mode_finish arg... +func_mode_finish () +{ + $opt_debug + libdirs="$nonopt" + admincmds= + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + for dir + do + libdirs="$libdirs $dir" + done + + for libdir in $libdirs; do + if test -n "$finish_cmds"; then + # Do each command in the finish commands. + func_execute_cmds "$finish_cmds" 'admincmds="$admincmds +'"$cmd"'"' + fi + if test -n "$finish_eval"; then + # Do the single finish_eval. + eval cmds=\"$finish_eval\" + $opt_dry_run || eval "$cmds" || admincmds="$admincmds + $cmds" + fi + done + fi + + # Exit here if they wanted silent mode. + $opt_silent && exit $EXIT_SUCCESS + + $ECHO "X----------------------------------------------------------------------" | $Xsed + $ECHO "Libraries have been installed in:" + for libdir in $libdirs; do + $ECHO " $libdir" + done + $ECHO + $ECHO "If you ever happen to want to link against installed libraries" + $ECHO "in a given directory, LIBDIR, you must either use libtool, and" + $ECHO "specify the full pathname of the library, or use the \`-LLIBDIR'" + $ECHO "flag during linking and do at least one of the following:" + if test -n "$shlibpath_var"; then + $ECHO " - add LIBDIR to the \`$shlibpath_var' environment variable" + $ECHO " during execution" + fi + if test -n "$runpath_var"; then + $ECHO " - add LIBDIR to the \`$runpath_var' environment variable" + $ECHO " during linking" + fi + if test -n "$hardcode_libdir_flag_spec"; then + libdir=LIBDIR + eval flag=\"$hardcode_libdir_flag_spec\" + + $ECHO " - use the \`$flag' linker flag" + fi + if test -n "$admincmds"; then + $ECHO " - have your system administrator run these commands:$admincmds" + fi + if test -f /etc/ld.so.conf; then + $ECHO " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" + fi + $ECHO + + $ECHO "See any operating system documentation about shared libraries for" + case $host in + solaris2.[6789]|solaris2.1[0-9]) + $ECHO "more information, such as the ld(1), crle(1) and ld.so(8) manual" + $ECHO "pages." + ;; + *) + $ECHO "more information, such as the ld(1) and ld.so(8) manual pages." + ;; + esac + $ECHO "X----------------------------------------------------------------------" | $Xsed + exit $EXIT_SUCCESS +} + +test "$mode" = finish && func_mode_finish ${1+"$@"} + + +# func_mode_install arg... +func_mode_install () +{ + $opt_debug + # There may be an optional sh(1) argument at the beginning of + # install_prog (especially on Windows NT). + if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || + # Allow the use of GNU shtool's install command. + $ECHO "X$nonopt" | $GREP shtool >/dev/null; then + # Aesthetically quote it. + func_quote_for_eval "$nonopt" + install_prog="$func_quote_for_eval_result " + arg=$1 + shift + else + install_prog= + arg=$nonopt + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + func_quote_for_eval "$arg" + install_prog="$install_prog$func_quote_for_eval_result" + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir=no + stripme= + for arg + do + if test -n "$dest"; then + files="$files $dest" + dest=$arg + continue + fi + + case $arg in + -d) isdir=yes ;; + -f) + case " $install_prog " in + *[\\\ /]cp\ *) ;; + *) prev=$arg ;; + esac + ;; + -g | -m | -o) + prev=$arg + ;; + -s) + stripme=" -s" + continue + ;; + -*) + ;; + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + prev= + else + dest=$arg + continue + fi + ;; + esac + + # Aesthetically quote the argument. + func_quote_for_eval "$arg" + install_prog="$install_prog $func_quote_for_eval_result" + done + + test -z "$install_prog" && \ + func_fatal_help "you must specify an install program" + + test -n "$prev" && \ + func_fatal_help "the \`$prev' option requires an argument" + + if test -z "$files"; then + if test -z "$dest"; then + func_fatal_help "no file or destination specified" + else + func_fatal_help "you must specify a destination" + fi + fi + + # Strip any trailing slash from the destination. + func_stripname '' '/' "$dest" + dest=$func_stripname_result + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=yes + if test "$isdir" = yes; then + destdir="$dest" + destname= + else + func_dirname_and_basename "$dest" "" "." + destdir="$func_dirname_result" + destname="$func_basename_result" + + # Not a directory, so check to see that there is only one file specified. + set dummy $files; shift + test "$#" -gt 1 && \ + func_fatal_help "\`$dest' is not a directory" + fi + case $destdir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + for file in $files; do + case $file in + *.lo) ;; + *) + func_fatal_help "\`$destdir' must be an absolute directory name" + ;; + esac + done + ;; + esac + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + staticlibs= + future_libdirs= + current_libdirs= + for file in $files; do + + # Do each installation. + case $file in + *.$libext) + # Do the static libraries later. + staticlibs="$staticlibs $file" + ;; + + *.la) + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "\`$file' is not a valid libtool archive" + + library_names= + old_library= + relink_command= + func_source "$file" + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) current_libdirs="$current_libdirs $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) future_libdirs="$future_libdirs $libdir" ;; + esac + fi + + func_dirname "$file" "/" "" + dir="$func_dirname_result" + dir="$dir$objdir" + + if test -n "$relink_command"; then + # Determine the prefix the user has applied to our future dir. + inst_prefix_dir=`$ECHO "X$destdir" | $Xsed -e "s%$libdir\$%%"` + + # Don't allow the user to place us outside of our expected + # location b/c this prevents finding dependent libraries that + # are installed to the same prefix. + # At present, this check doesn't affect windows .dll's that + # are installed into $libdir/../bin (currently, that works fine) + # but it's something to keep an eye on. + test "$inst_prefix_dir" = "$destdir" && \ + func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir" + + if test -n "$inst_prefix_dir"; then + # Stick the inst_prefix_dir data into the link command. + relink_command=`$ECHO "X$relink_command" | $Xsed -e "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` + else + relink_command=`$ECHO "X$relink_command" | $Xsed -e "s%@inst_prefix_dir@%%"` + fi + + func_warning "relinking \`$file'" + func_show_eval "$relink_command" \ + 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"' + fi + + # See the names of the shared library. + set dummy $library_names; shift + if test -n "$1"; then + realname="$1" + shift + + srcname="$realname" + test -n "$relink_command" && srcname="$realname"T + + # Install the shared library and build the symlinks. + func_show_eval "$install_prog $dir/$srcname $destdir/$realname" \ + 'exit $?' + tstripme="$stripme" + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + case $realname in + *.dll.a) + tstripme="" + ;; + esac + ;; + esac + if test -n "$tstripme" && test -n "$striplib"; then + func_show_eval "$striplib $destdir/$realname" 'exit $?' + fi + + if test "$#" -gt 0; then + # Delete the old symlinks, and create new ones. + # Try `ln -sf' first, because the `ln' binary might depend on + # the symlink we replace! Solaris /bin/ln does not understand -f, + # so we also need to try rm && ln -s. + for linkname + do + test "$linkname" != "$realname" \ + && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" + done + fi + + # Do each command in the postinstall commands. + lib="$destdir/$realname" + func_execute_cmds "$postinstall_cmds" 'exit $?' + fi + + # Install the pseudo-library for information purposes. + func_basename "$file" + name="$func_basename_result" + instname="$dir/$name"i + func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' + + # Maybe install the static library, too. + test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" + ;; + + *.lo) + # Install (i.e. copy) a libtool object. + + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + func_basename "$file" + destfile="$func_basename_result" + destfile="$destdir/$destfile" + fi + + # Deduce the name of the destination old-style object file. + case $destfile in + *.lo) + func_lo2o "$destfile" + staticdest=$func_lo2o_result + ;; + *.$objext) + staticdest="$destfile" + destfile= + ;; + *) + func_fatal_help "cannot copy a libtool object to \`$destfile'" + ;; + esac + + # Install the libtool object if requested. + test -n "$destfile" && \ + func_show_eval "$install_prog $file $destfile" 'exit $?' + + # Install the old object if enabled. + if test "$build_old_libs" = yes; then + # Deduce the name of the old-style object file. + func_lo2o "$file" + staticobj=$func_lo2o_result + func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' + fi + exit $EXIT_SUCCESS + ;; + + *) + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + func_basename "$file" + destfile="$func_basename_result" + destfile="$destdir/$destfile" + fi + + # If the file is missing, and there is a .exe on the end, strip it + # because it is most likely a libtool script we actually want to + # install + stripped_ext="" + case $file in + *.exe) + if test ! -f "$file"; then + func_stripname '' '.exe' "$file" + file=$func_stripname_result + stripped_ext=".exe" + fi + ;; + esac + + # Do a test to see if this is really a libtool program. + case $host in + *cygwin* | *mingw*) + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + wrapper=$func_ltwrapper_scriptname_result + else + func_stripname '' '.exe' "$file" + wrapper=$func_stripname_result + fi + ;; + *) + wrapper=$file + ;; + esac + if func_ltwrapper_script_p "$wrapper"; then + notinst_deplibs= + relink_command= + + func_source "$wrapper" + + # Check the variables that should have been set. + test -z "$generated_by_libtool_version" && \ + func_fatal_error "invalid libtool wrapper script \`$wrapper'" + + finalize=yes + for lib in $notinst_deplibs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + func_source "$lib" + fi + libfile="$libdir/"`$ECHO "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test + if test -n "$libdir" && test ! -f "$libfile"; then + func_warning "\`$lib' has not been installed in \`$libdir'" + finalize=no + fi + done + + relink_command= + func_source "$wrapper" + + outputname= + if test "$fast_install" = no && test -n "$relink_command"; then + $opt_dry_run || { + if test "$finalize" = yes; then + tmpdir=`func_mktempdir` + func_basename "$file$stripped_ext" + file="$func_basename_result" + outputname="$tmpdir/$file" + # Replace the output file specification. + relink_command=`$ECHO "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'` + + $opt_silent || { + func_quote_for_expand "$relink_command" + eval "func_echo $func_quote_for_expand_result" + } + if eval "$relink_command"; then : + else + func_error "error: relink \`$file' with the above command before installing it" + $opt_dry_run || ${RM}r "$tmpdir" + continue + fi + file="$outputname" + else + func_warning "cannot relink \`$file'" + fi + } + else + # Install the binary that we compiled earlier. + file=`$ECHO "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"` + fi + fi + + # remove .exe since cygwin /usr/bin/install will append another + # one anyway + case $install_prog,$host in + */usr/bin/install*,*cygwin*) + case $file:$destfile in + *.exe:*.exe) + # this is ok + ;; + *.exe:*) + destfile=$destfile.exe + ;; + *:*.exe) + func_stripname '' '.exe' "$destfile" + destfile=$func_stripname_result + ;; + esac + ;; + esac + func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' + $opt_dry_run || if test -n "$outputname"; then + ${RM}r "$tmpdir" + fi + ;; + esac + done + + for file in $staticlibs; do + func_basename "$file" + name="$func_basename_result" + + # Set up the ranlib parameters. + oldlib="$destdir/$name" + + func_show_eval "$install_prog \$file \$oldlib" 'exit $?' + + if test -n "$stripme" && test -n "$old_striplib"; then + func_show_eval "$old_striplib $oldlib" 'exit $?' + fi + + # Do each command in the postinstall commands. + func_execute_cmds "$old_postinstall_cmds" 'exit $?' + done + + test -n "$future_libdirs" && \ + func_warning "remember to run \`$progname --finish$future_libdirs'" + + if test -n "$current_libdirs"; then + # Maybe just do a dry run. + $opt_dry_run && current_libdirs=" -n$current_libdirs" + exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' + else + exit $EXIT_SUCCESS + fi +} + +test "$mode" = install && func_mode_install ${1+"$@"} + + +# func_generate_dlsyms outputname originator pic_p +# Extract symbols from dlprefiles and create ${outputname}S.o with +# a dlpreopen symbol table. +func_generate_dlsyms () +{ + $opt_debug + my_outputname="$1" + my_originator="$2" + my_pic_p="${3-no}" + my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'` + my_dlsyms= + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + if test -n "$NM" && test -n "$global_symbol_pipe"; then + my_dlsyms="${my_outputname}S.c" + else + func_error "not configured to extract global symbols from dlpreopened files" + fi + fi + + if test -n "$my_dlsyms"; then + case $my_dlsyms in + "") ;; + *.c) + # Discover the nlist of each of the dlfiles. + nlist="$output_objdir/${my_outputname}.nm" + + func_show_eval "$RM $nlist ${nlist}S ${nlist}T" + + # Parse the name list into a source file. + func_verbose "creating $output_objdir/$my_dlsyms" + + $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ +/* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */ +/* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +/* External symbol declarations for the compiler. */\ +" + + if test "$dlself" = yes; then + func_verbose "generating symbol list for \`$output'" + + $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" + + # Add our own program objects to the symbol list. + progfiles=`$ECHO "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + for progfile in $progfiles; do + func_verbose "extracting global C symbols from \`$progfile'" + $opt_dry_run || eval "$NM $progfile | $global_symbol_pipe >> '$nlist'" + done + + if test -n "$exclude_expsyms"; then + $opt_dry_run || { + eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + } + fi + + if test -n "$export_symbols_regex"; then + $opt_dry_run || { + eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + } + fi + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + export_symbols="$output_objdir/$outputname.exp" + $opt_dry_run || { + $RM $export_symbols + eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' + case $host in + *cygwin* | *mingw* | *cegcc* ) + eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' + ;; + esac + } + else + $opt_dry_run || { + eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' + eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + case $host in + *cygwin | *mingw* | *cegcc* ) + eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' + ;; + esac + } + fi + fi + + for dlprefile in $dlprefiles; do + func_verbose "extracting global C symbols from \`$dlprefile'" + func_basename "$dlprefile" + name="$func_basename_result" + $opt_dry_run || { + eval '$ECHO ": $name " >> "$nlist"' + eval "$NM $dlprefile 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + done + + $opt_dry_run || { + # Make sure we have at least an empty file. + test -f "$nlist" || : > "$nlist" + + if test -n "$exclude_expsyms"; then + $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T + $MV "$nlist"T "$nlist" + fi + + # Try sorting and uniquifying the output. + if $GREP -v "^: " < "$nlist" | + if sort -k 3 /dev/null 2>&1; then + sort -k 3 + else + sort +2 + fi | + uniq > "$nlist"S; then + : + else + $GREP -v "^: " < "$nlist" > "$nlist"S + fi + + if test -f "$nlist"S; then + eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' + else + $ECHO '/* NONE */' >> "$output_objdir/$my_dlsyms" + fi + + $ECHO >> "$output_objdir/$my_dlsyms" "\ + +/* The mapping between symbol names and symbols. */ +typedef struct { + const char *name; + void *address; +} lt_dlsymlist; +" + case $host in + *cygwin* | *mingw* | *cegcc* ) + $ECHO >> "$output_objdir/$my_dlsyms" "\ +/* DATA imports from DLLs on WIN32 con't be const, because + runtime relocations are performed -- see ld's documentation + on pseudo-relocs. */" + lt_dlsym_const= ;; + *osf5*) + echo >> "$output_objdir/$my_dlsyms" "\ +/* This system does not cope well with relocations in const data */" + lt_dlsym_const= ;; + *) + lt_dlsym_const=const ;; + esac + + $ECHO >> "$output_objdir/$my_dlsyms" "\ +extern $lt_dlsym_const lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[]; +$lt_dlsym_const lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[] = +{\ + { \"$my_originator\", (void *) 0 }," + + case $need_lib_prefix in + no) + eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + *) + eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + esac + $ECHO >> "$output_objdir/$my_dlsyms" "\ + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt_${my_prefix}_LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif\ +" + } # !$opt_dry_run + + pic_flag_for_symtable= + case "$compile_command " in + *" -static "*) ;; + *) + case $host in + # compiling the symbol table file with pic_flag works around + # a FreeBSD bug that causes programs to crash when -lm is + # linked before any other PIC object. But we must not use + # pic_flag when linking with -static. The problem exists in + # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. + *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) + pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; + *-*-hpux*) + pic_flag_for_symtable=" $pic_flag" ;; + *) + if test "X$my_pic_p" != Xno; then + pic_flag_for_symtable=" $pic_flag" + fi + ;; + esac + ;; + esac + symtab_cflags= + for arg in $LTCFLAGS; do + case $arg in + -pie | -fpie | -fPIE) ;; + *) symtab_cflags="$symtab_cflags $arg" ;; + esac + done + + # Now compile the dynamic symbol file. + func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' + + # Clean up the generated files. + func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"' + + # Transform the symbol file into the correct name. + symfileobj="$output_objdir/${my_outputname}S.$objext" + case $host in + *cygwin* | *mingw* | *cegcc* ) + if test -f "$output_objdir/$my_outputname.def"; then + compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + else + compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` + fi + ;; + *) + compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` + ;; + esac + ;; + *) + func_fatal_error "unknown suffix for \`$my_dlsyms'" + ;; + esac + else + # We keep going just in case the user didn't refer to + # lt_preloaded_symbols. The linker will fail if global_symbol_pipe + # really was required. + + # Nullify the symbol file. + compile_command=`$ECHO "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"` + finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"` + fi +} + +# func_win32_libid arg +# return the library type of file 'arg' +# +# Need a lot of goo to handle *both* DLLs and import libs +# Has to be a shell function in order to 'eat' the argument +# that is supplied when $file_magic_command is called. +func_win32_libid () +{ + $opt_debug + win32_libid_type="unknown" + win32_fileres=`file -L $1 2>/dev/null` + case $win32_fileres in + *ar\ archive\ import\ library*) # definitely import + win32_libid_type="x86 archive import" + ;; + *ar\ archive*) # could be an import, or static + if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | + $EGREP 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then + win32_nmres=`eval $NM -f posix -A $1 | + $SED -n -e ' + 1,100{ + / I /{ + s,.*,import, + p + q + } + }'` + case $win32_nmres in + import*) win32_libid_type="x86 archive import";; + *) win32_libid_type="x86 archive static";; + esac + fi + ;; + *DLL*) + win32_libid_type="x86 DLL" + ;; + *executable*) # but shell scripts are "executable" too... + case $win32_fileres in + *MS\ Windows\ PE\ Intel*) + win32_libid_type="x86 DLL" + ;; + esac + ;; + esac + $ECHO "$win32_libid_type" +} + + + +# func_extract_an_archive dir oldlib +func_extract_an_archive () +{ + $opt_debug + f_ex_an_ar_dir="$1"; shift + f_ex_an_ar_oldlib="$1" + func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" 'exit $?' + if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then + : + else + func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" + fi +} + + +# func_extract_archives gentop oldlib ... +func_extract_archives () +{ + $opt_debug + my_gentop="$1"; shift + my_oldlibs=${1+"$@"} + my_oldobjs="" + my_xlib="" + my_xabs="" + my_xdir="" + + for my_xlib in $my_oldlibs; do + # Extract the objects. + case $my_xlib in + [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; + *) my_xabs=`pwd`"/$my_xlib" ;; + esac + func_basename "$my_xlib" + my_xlib="$func_basename_result" + my_xlib_u=$my_xlib + while :; do + case " $extracted_archives " in + *" $my_xlib_u "*) + func_arith $extracted_serial + 1 + extracted_serial=$func_arith_result + my_xlib_u=lt$extracted_serial-$my_xlib ;; + *) break ;; + esac + done + extracted_archives="$extracted_archives $my_xlib_u" + my_xdir="$my_gentop/$my_xlib_u" + + func_mkdir_p "$my_xdir" + + case $host in + *-darwin*) + func_verbose "Extracting $my_xabs" + # Do not bother doing anything if just a dry run + $opt_dry_run || { + darwin_orig_dir=`pwd` + cd $my_xdir || exit $? + darwin_archive=$my_xabs + darwin_curdir=`pwd` + darwin_base_archive=`basename "$darwin_archive"` + darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` + if test -n "$darwin_arches"; then + darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` + darwin_arch= + func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" + for darwin_arch in $darwin_arches ; do + func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}" + $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" + cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" + func_extract_an_archive "`pwd`" "${darwin_base_archive}" + cd "$darwin_curdir" + $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" + done # $darwin_arches + ## Okay now we've a bunch of thin objects, gotta fatten them up :) + darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u` + darwin_file= + darwin_files= + for darwin_file in $darwin_filelist; do + darwin_files=`find unfat-$$ -name $darwin_file -print | $NL2SP` + $LIPO -create -output "$darwin_file" $darwin_files + done # $darwin_filelist + $RM -rf unfat-$$ + cd "$darwin_orig_dir" + else + cd $darwin_orig_dir + func_extract_an_archive "$my_xdir" "$my_xabs" + fi # $darwin_arches + } # !$opt_dry_run + ;; + *) + func_extract_an_archive "$my_xdir" "$my_xabs" + ;; + esac + my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP` + done + + func_extract_archives_result="$my_oldobjs" +} + + + +# func_emit_wrapper_part1 [arg=no] +# +# Emit the first part of a libtool wrapper script on stdout. +# For more information, see the description associated with +# func_emit_wrapper(), below. +func_emit_wrapper_part1 () +{ + func_emit_wrapper_part1_arg1=no + if test -n "$1" ; then + func_emit_wrapper_part1_arg1=$1 + fi + + $ECHO "\ +#! $SHELL + +# $output - temporary wrapper script for $objdir/$outputname +# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION +# +# The $output program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of the build directory. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='${SED} -e 1s/^X//' +sed_quote_subst='$sed_quote_subst' + +# Be Bourne compatible +if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +relink_command=\"$relink_command\" + +# This environment variable determines our operation mode. +if test \"\$libtool_install_magic\" = \"$magic\"; then + # install mode needs the following variables: + generated_by_libtool_version='$macro_version' + notinst_deplibs='$notinst_deplibs' +else + # When we are sourced in execute mode, \$file and \$ECHO are already set. + if test \"\$libtool_execute_magic\" != \"$magic\"; then + ECHO=\"$qecho\" + file=\"\$0\" + # Make sure echo works. + if test \"X\$1\" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift + elif test \"X\`{ \$ECHO '\t'; } 2>/dev/null\`\" = 'X\t'; then + # Yippee, \$ECHO works! + : + else + # Restart under the correct shell, and then maybe \$ECHO will work. + exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"} + fi + fi\ +" + $ECHO "\ + + # Find the directory that this script lives in. + thisdir=\`\$ECHO \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\` + test \"x\$thisdir\" = \"x\$file\" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\` + while test -n \"\$file\"; do + destdir=\`\$ECHO \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\` + + # If there was a directory component, then change thisdir. + if test \"x\$destdir\" != \"x\$file\"; then + case \"\$destdir\" in + [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; + *) thisdir=\"\$thisdir/\$destdir\" ;; + esac + fi + + file=\`\$ECHO \"X\$file\" | \$Xsed -e 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\` + done +" +} +# end: func_emit_wrapper_part1 + +# func_emit_wrapper_part2 [arg=no] +# +# Emit the second part of a libtool wrapper script on stdout. +# For more information, see the description associated with +# func_emit_wrapper(), below. +func_emit_wrapper_part2 () +{ + func_emit_wrapper_part2_arg1=no + if test -n "$1" ; then + func_emit_wrapper_part2_arg1=$1 + fi + + $ECHO "\ + + # Usually 'no', except on cygwin/mingw when embedded into + # the cwrapper. + WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_part2_arg1 + if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then + # special case for '.' + if test \"\$thisdir\" = \".\"; then + thisdir=\`pwd\` + fi + # remove .libs from thisdir + case \"\$thisdir\" in + *[\\\\/]$objdir ) thisdir=\`\$ECHO \"X\$thisdir\" | \$Xsed -e 's%[\\\\/][^\\\\/]*$%%'\` ;; + $objdir ) thisdir=. ;; + esac + fi + + # Try to get the absolute directory name. + absdir=\`cd \"\$thisdir\" && pwd\` + test -n \"\$absdir\" && thisdir=\"\$absdir\" +" + + if test "$fast_install" = yes; then + $ECHO "\ + program=lt-'$outputname'$exeext + progdir=\"\$thisdir/$objdir\" + + if test ! -f \"\$progdir/\$program\" || + { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ + test \"X\$file\" != \"X\$progdir/\$program\"; }; then + + file=\"\$\$-\$program\" + + if test ! -d \"\$progdir\"; then + $MKDIR \"\$progdir\" + else + $RM \"\$progdir/\$file\" + fi" + + $ECHO "\ + + # relink executable if necessary + if test -n \"\$relink_command\"; then + if relink_command_output=\`eval \$relink_command 2>&1\`; then : + else + $ECHO \"\$relink_command_output\" >&2 + $RM \"\$progdir/\$file\" + exit 1 + fi + fi + + $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || + { $RM \"\$progdir/\$program\"; + $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } + $RM \"\$progdir/\$file\" + fi" + else + $ECHO "\ + program='$outputname' + progdir=\"\$thisdir/$objdir\" +" + fi + + $ECHO "\ + + if test -f \"\$progdir/\$program\"; then" + + # Export our shlibpath_var if we have one. + if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + $ECHO "\ + # Add our own library path to $shlibpath_var + $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" + + # Some systems cannot cope with colon-terminated $shlibpath_var + # The second colon is a workaround for a bug in BeOS R4 sed + $shlibpath_var=\`\$ECHO \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\` + + export $shlibpath_var +" + fi + + # fixup the dll searchpath if we need to. + if test -n "$dllsearchpath"; then + $ECHO "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + + $ECHO "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. +" + case $host in + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2* | *-cegcc*) + $ECHO "\ + exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} +" + ;; + + *) + $ECHO "\ + exec \"\$progdir/\$program\" \${1+\"\$@\"} +" + ;; + esac + $ECHO "\ + \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 + exit 1 + fi + else + # The program doesn't exist. + \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 + \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 + $ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 + exit 1 + fi +fi\ +" +} +# end: func_emit_wrapper_part2 + + +# func_emit_wrapper [arg=no] +# +# Emit a libtool wrapper script on stdout. +# Don't directly open a file because we may want to +# incorporate the script contents within a cygwin/mingw +# wrapper executable. Must ONLY be called from within +# func_mode_link because it depends on a number of variables +# set therein. +# +# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR +# variable will take. If 'yes', then the emitted script +# will assume that the directory in which it is stored is +# the $objdir directory. This is a cygwin/mingw-specific +# behavior. +func_emit_wrapper () +{ + func_emit_wrapper_arg1=no + if test -n "$1" ; then + func_emit_wrapper_arg1=$1 + fi + + # split this up so that func_emit_cwrapperexe_src + # can call each part independently. + func_emit_wrapper_part1 "${func_emit_wrapper_arg1}" + func_emit_wrapper_part2 "${func_emit_wrapper_arg1}" +} + + +# func_to_host_path arg +# +# Convert paths to host format when used with build tools. +# Intended for use with "native" mingw (where libtool itself +# is running under the msys shell), or in the following cross- +# build environments: +# $build $host +# mingw (msys) mingw [e.g. native] +# cygwin mingw +# *nix + wine mingw +# where wine is equipped with the `winepath' executable. +# In the native mingw case, the (msys) shell automatically +# converts paths for any non-msys applications it launches, +# but that facility isn't available from inside the cwrapper. +# Similar accommodations are necessary for $host mingw and +# $build cygwin. Calling this function does no harm for other +# $host/$build combinations not listed above. +# +# ARG is the path (on $build) that should be converted to +# the proper representation for $host. The result is stored +# in $func_to_host_path_result. +func_to_host_path () +{ + func_to_host_path_result="$1" + if test -n "$1" ; then + case $host in + *mingw* ) + lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' + case $build in + *mingw* ) # actually, msys + # awkward: cmd appends spaces to result + lt_sed_strip_trailing_spaces="s/[ ]*\$//" + func_to_host_path_tmp1=`( cmd //c echo "$1" |\ + $SED -e "$lt_sed_strip_trailing_spaces" ) 2>/dev/null || echo ""` + func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\ + $SED -e "$lt_sed_naive_backslashify"` + ;; + *cygwin* ) + func_to_host_path_tmp1=`cygpath -w "$1"` + func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\ + $SED -e "$lt_sed_naive_backslashify"` + ;; + * ) + # Unfortunately, winepath does not exit with a non-zero + # error code, so we are forced to check the contents of + # stdout. On the other hand, if the command is not + # found, the shell will set an exit code of 127 and print + # *an error message* to stdout. So we must check for both + # error code of zero AND non-empty stdout, which explains + # the odd construction: + func_to_host_path_tmp1=`winepath -w "$1" 2>/dev/null` + if test "$?" -eq 0 && test -n "${func_to_host_path_tmp1}"; then + func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\ + $SED -e "$lt_sed_naive_backslashify"` + else + # Allow warning below. + func_to_host_path_result="" + fi + ;; + esac + if test -z "$func_to_host_path_result" ; then + func_error "Could not determine host path corresponding to" + func_error " '$1'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback: + func_to_host_path_result="$1" + fi + ;; + esac + fi +} +# end: func_to_host_path + +# func_to_host_pathlist arg +# +# Convert pathlists to host format when used with build tools. +# See func_to_host_path(), above. This function supports the +# following $build/$host combinations (but does no harm for +# combinations not listed here): +# $build $host +# mingw (msys) mingw [e.g. native] +# cygwin mingw +# *nix + wine mingw +# +# Path separators are also converted from $build format to +# $host format. If ARG begins or ends with a path separator +# character, it is preserved (but converted to $host format) +# on output. +# +# ARG is a pathlist (on $build) that should be converted to +# the proper representation on $host. The result is stored +# in $func_to_host_pathlist_result. +func_to_host_pathlist () +{ + func_to_host_pathlist_result="$1" + if test -n "$1" ; then + case $host in + *mingw* ) + lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' + # Remove leading and trailing path separator characters from + # ARG. msys behavior is inconsistent here, cygpath turns them + # into '.;' and ';.', and winepath ignores them completely. + func_to_host_pathlist_tmp2="$1" + # Once set for this call, this variable should not be + # reassigned. It is used in tha fallback case. + func_to_host_pathlist_tmp1=`echo "$func_to_host_pathlist_tmp2" |\ + $SED -e 's|^:*||' -e 's|:*$||'` + case $build in + *mingw* ) # Actually, msys. + # Awkward: cmd appends spaces to result. + lt_sed_strip_trailing_spaces="s/[ ]*\$//" + func_to_host_pathlist_tmp2=`( cmd //c echo "$func_to_host_pathlist_tmp1" |\ + $SED -e "$lt_sed_strip_trailing_spaces" ) 2>/dev/null || echo ""` + func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp2" |\ + $SED -e "$lt_sed_naive_backslashify"` + ;; + *cygwin* ) + func_to_host_pathlist_tmp2=`cygpath -w -p "$func_to_host_pathlist_tmp1"` + func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp2" |\ + $SED -e "$lt_sed_naive_backslashify"` + ;; + * ) + # unfortunately, winepath doesn't convert pathlists + func_to_host_pathlist_result="" + func_to_host_pathlist_oldIFS=$IFS + IFS=: + for func_to_host_pathlist_f in $func_to_host_pathlist_tmp1 ; do + IFS=$func_to_host_pathlist_oldIFS + if test -n "$func_to_host_pathlist_f" ; then + func_to_host_path "$func_to_host_pathlist_f" + if test -n "$func_to_host_path_result" ; then + if test -z "$func_to_host_pathlist_result" ; then + func_to_host_pathlist_result="$func_to_host_path_result" + else + func_to_host_pathlist_result="$func_to_host_pathlist_result;$func_to_host_path_result" + fi + fi + fi + IFS=: + done + IFS=$func_to_host_pathlist_oldIFS + ;; + esac + if test -z "$func_to_host_pathlist_result" ; then + func_error "Could not determine the host path(s) corresponding to" + func_error " '$1'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback. This may break if $1 contains DOS-style drive + # specifications. The fix is not to complicate the expression + # below, but for the user to provide a working wine installation + # with winepath so that path translation in the cross-to-mingw + # case works properly. + lt_replace_pathsep_nix_to_dos="s|:|;|g" + func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp1" |\ + $SED -e "$lt_replace_pathsep_nix_to_dos"` + fi + # Now, add the leading and trailing path separators back + case "$1" in + :* ) func_to_host_pathlist_result=";$func_to_host_pathlist_result" + ;; + esac + case "$1" in + *: ) func_to_host_pathlist_result="$func_to_host_pathlist_result;" + ;; + esac + ;; + esac + fi +} +# end: func_to_host_pathlist + +# func_emit_cwrapperexe_src +# emit the source code for a wrapper executable on stdout +# Must ONLY be called from within func_mode_link because +# it depends on a number of variable set therein. +func_emit_cwrapperexe_src () +{ + cat < +#include +#ifdef _MSC_VER +# include +# include +# include +# define setmode _setmode +#else +# include +# include +# ifdef __CYGWIN__ +# include +# define HAVE_SETENV +# ifdef __STRICT_ANSI__ +char *realpath (const char *, char *); +int putenv (char *); +int setenv (const char *, const char *, int); +# endif +# endif +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(PATH_MAX) +# define LT_PATHMAX PATH_MAX +#elif defined(MAXPATHLEN) +# define LT_PATHMAX MAXPATHLEN +#else +# define LT_PATHMAX 1024 +#endif + +#ifndef S_IXOTH +# define S_IXOTH 0 +#endif +#ifndef S_IXGRP +# define S_IXGRP 0 +#endif + +#ifdef _MSC_VER +# define S_IXUSR _S_IEXEC +# define stat _stat +# ifndef _INTPTR_T_DEFINED +# define intptr_t int +# endif +#endif + +#ifndef DIR_SEPARATOR +# define DIR_SEPARATOR '/' +# define PATH_SEPARATOR ':' +#endif + +#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ + defined (__OS2__) +# define HAVE_DOS_BASED_FILE_SYSTEM +# define FOPEN_WB "wb" +# ifndef DIR_SEPARATOR_2 +# define DIR_SEPARATOR_2 '\\' +# endif +# ifndef PATH_SEPARATOR_2 +# define PATH_SEPARATOR_2 ';' +# endif +#endif + +#ifndef DIR_SEPARATOR_2 +# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) +#else /* DIR_SEPARATOR_2 */ +# define IS_DIR_SEPARATOR(ch) \ + (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) +#endif /* DIR_SEPARATOR_2 */ + +#ifndef PATH_SEPARATOR_2 +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) +#else /* PATH_SEPARATOR_2 */ +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) +#endif /* PATH_SEPARATOR_2 */ + +#ifdef __CYGWIN__ +# define FOPEN_WB "wb" +#endif + +#ifndef FOPEN_WB +# define FOPEN_WB "w" +#endif +#ifndef _O_BINARY +# define _O_BINARY 0 +#endif + +#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) +#define XFREE(stale) do { \ + if (stale) { free ((void *) stale); stale = 0; } \ +} while (0) + +#undef LTWRAPPER_DEBUGPRINTF +#if defined DEBUGWRAPPER +# define LTWRAPPER_DEBUGPRINTF(args) ltwrapper_debugprintf args +static void +ltwrapper_debugprintf (const char *fmt, ...) +{ + va_list args; + va_start (args, fmt); + (void) vfprintf (stderr, fmt, args); + va_end (args); +} +#else +# define LTWRAPPER_DEBUGPRINTF(args) +#endif + +const char *program_name = NULL; + +void *xmalloc (size_t num); +char *xstrdup (const char *string); +const char *base_name (const char *name); +char *find_executable (const char *wrapper); +char *chase_symlinks (const char *pathspec); +int make_executable (const char *path); +int check_executable (const char *path); +char *strendzap (char *str, const char *pat); +void lt_fatal (const char *message, ...); +void lt_setenv (const char *name, const char *value); +char *lt_extend_str (const char *orig_value, const char *add, int to_end); +void lt_opt_process_env_set (const char *arg); +void lt_opt_process_env_prepend (const char *arg); +void lt_opt_process_env_append (const char *arg); +int lt_split_name_value (const char *arg, char** name, char** value); +void lt_update_exe_path (const char *name, const char *value); +void lt_update_lib_path (const char *name, const char *value); + +static const char *script_text_part1 = +EOF + + func_emit_wrapper_part1 yes | + $SED -e 's/\([\\"]\)/\\\1/g' \ + -e 's/^/ "/' -e 's/$/\\n"/' + echo ";" + cat <"))); + for (i = 0; i < newargc; i++) + { + LTWRAPPER_DEBUGPRINTF (("(main) newargz[%d] : %s\n", i, (newargz[i] ? newargz[i] : ""))); + } + +EOF + + case $host_os in + mingw*) + cat <<"EOF" + /* execv doesn't actually work on mingw as expected on unix */ + rval = _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz); + if (rval == -1) + { + /* failed to start process */ + LTWRAPPER_DEBUGPRINTF (("(main) failed to launch target \"%s\": errno = %d\n", lt_argv_zero, errno)); + return 127; + } + return rval; +EOF + ;; + *) + cat <<"EOF" + execv (lt_argv_zero, newargz); + return rval; /* =127, but avoids unused variable warning */ +EOF + ;; + esac + + cat <<"EOF" +} + +void * +xmalloc (size_t num) +{ + void *p = (void *) malloc (num); + if (!p) + lt_fatal ("Memory exhausted"); + + return p; +} + +char * +xstrdup (const char *string) +{ + return string ? strcpy ((char *) xmalloc (strlen (string) + 1), + string) : NULL; +} + +const char * +base_name (const char *name) +{ + const char *base; + +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + /* Skip over the disk name in MSDOS pathnames. */ + if (isalpha ((unsigned char) name[0]) && name[1] == ':') + name += 2; +#endif + + for (base = name; *name; name++) + if (IS_DIR_SEPARATOR (*name)) + base = name + 1; + return base; +} + +int +check_executable (const char *path) +{ + struct stat st; + + LTWRAPPER_DEBUGPRINTF (("(check_executable) : %s\n", + path ? (*path ? path : "EMPTY!") : "NULL!")); + if ((!path) || (!*path)) + return 0; + + if ((stat (path, &st) >= 0) + && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) + return 1; + else + return 0; +} + +int +make_executable (const char *path) +{ + int rval = 0; + struct stat st; + + LTWRAPPER_DEBUGPRINTF (("(make_executable) : %s\n", + path ? (*path ? path : "EMPTY!") : "NULL!")); + if ((!path) || (!*path)) + return 0; + + if (stat (path, &st) >= 0) + { + rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); + } + return rval; +} + +/* Searches for the full path of the wrapper. Returns + newly allocated full path name if found, NULL otherwise + Does not chase symlinks, even on platforms that support them. +*/ +char * +find_executable (const char *wrapper) +{ + int has_slash = 0; + const char *p; + const char *p_next; + /* static buffer for getcwd */ + char tmp[LT_PATHMAX + 1]; + int tmp_len; + char *concat_name; + + LTWRAPPER_DEBUGPRINTF (("(find_executable) : %s\n", + wrapper ? (*wrapper ? wrapper : "EMPTY!") : "NULL!")); + + if ((wrapper == NULL) || (*wrapper == '\0')) + return NULL; + + /* Absolute path? */ +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') + { + concat_name = xstrdup (wrapper); + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } + else + { +#endif + if (IS_DIR_SEPARATOR (wrapper[0])) + { + concat_name = xstrdup (wrapper); + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + } +#endif + + for (p = wrapper; *p; p++) + if (*p == '/') + { + has_slash = 1; + break; + } + if (!has_slash) + { + /* no slashes; search PATH */ + const char *path = getenv ("PATH"); + if (path != NULL) + { + for (p = path; *p; p = p_next) + { + const char *q; + size_t p_len; + for (q = p; *q; q++) + if (IS_PATH_SEPARATOR (*q)) + break; + p_len = q - p; + p_next = (*q == '\0' ? q : q + 1); + if (p_len == 0) + { + /* empty path: current directory */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal ("getcwd failed"); + tmp_len = strlen (tmp); + concat_name = + XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + } + else + { + concat_name = + XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, p, p_len); + concat_name[p_len] = '/'; + strcpy (concat_name + p_len + 1, wrapper); + } + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } + } + /* not found in PATH; assume curdir */ + } + /* Relative path | not found in path: prepend cwd */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal ("getcwd failed"); + tmp_len = strlen (tmp); + concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + return NULL; +} + +char * +chase_symlinks (const char *pathspec) +{ +#ifndef S_ISLNK + return xstrdup (pathspec); +#else + char buf[LT_PATHMAX]; + struct stat s; + char *tmp_pathspec = xstrdup (pathspec); + char *p; + int has_symlinks = 0; + while (strlen (tmp_pathspec) && !has_symlinks) + { + LTWRAPPER_DEBUGPRINTF (("checking path component for symlinks: %s\n", + tmp_pathspec)); + if (lstat (tmp_pathspec, &s) == 0) + { + if (S_ISLNK (s.st_mode) != 0) + { + has_symlinks = 1; + break; + } + + /* search backwards for last DIR_SEPARATOR */ + p = tmp_pathspec + strlen (tmp_pathspec) - 1; + while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + p--; + if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + { + /* no more DIR_SEPARATORS left */ + break; + } + *p = '\0'; + } + else + { + char *errstr = strerror (errno); + lt_fatal ("Error accessing file %s (%s)", tmp_pathspec, errstr); + } + } + XFREE (tmp_pathspec); + + if (!has_symlinks) + { + return xstrdup (pathspec); + } + + tmp_pathspec = realpath (pathspec, buf); + if (tmp_pathspec == 0) + { + lt_fatal ("Could not follow symlinks for %s", pathspec); + } + return xstrdup (tmp_pathspec); +#endif +} + +char * +strendzap (char *str, const char *pat) +{ + size_t len, patlen; + + assert (str != NULL); + assert (pat != NULL); + + len = strlen (str); + patlen = strlen (pat); + + if (patlen <= len) + { + str += len - patlen; + if (strcmp (str, pat) == 0) + *str = '\0'; + } + return str; +} + +static void +lt_error_core (int exit_status, const char *mode, + const char *message, va_list ap) +{ + fprintf (stderr, "%s: %s: ", program_name, mode); + vfprintf (stderr, message, ap); + fprintf (stderr, ".\n"); + + if (exit_status >= 0) + exit (exit_status); +} + +void +lt_fatal (const char *message, ...) +{ + va_list ap; + va_start (ap, message); + lt_error_core (EXIT_FAILURE, "FATAL", message, ap); + va_end (ap); +} + +void +lt_setenv (const char *name, const char *value) +{ + LTWRAPPER_DEBUGPRINTF (("(lt_setenv) setting '%s' to '%s'\n", + (name ? name : ""), + (value ? value : ""))); + { +#ifdef HAVE_SETENV + /* always make a copy, for consistency with !HAVE_SETENV */ + char *str = xstrdup (value); + setenv (name, str, 1); +#else + int len = strlen (name) + 1 + strlen (value) + 1; + char *str = XMALLOC (char, len); + sprintf (str, "%s=%s", name, value); + if (putenv (str) != EXIT_SUCCESS) + { + XFREE (str); + } +#endif + } +} + +char * +lt_extend_str (const char *orig_value, const char *add, int to_end) +{ + char *new_value; + if (orig_value && *orig_value) + { + int orig_value_len = strlen (orig_value); + int add_len = strlen (add); + new_value = XMALLOC (char, add_len + orig_value_len + 1); + if (to_end) + { + strcpy (new_value, orig_value); + strcpy (new_value + orig_value_len, add); + } + else + { + strcpy (new_value, add); + strcpy (new_value + add_len, orig_value); + } + } + else + { + new_value = xstrdup (add); + } + return new_value; +} + +int +lt_split_name_value (const char *arg, char** name, char** value) +{ + const char *p; + int len; + if (!arg || !*arg) + return 1; + + p = strchr (arg, (int)'='); + + if (!p) + return 1; + + *value = xstrdup (++p); + + len = strlen (arg) - strlen (*value); + *name = XMALLOC (char, len); + strncpy (*name, arg, len-1); + (*name)[len - 1] = '\0'; + + return 0; +} + +void +lt_opt_process_env_set (const char *arg) +{ + char *name = NULL; + char *value = NULL; + + if (lt_split_name_value (arg, &name, &value) != 0) + { + XFREE (name); + XFREE (value); + lt_fatal ("bad argument for %s: '%s'", env_set_opt, arg); + } + + lt_setenv (name, value); + XFREE (name); + XFREE (value); +} + +void +lt_opt_process_env_prepend (const char *arg) +{ + char *name = NULL; + char *value = NULL; + char *new_value = NULL; + + if (lt_split_name_value (arg, &name, &value) != 0) + { + XFREE (name); + XFREE (value); + lt_fatal ("bad argument for %s: '%s'", env_prepend_opt, arg); + } + + new_value = lt_extend_str (getenv (name), value, 0); + lt_setenv (name, new_value); + XFREE (new_value); + XFREE (name); + XFREE (value); +} + +void +lt_opt_process_env_append (const char *arg) +{ + char *name = NULL; + char *value = NULL; + char *new_value = NULL; + + if (lt_split_name_value (arg, &name, &value) != 0) + { + XFREE (name); + XFREE (value); + lt_fatal ("bad argument for %s: '%s'", env_append_opt, arg); + } + + new_value = lt_extend_str (getenv (name), value, 1); + lt_setenv (name, new_value); + XFREE (new_value); + XFREE (name); + XFREE (value); +} + +void +lt_update_exe_path (const char *name, const char *value) +{ + LTWRAPPER_DEBUGPRINTF (("(lt_update_exe_path) modifying '%s' by prepending '%s'\n", + (name ? name : ""), + (value ? value : ""))); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + /* some systems can't cope with a ':'-terminated path #' */ + int len = strlen (new_value); + while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1])) + { + new_value[len-1] = '\0'; + } + lt_setenv (name, new_value); + XFREE (new_value); + } +} + +void +lt_update_lib_path (const char *name, const char *value) +{ + LTWRAPPER_DEBUGPRINTF (("(lt_update_lib_path) modifying '%s' by prepending '%s'\n", + (name ? name : ""), + (value ? value : ""))); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + lt_setenv (name, new_value); + XFREE (new_value); + } +} + + +EOF +} +# end: func_emit_cwrapperexe_src + +# func_mode_link arg... +func_mode_link () +{ + $opt_debug + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + # It is impossible to link a dll without this setting, and + # we shouldn't force the makefile maintainer to figure out + # which system we are compiling for in order to pass an extra + # flag for every libtool invocation. + # allow_undefined=no + + # FIXME: Unfortunately, there are problems with the above when trying + # to make a dll which has undefined symbols, in which case not + # even a static library is built. For now, we need to specify + # -no-undefined on the libtool link line when we can be certain + # that all symbols are satisfied, otherwise we get a static library. + allow_undefined=yes + ;; + *) + allow_undefined=yes + ;; + esac + libtool_args=$nonopt + base_compile="$nonopt $@" + compile_command=$nonopt + finalize_command=$nonopt + + compile_rpath= + finalize_rpath= + compile_shlibpath= + finalize_shlibpath= + convenience= + old_convenience= + deplibs= + old_deplibs= + compiler_flags= + linker_flags= + dllsearchpath= + lib_search_path=`pwd` + inst_prefix_dir= + new_inherited_linker_flags= + + avoid_version=no + dlfiles= + dlprefiles= + dlself=no + export_dynamic=no + export_symbols= + export_symbols_regex= + generated= + libobjs= + ltlibs= + module=no + no_install=no + objs= + non_pic_objects= + precious_files_regex= + prefer_static_libs=no + preload=no + prev= + prevarg= + release= + rpath= + xrpath= + perm_rpath= + temp_rpath= + thread_safe=no + vinfo= + vinfo_number=no + weak_libs= + single_module="${wl}-single_module" + func_infer_tag $base_compile + + # We need to know -static, to get the right output filenames. + for arg + do + case $arg in + -shared) + test "$build_libtool_libs" != yes && \ + func_fatal_configuration "can not build a shared library" + build_old_libs=no + break + ;; + -all-static | -static | -static-libtool-libs) + case $arg in + -all-static) + if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then + func_warning "complete static linking is impossible in this configuration" + fi + if test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + -static) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=built + ;; + -static-libtool-libs) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + esac + build_libtool_libs=no + build_old_libs=yes + break + ;; + esac + done + + # See if our shared archives depend on static archives. + test -n "$old_archive_from_new_cmds" && build_old_libs=yes + + # Go through the arguments, transforming them on the way. + while test "$#" -gt 0; do + arg="$1" + shift + func_quote_for_eval "$arg" + qarg=$func_quote_for_eval_unquoted_result + func_append libtool_args " $func_quote_for_eval_result" + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + output) + func_append compile_command " @OUTPUT@" + func_append finalize_command " @OUTPUT@" + ;; + esac + + case $prev in + dlfiles|dlprefiles) + if test "$preload" = no; then + # Add the symbol object into the linking commands. + func_append compile_command " @SYMFILE@" + func_append finalize_command " @SYMFILE@" + preload=yes + fi + case $arg in + *.la | *.lo) ;; # We handle these cases below. + force) + if test "$dlself" = no; then + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + self) + if test "$prev" = dlprefiles; then + dlself=yes + elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then + dlself=yes + else + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + *) + if test "$prev" = dlfiles; then + dlfiles="$dlfiles $arg" + else + dlprefiles="$dlprefiles $arg" + fi + prev= + continue + ;; + esac + ;; + expsyms) + export_symbols="$arg" + test -f "$arg" \ + || func_fatal_error "symbol file \`$arg' does not exist" + prev= + continue + ;; + expsyms_regex) + export_symbols_regex="$arg" + prev= + continue + ;; + framework) + case $host in + *-*-darwin*) + case "$deplibs " in + *" $qarg.ltframework "*) ;; + *) deplibs="$deplibs $qarg.ltframework" # this is fixed later + ;; + esac + ;; + esac + prev= + continue + ;; + inst_prefix) + inst_prefix_dir="$arg" + prev= + continue + ;; + objectlist) + if test -f "$arg"; then + save_arg=$arg + moreargs= + for fil in `cat "$save_arg"` + do +# moreargs="$moreargs $fil" + arg=$fil + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test "$pic_object" = none && + test "$non_pic_object" = none; then + func_fatal_error "cannot find name of object for \`$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "\`$arg' is not a valid libtool object" + fi + fi + done + else + func_fatal_error "link input file \`$arg' does not exist" + fi + arg=$save_arg + prev= + continue + ;; + precious_regex) + precious_files_regex="$arg" + prev= + continue + ;; + release) + release="-$arg" + prev= + continue + ;; + rpath | xrpath) + # We need an absolute path. + case $arg in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + if test "$prev" = rpath; then + case "$rpath " in + *" $arg "*) ;; + *) rpath="$rpath $arg" ;; + esac + else + case "$xrpath " in + *" $arg "*) ;; + *) xrpath="$xrpath $arg" ;; + esac + fi + prev= + continue + ;; + shrext) + shrext_cmds="$arg" + prev= + continue + ;; + weak) + weak_libs="$weak_libs $arg" + prev= + continue + ;; + xcclinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xcompiler) + compiler_flags="$compiler_flags $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xlinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $wl$qarg" + prev= + func_append compile_command " $wl$qarg" + func_append finalize_command " $wl$qarg" + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi # test -n "$prev" + + prevarg="$arg" + + case $arg in + -all-static) + if test -n "$link_static_flag"; then + # See comment for -static flag below, for more details. + func_append compile_command " $link_static_flag" + func_append finalize_command " $link_static_flag" + fi + continue + ;; + + -allow-undefined) + # FIXME: remove this flag sometime in the future. + func_fatal_error "\`-allow-undefined' must not be used because it is the default" + ;; + + -avoid-version) + avoid_version=yes + continue + ;; + + -dlopen) + prev=dlfiles + continue + ;; + + -dlpreopen) + prev=dlprefiles + continue + ;; + + -export-dynamic) + export_dynamic=yes + continue + ;; + + -export-symbols | -export-symbols-regex) + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + func_fatal_error "more than one -exported-symbols argument is not allowed" + fi + if test "X$arg" = "X-export-symbols"; then + prev=expsyms + else + prev=expsyms_regex + fi + continue + ;; + + -framework) + prev=framework + continue + ;; + + -inst-prefix-dir) + prev=inst_prefix + continue + ;; + + # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* + # so, if we see these flags be careful not to treat them like -L + -L[A-Z][A-Z]*:*) + case $with_gcc/$host in + no/*-*-irix* | /*-*-irix*) + func_append compile_command " $arg" + func_append finalize_command " $arg" + ;; + esac + continue + ;; + + -L*) + func_stripname '-L' '' "$arg" + dir=$func_stripname_result + if test -z "$dir"; then + if test "$#" -gt 0; then + func_fatal_error "require no space between \`-L' and \`$1'" + else + func_fatal_error "need path for \`-L' option" + fi + fi + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + absdir=`cd "$dir" && pwd` + test -z "$absdir" && \ + func_fatal_error "cannot determine absolute directory name of \`$dir'" + dir="$absdir" + ;; + esac + case "$deplibs " in + *" -L$dir "*) ;; + *) + deplibs="$deplibs -L$dir" + lib_search_path="$lib_search_path $dir" + ;; + esac + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`$ECHO "X$dir" | $Xsed -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$dir:"*) ;; + ::) dllsearchpath=$dir;; + *) dllsearchpath="$dllsearchpath:$dir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) dllsearchpath="$dllsearchpath:$testbindir";; + esac + ;; + esac + continue + ;; + + -l*) + if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc*) + # These systems don't actually have a C or math library (as such) + continue + ;; + *-*-os2*) + # These systems don't actually have a C library (as such) + test "X$arg" = "X-lc" && continue + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + test "X$arg" = "X-lc" && continue + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C and math libraries are in the System framework + deplibs="$deplibs System.ltframework" + continue + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + test "X$arg" = "X-lc" && continue + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + test "X$arg" = "X-lc" && continue + ;; + esac + elif test "X$arg" = "X-lc_r"; then + case $host in + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc_r directly, use -pthread flag. + continue + ;; + esac + fi + deplibs="$deplibs $arg" + continue + ;; + + -module) + module=yes + continue + ;; + + # Tru64 UNIX uses -model [arg] to determine the layout of C++ + # classes, name mangling, and exception handling. + # Darwin uses the -arch flag to determine output architecture. + -model|-arch|-isysroot) + compiler_flags="$compiler_flags $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + prev=xcompiler + continue + ;; + + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) + compiler_flags="$compiler_flags $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + case "$new_inherited_linker_flags " in + *" $arg "*) ;; + * ) new_inherited_linker_flags="$new_inherited_linker_flags $arg" ;; + esac + continue + ;; + + -multi_module) + single_module="${wl}-multi_module" + continue + ;; + + -no-fast-install) + fast_install=no + continue + ;; + + -no-install) + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) + # The PATH hackery in wrapper scripts is required on Windows + # and Darwin in order for the loader to find any dlls it needs. + func_warning "\`-no-install' is ignored for $host" + func_warning "assuming \`-no-fast-install' instead" + fast_install=no + ;; + *) no_install=yes ;; + esac + continue + ;; + + -no-undefined) + allow_undefined=no + continue + ;; + + -objectlist) + prev=objectlist + continue + ;; + + -o) prev=output ;; + + -precious-files-regex) + prev=precious_regex + continue + ;; + + -release) + prev=release + continue + ;; + + -rpath) + prev=rpath + continue + ;; + + -R) + prev=xrpath + continue + ;; + + -R*) + func_stripname '-R' '' "$arg" + dir=$func_stripname_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + continue + ;; + + -shared) + # The effects of -shared are defined in a previous loop. + continue + ;; + + -shrext) + prev=shrext + continue + ;; + + -static | -static-libtool-libs) + # The effects of -static are defined in a previous loop. + # We used to do the same as -all-static on platforms that + # didn't have a PIC flag, but the assumption that the effects + # would be equivalent was wrong. It would break on at least + # Digital Unix and AIX. + continue + ;; + + -thread-safe) + thread_safe=yes + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + + -version-number) + prev=vinfo + vinfo_number=yes + continue + ;; + + -weak) + prev=weak + continue + ;; + + -Wc,*) + func_stripname '-Wc,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + func_quote_for_eval "$flag" + arg="$arg $wl$func_quote_for_eval_result" + compiler_flags="$compiler_flags $func_quote_for_eval_result" + done + IFS="$save_ifs" + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Wl,*) + func_stripname '-Wl,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + func_quote_for_eval "$flag" + arg="$arg $wl$func_quote_for_eval_result" + compiler_flags="$compiler_flags $wl$func_quote_for_eval_result" + linker_flags="$linker_flags $func_quote_for_eval_result" + done + IFS="$save_ifs" + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Xcompiler) + prev=xcompiler + continue + ;; + + -Xlinker) + prev=xlinker + continue + ;; + + -XCClinker) + prev=xcclinker + continue + ;; + + # -msg_* for osf cc + -msg_*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + + # -64, -mips[0-9] enable 64-bit mode on the SGI compiler + # -r[0-9][0-9]* specifies the processor on the SGI compiler + # -xarch=*, -xtarget=* enable 64-bit mode on the Sun compiler + # +DA*, +DD* enable 64-bit mode on the HP compiler + # -q* pass through compiler args for the IBM compiler + # -m*, -t[45]*, -txscale* pass through architecture-specific + # compiler args for GCC + # -F/path gives path to uninstalled frameworks, gcc on darwin + # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC + # @file GCC response files + -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ + -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + func_append compile_command " $arg" + func_append finalize_command " $arg" + compiler_flags="$compiler_flags $arg" + continue + ;; + + # Some other compiler flag. + -* | +*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + + *.$objext) + # A standard object. + objs="$objs $arg" + ;; + + *.lo) + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test "$pic_object" = none && + test "$non_pic_object" = none; then + func_fatal_error "cannot find name of object for \`$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "\`$arg' is not a valid libtool object" + fi + fi + ;; + + *.$libext) + # An archive. + deplibs="$deplibs $arg" + old_deplibs="$old_deplibs $arg" + continue + ;; + + *.la) + # A libtool-controlled library. + + if test "$prev" = dlfiles; then + # This library was specified with -dlopen. + dlfiles="$dlfiles $arg" + prev= + elif test "$prev" = dlprefiles; then + # The library was specified with -dlpreopen. + dlprefiles="$dlprefiles $arg" + prev= + else + deplibs="$deplibs $arg" + fi + continue + ;; + + # Some other compiler argument. + *) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + esac # arg + + # Now actually substitute the argument into the commands. + if test -n "$arg"; then + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + done # argument parsing loop + + test -n "$prev" && \ + func_fatal_help "the \`$prevarg' option requires an argument" + + if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then + eval arg=\"$export_dynamic_flag_spec\" + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + + oldlibs= + # calculate the name of the file, without its directory + func_basename "$output" + outputname="$func_basename_result" + libobjs_save="$libobjs" + + if test -n "$shlibpath_var"; then + # get the directories listed in $shlibpath_var + eval shlib_search_path=\`\$ECHO \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\` + else + shlib_search_path= + fi + eval sys_lib_search_path=\"$sys_lib_search_path_spec\" + eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" + + func_dirname "$output" "/" "" + output_objdir="$func_dirname_result$objdir" + # Create the object directory. + func_mkdir_p "$output_objdir" + + # Determine the type of output + case $output in + "") + func_fatal_help "you must specify an output file" + ;; + *.$libext) linkmode=oldlib ;; + *.lo | *.$objext) linkmode=obj ;; + *.la) linkmode=lib ;; + *) linkmode=prog ;; # Anything else should be a program. + esac + + specialdeplibs= + + libs= + # Find all interdependent deplibs by searching for libraries + # that are linked more than once (e.g. -la -lb -la) + for deplib in $deplibs; do + if $opt_duplicate_deps ; then + case "$libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + libs="$libs $deplib" + done + + if test "$linkmode" = lib; then + libs="$predeps $libs $compiler_lib_search_path $postdeps" + + # Compute libraries that are listed more than once in $predeps + # $postdeps and mark them as special (i.e., whose duplicates are + # not to be eliminated). + pre_post_deps= + if $opt_duplicate_compiler_generated_deps; then + for pre_post_dep in $predeps $postdeps; do + case "$pre_post_deps " in + *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;; + esac + pre_post_deps="$pre_post_deps $pre_post_dep" + done + fi + pre_post_deps= + fi + + deplibs= + newdependency_libs= + newlib_search_path= + need_relink=no # whether we're linking any uninstalled libtool libraries + notinst_deplibs= # not-installed libtool libraries + notinst_path= # paths that contain not-installed libtool libraries + + case $linkmode in + lib) + passes="conv dlpreopen link" + for file in $dlfiles $dlprefiles; do + case $file in + *.la) ;; + *) + func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file" + ;; + esac + done + ;; + prog) + compile_deplibs= + finalize_deplibs= + alldeplibs=no + newdlfiles= + newdlprefiles= + passes="conv scan dlopen dlpreopen link" + ;; + *) passes="conv" + ;; + esac + + for pass in $passes; do + # The preopen pass in lib mode reverses $deplibs; put it back here + # so that -L comes before libs that need it for instance... + if test "$linkmode,$pass" = "lib,link"; then + ## FIXME: Find the place where the list is rebuilt in the wrong + ## order, and fix it there properly + tmp_deplibs= + for deplib in $deplibs; do + tmp_deplibs="$deplib $tmp_deplibs" + done + deplibs="$tmp_deplibs" + fi + + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan"; then + libs="$deplibs" + deplibs= + fi + if test "$linkmode" = prog; then + case $pass in + dlopen) libs="$dlfiles" ;; + dlpreopen) libs="$dlprefiles" ;; + link) + libs="$deplibs %DEPLIBS%" + test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs" + ;; + esac + fi + if test "$linkmode,$pass" = "lib,dlpreopen"; then + # Collect and forward deplibs of preopened libtool libs + for lib in $dlprefiles; do + # Ignore non-libtool-libs + dependency_libs= + case $lib in + *.la) func_source "$lib" ;; + esac + + # Collect preopened libtool deplibs, except any this library + # has declared as weak libs + for deplib in $dependency_libs; do + deplib_base=`$ECHO "X$deplib" | $Xsed -e "$basename"` + case " $weak_libs " in + *" $deplib_base "*) ;; + *) deplibs="$deplibs $deplib" ;; + esac + done + done + libs="$dlprefiles" + fi + if test "$pass" = dlopen; then + # Collect dlpreopened libraries + save_deplibs="$deplibs" + deplibs= + fi + + for deplib in $libs; do + lib= + found=no + case $deplib in + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + compiler_flags="$compiler_flags $deplib" + if test "$linkmode" = lib ; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;; + esac + fi + fi + continue + ;; + -l*) + if test "$linkmode" != lib && test "$linkmode" != prog; then + func_warning "\`-l' is ignored for archives/objects" + continue + fi + func_stripname '-l' '' "$deplib" + name=$func_stripname_result + if test "$linkmode" = lib; then + searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" + else + searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" + fi + for searchdir in $searchdirs; do + for search_ext in .la $std_shrext .so .a; do + # Search the libtool library + lib="$searchdir/lib${name}${search_ext}" + if test -f "$lib"; then + if test "$search_ext" = ".la"; then + found=yes + else + found=no + fi + break 2 + fi + done + done + if test "$found" != yes; then + # deplib doesn't seem to be a libtool library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + else # deplib is a libtool library + # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, + # We need to do some special things here, and not later. + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $deplib "*) + if func_lalib_p "$lib"; then + library_names= + old_library= + func_source "$lib" + for l in $old_library $library_names; do + ll="$l" + done + if test "X$ll" = "X$old_library" ; then # only static version available + found=no + func_dirname "$lib" "" "." + ladir="$func_dirname_result" + lib=$ladir/$old_library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + fi + ;; + *) ;; + esac + fi + fi + ;; # -l + *.ltframework) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + if test "$linkmode" = lib ; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;; + esac + fi + fi + continue + ;; + -L*) + case $linkmode in + lib) + deplibs="$deplib $deplibs" + test "$pass" = conv && continue + newdependency_libs="$deplib $newdependency_libs" + func_stripname '-L' '' "$deplib" + newlib_search_path="$newlib_search_path $func_stripname_result" + ;; + prog) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + if test "$pass" = scan; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + func_stripname '-L' '' "$deplib" + newlib_search_path="$newlib_search_path $func_stripname_result" + ;; + *) + func_warning "\`-L' is ignored for archives/objects" + ;; + esac # linkmode + continue + ;; # -L + -R*) + if test "$pass" = link; then + func_stripname '-R' '' "$deplib" + dir=$func_stripname_result + # Make sure the xrpath contains only unique directories. + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + fi + deplibs="$deplib $deplibs" + continue + ;; + *.la) lib="$deplib" ;; + *.$libext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + case $linkmode in + lib) + # Linking convenience modules into shared libraries is allowed, + # but linking other static libraries is non-portable. + case " $dlpreconveniencelibs " in + *" $deplib "*) ;; + *) + valid_a_lib=no + case $deplibs_check_method in + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + if eval "\$ECHO \"X$deplib\"" 2>/dev/null | $Xsed -e 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + valid_a_lib=yes + fi + ;; + pass_all) + valid_a_lib=yes + ;; + esac + if test "$valid_a_lib" != yes; then + $ECHO + $ECHO "*** Warning: Trying to link with static lib archive $deplib." + $ECHO "*** I have the capability to make that library automatically link in when" + $ECHO "*** you link to this library. But I can only do this if you have a" + $ECHO "*** shared version of the library, which you do not appear to have" + $ECHO "*** because the file extensions .$libext of this argument makes me believe" + $ECHO "*** that it is just a static archive that I should not use here." + else + $ECHO + $ECHO "*** Warning: Linking the shared library $output against the" + $ECHO "*** static library $deplib is not portable!" + deplibs="$deplib $deplibs" + fi + ;; + esac + continue + ;; + prog) + if test "$pass" != link; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + continue + ;; + esac # linkmode + ;; # *.$libext + *.lo | *.$objext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + elif test "$linkmode" = prog; then + if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then + # If there is no dlopen support or we're linking statically, + # we need to preload. + newdlprefiles="$newdlprefiles $deplib" + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + newdlfiles="$newdlfiles $deplib" + fi + fi + continue + ;; + %DEPLIBS%) + alldeplibs=yes + continue + ;; + esac # case $deplib + + if test "$found" = yes || test -f "$lib"; then : + else + func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'" + fi + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$lib" \ + || func_fatal_error "\`$lib' is not a valid libtool archive" + + func_dirname "$lib" "" "." + ladir="$func_dirname_result" + + dlname= + dlopen= + dlpreopen= + libdir= + library_names= + old_library= + inherited_linker_flags= + # If the library was installed with an old release of libtool, + # it will not redefine variables installed, or shouldnotlink + installed=yes + shouldnotlink=no + avoidtemprpath= + + + # Read the .la file + func_source "$lib" + + # Convert "-framework foo" to "foo.ltframework" + if test -n "$inherited_linker_flags"; then + tmp_inherited_linker_flags=`$ECHO "X$inherited_linker_flags" | $Xsed -e 's/-framework \([^ $]*\)/\1.ltframework/g'` + for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do + case " $new_inherited_linker_flags " in + *" $tmp_inherited_linker_flag "*) ;; + *) new_inherited_linker_flags="$new_inherited_linker_flags $tmp_inherited_linker_flag";; + esac + done + fi + dependency_libs=`$ECHO "X $dependency_libs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan" || + { test "$linkmode" != prog && test "$linkmode" != lib; }; then + test -n "$dlopen" && dlfiles="$dlfiles $dlopen" + test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen" + fi + + if test "$pass" = conv; then + # Only check for convenience libraries + deplibs="$lib $deplibs" + if test -z "$libdir"; then + if test -z "$old_library"; then + func_fatal_error "cannot find name of link library for \`$lib'" + fi + # It is a libtool convenience library, so add in its objects. + convenience="$convenience $ladir/$objdir/$old_library" + old_convenience="$old_convenience $ladir/$objdir/$old_library" + elif test "$linkmode" != prog && test "$linkmode" != lib; then + func_fatal_error "\`$lib' is not a convenience library" + fi + tmp_libs= + for deplib in $dependency_libs; do + deplibs="$deplib $deplibs" + if $opt_duplicate_deps ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done + continue + fi # $pass = conv + + + # Get the name of the library we link against. + linklib= + for l in $old_library $library_names; do + linklib="$l" + done + if test -z "$linklib"; then + func_fatal_error "cannot find name of link library for \`$lib'" + fi + + # This library was specified with -dlopen. + if test "$pass" = dlopen; then + if test -z "$libdir"; then + func_fatal_error "cannot -dlopen a convenience library: \`$lib'" + fi + if test -z "$dlname" || + test "$dlopen_support" != yes || + test "$build_libtool_libs" = no; then + # If there is no dlname, no dlopen support or we're linking + # statically, we need to preload. We also need to preload any + # dependent libraries so libltdl's deplib preloader doesn't + # bomb out in the load deplibs phase. + dlprefiles="$dlprefiles $lib $dependency_libs" + else + newdlfiles="$newdlfiles $lib" + fi + continue + fi # $pass = dlopen + + # We need an absolute path. + case $ladir in + [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; + *) + abs_ladir=`cd "$ladir" && pwd` + if test -z "$abs_ladir"; then + func_warning "cannot determine absolute directory name of \`$ladir'" + func_warning "passing it literally to the linker, although it might fail" + abs_ladir="$ladir" + fi + ;; + esac + func_basename "$lib" + laname="$func_basename_result" + + # Find the relevant object directory and library name. + if test "X$installed" = Xyes; then + if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then + func_warning "library \`$lib' was moved." + dir="$ladir" + absdir="$abs_ladir" + libdir="$abs_ladir" + else + dir="$libdir" + absdir="$libdir" + fi + test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes + else + if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then + dir="$ladir" + absdir="$abs_ladir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + else + dir="$ladir/$objdir" + absdir="$abs_ladir/$objdir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + fi + fi # $installed = yes + func_stripname 'lib' '.la' "$laname" + name=$func_stripname_result + + # This library was specified with -dlpreopen. + if test "$pass" = dlpreopen; then + if test -z "$libdir" && test "$linkmode" = prog; then + func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'" + fi + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + newdlprefiles="$newdlprefiles $dir/$old_library" + # Keep a list of preopened convenience libraries to check + # that they are being used correctly in the link pass. + test -z "$libdir" && \ + dlpreconveniencelibs="$dlpreconveniencelibs $dir/$old_library" + # Otherwise, use the dlname, so that lt_dlopen finds it. + elif test -n "$dlname"; then + newdlprefiles="$newdlprefiles $dir/$dlname" + else + newdlprefiles="$newdlprefiles $dir/$linklib" + fi + fi # $pass = dlpreopen + + if test -z "$libdir"; then + # Link the convenience library + if test "$linkmode" = lib; then + deplibs="$dir/$old_library $deplibs" + elif test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$dir/$old_library $compile_deplibs" + finalize_deplibs="$dir/$old_library $finalize_deplibs" + else + deplibs="$lib $deplibs" # used for prog,scan pass + fi + continue + fi + + + if test "$linkmode" = prog && test "$pass" != link; then + newlib_search_path="$newlib_search_path $ladir" + deplibs="$lib $deplibs" + + linkalldeplibs=no + if test "$link_all_deplibs" != no || test -z "$library_names" || + test "$build_libtool_libs" = no; then + linkalldeplibs=yes + fi + + tmp_libs= + for deplib in $dependency_libs; do + case $deplib in + -L*) func_stripname '-L' '' "$deplib" + newlib_search_path="$newlib_search_path $func_stripname_result" + ;; + esac + # Need to link against all dependency_libs? + if test "$linkalldeplibs" = yes; then + deplibs="$deplib $deplibs" + else + # Need to hardcode shared library paths + # or/and link against static libraries + newdependency_libs="$deplib $newdependency_libs" + fi + if $opt_duplicate_deps ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done # for deplib + continue + fi # $linkmode = prog... + + if test "$linkmode,$pass" = "prog,link"; then + if test -n "$library_names" && + { { test "$prefer_static_libs" = no || + test "$prefer_static_libs,$installed" = "built,yes"; } || + test -z "$old_library"; }; then + # We need to hardcode the library path + if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then + # Make sure the rpath contains only unique directories. + case "$temp_rpath:" in + *"$absdir:"*) ;; + *) temp_rpath="$temp_rpath$absdir:" ;; + esac + fi + + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + fi # $linkmode,$pass = prog,link... + + if test "$alldeplibs" = yes && + { test "$deplibs_check_method" = pass_all || + { test "$build_libtool_libs" = yes && + test -n "$library_names"; }; }; then + # We only need to search for static libraries + continue + fi + fi + + link_static=no # Whether the deplib will be linked statically + use_static_libs=$prefer_static_libs + if test "$use_static_libs" = built && test "$installed" = yes; then + use_static_libs=no + fi + if test -n "$library_names" && + { test "$use_static_libs" = no || test -z "$old_library"; }; then + case $host in + *cygwin* | *mingw* | *cegcc*) + # No point in relinking DLLs because paths are not encoded + notinst_deplibs="$notinst_deplibs $lib" + need_relink=no + ;; + *) + if test "$installed" = no; then + notinst_deplibs="$notinst_deplibs $lib" + need_relink=yes + fi + ;; + esac + # This is a shared library + + # Warn about portability, can't link against -module's on some + # systems (darwin). Don't bleat about dlopened modules though! + dlopenmodule="" + for dlpremoduletest in $dlprefiles; do + if test "X$dlpremoduletest" = "X$lib"; then + dlopenmodule="$dlpremoduletest" + break + fi + done + if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then + $ECHO + if test "$linkmode" = prog; then + $ECHO "*** Warning: Linking the executable $output against the loadable module" + else + $ECHO "*** Warning: Linking the shared library $output against the loadable module" + fi + $ECHO "*** $linklib is not portable!" + fi + if test "$linkmode" = lib && + test "$hardcode_into_libs" = yes; then + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + fi + + if test -n "$old_archive_from_expsyms_cmds"; then + # figure out the soname + set dummy $library_names + shift + realname="$1" + shift + libname=`eval "\\$ECHO \"$libname_spec\""` + # use dlname if we got it. it's perfectly good, no? + if test -n "$dlname"; then + soname="$dlname" + elif test -n "$soname_spec"; then + # bleh windows + case $host in + *cygwin* | mingw* | *cegcc*) + func_arith $current - $age + major=$func_arith_result + versuffix="-$major" + ;; + esac + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + + # Make a new name for the extract_expsyms_cmds to use + soroot="$soname" + func_basename "$soroot" + soname="$func_basename_result" + func_stripname 'lib' '.dll' "$soname" + newlib=libimp-$func_stripname_result.a + + # If the library has no export list, then create one now + if test -f "$output_objdir/$soname-def"; then : + else + func_verbose "extracting exported symbol list from \`$soname'" + func_execute_cmds "$extract_expsyms_cmds" 'exit $?' + fi + + # Create $newlib + if test -f "$output_objdir/$newlib"; then :; else + func_verbose "generating import library for \`$soname'" + func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' + fi + # make sure the library variables are pointing to the new library + dir=$output_objdir + linklib=$newlib + fi # test -n "$old_archive_from_expsyms_cmds" + + if test "$linkmode" = prog || test "$mode" != relink; then + add_shlibpath= + add_dir= + add= + lib_linked=yes + case $hardcode_action in + immediate | unsupported) + if test "$hardcode_direct" = no; then + add="$dir/$linklib" + case $host in + *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; + *-*-sysv4*uw2*) add_dir="-L$dir" ;; + *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ + *-*-unixware7*) add_dir="-L$dir" ;; + *-*-darwin* ) + # if the lib is a (non-dlopened) module then we can not + # link against it, someone is ignoring the earlier warnings + if /usr/bin/file -L $add 2> /dev/null | + $GREP ": [^:]* bundle" >/dev/null ; then + if test "X$dlopenmodule" != "X$lib"; then + $ECHO "*** Warning: lib $linklib is a module, not a shared library" + if test -z "$old_library" ; then + $ECHO + $ECHO "*** And there doesn't seem to be a static archive available" + $ECHO "*** The link will probably fail, sorry" + else + add="$dir/$old_library" + fi + elif test -n "$old_library"; then + add="$dir/$old_library" + fi + fi + esac + elif test "$hardcode_minus_L" = no; then + case $host in + *-*-sunos*) add_shlibpath="$dir" ;; + esac + add_dir="-L$dir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = no; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + relink) + if test "$hardcode_direct" = yes && + test "$hardcode_direct_absolute" = no; then + add="$dir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$dir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + add_dir="$add_dir -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + *) lib_linked=no ;; + esac + + if test "$lib_linked" != yes; then + func_fatal_configuration "unsupported hardcode properties" + fi + + if test -n "$add_shlibpath"; then + case :$compile_shlibpath: in + *":$add_shlibpath:"*) ;; + *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;; + esac + fi + if test "$linkmode" = prog; then + test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" + test -n "$add" && compile_deplibs="$add $compile_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + if test "$hardcode_direct" != yes && + test "$hardcode_minus_L" != yes && + test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + fi + fi + fi + + if test "$linkmode" = prog || test "$mode" = relink; then + add_shlibpath= + add_dir= + add= + # Finalize command for both is simple: just hardcode it. + if test "$hardcode_direct" = yes && + test "$hardcode_direct_absolute" = no; then + add="$libdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$libdir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + add="-l$name" + elif test "$hardcode_automatic" = yes; then + if test -n "$inst_prefix_dir" && + test -f "$inst_prefix_dir$libdir/$linklib" ; then + add="$inst_prefix_dir$libdir/$linklib" + else + add="$libdir/$linklib" + fi + else + # We cannot seem to hardcode it, guess we'll fake it. + add_dir="-L$libdir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + add_dir="$add_dir -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + fi + + if test "$linkmode" = prog; then + test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" + test -n "$add" && finalize_deplibs="$add $finalize_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + fi + fi + elif test "$linkmode" = prog; then + # Here we assume that one of hardcode_direct or hardcode_minus_L + # is not unsupported. This is valid on all known static and + # shared platforms. + if test "$hardcode_direct" != unsupported; then + test -n "$old_library" && linklib="$old_library" + compile_deplibs="$dir/$linklib $compile_deplibs" + finalize_deplibs="$dir/$linklib $finalize_deplibs" + else + compile_deplibs="-l$name -L$dir $compile_deplibs" + finalize_deplibs="-l$name -L$dir $finalize_deplibs" + fi + elif test "$build_libtool_libs" = yes; then + # Not a shared library + if test "$deplibs_check_method" != pass_all; then + # We're trying link a shared library against a static one + # but the system doesn't support it. + + # Just print a warning and add the library to dependency_libs so + # that the program can be linked against the static library. + $ECHO + $ECHO "*** Warning: This system can not link to static lib archive $lib." + $ECHO "*** I have the capability to make that library automatically link in when" + $ECHO "*** you link to this library. But I can only do this if you have a" + $ECHO "*** shared version of the library, which you do not appear to have." + if test "$module" = yes; then + $ECHO "*** But as you try to build a module library, libtool will still create " + $ECHO "*** a static module, that should work as long as the dlopening application" + $ECHO "*** is linked with the -dlopen flag to resolve symbols at runtime." + if test -z "$global_symbol_pipe"; then + $ECHO + $ECHO "*** However, this would only work if libtool was able to extract symbol" + $ECHO "*** lists from a program, using \`nm' or equivalent, but libtool could" + $ECHO "*** not find such a program. So, this module is probably useless." + $ECHO "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + else + deplibs="$dir/$old_library $deplibs" + link_static=yes + fi + fi # link shared/static library? + + if test "$linkmode" = lib; then + if test -n "$dependency_libs" && + { test "$hardcode_into_libs" != yes || + test "$build_old_libs" = yes || + test "$link_static" = yes; }; then + # Extract -R from dependency_libs + temp_deplibs= + for libdir in $dependency_libs; do + case $libdir in + -R*) func_stripname '-R' '' "$libdir" + temp_xrpath=$func_stripname_result + case " $xrpath " in + *" $temp_xrpath "*) ;; + *) xrpath="$xrpath $temp_xrpath";; + esac;; + *) temp_deplibs="$temp_deplibs $libdir";; + esac + done + dependency_libs="$temp_deplibs" + fi + + newlib_search_path="$newlib_search_path $absdir" + # Link against this library + test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" + # ... and its dependency_libs + tmp_libs= + for deplib in $dependency_libs; do + newdependency_libs="$deplib $newdependency_libs" + if $opt_duplicate_deps ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done + + if test "$link_all_deplibs" != no; then + # Add the search paths of all dependency libraries + for deplib in $dependency_libs; do + case $deplib in + -L*) path="$deplib" ;; + *.la) + func_dirname "$deplib" "" "." + dir="$func_dirname_result" + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + func_warning "cannot determine absolute directory name of \`$dir'" + absdir="$dir" + fi + ;; + esac + if $GREP "^installed=no" $deplib > /dev/null; then + case $host in + *-*-darwin*) + depdepl= + eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` + if test -n "$deplibrary_names" ; then + for tmp in $deplibrary_names ; do + depdepl=$tmp + done + if test -f "$absdir/$objdir/$depdepl" ; then + depdepl="$absdir/$objdir/$depdepl" + darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + if test -z "$darwin_install_name"; then + darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + fi + compiler_flags="$compiler_flags ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}" + linker_flags="$linker_flags -dylib_file ${darwin_install_name}:${depdepl}" + path= + fi + fi + ;; + *) + path="-L$absdir/$objdir" + ;; + esac + else + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + test -z "$libdir" && \ + func_fatal_error "\`$deplib' is not a valid libtool archive" + test "$absdir" != "$libdir" && \ + func_warning "\`$deplib' seems to be moved" + + path="-L$absdir" + fi + ;; + esac + case " $deplibs " in + *" $path "*) ;; + *) deplibs="$path $deplibs" ;; + esac + done + fi # link_all_deplibs != no + fi # linkmode = lib + done # for deplib in $libs + if test "$pass" = link; then + if test "$linkmode" = "prog"; then + compile_deplibs="$new_inherited_linker_flags $compile_deplibs" + finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" + else + compiler_flags="$compiler_flags "`$ECHO "X $new_inherited_linker_flags" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + fi + fi + dependency_libs="$newdependency_libs" + if test "$pass" = dlpreopen; then + # Link the dlpreopened libraries before other libraries + for deplib in $save_deplibs; do + deplibs="$deplib $deplibs" + done + fi + if test "$pass" != dlopen; then + if test "$pass" != conv; then + # Make sure lib_search_path contains only unique directories. + lib_search_path= + for dir in $newlib_search_path; do + case "$lib_search_path " in + *" $dir "*) ;; + *) lib_search_path="$lib_search_path $dir" ;; + esac + done + newlib_search_path= + fi + + if test "$linkmode,$pass" != "prog,link"; then + vars="deplibs" + else + vars="compile_deplibs finalize_deplibs" + fi + for var in $vars dependency_libs; do + # Add libraries to $var in reverse order + eval tmp_libs=\"\$$var\" + new_libs= + for deplib in $tmp_libs; do + # FIXME: Pedantically, this is the right thing to do, so + # that some nasty dependency loop isn't accidentally + # broken: + #new_libs="$deplib $new_libs" + # Pragmatically, this seems to cause very few problems in + # practice: + case $deplib in + -L*) new_libs="$deplib $new_libs" ;; + -R*) ;; + *) + # And here is the reason: when a library appears more + # than once as an explicit dependence of a library, or + # is implicitly linked in more than once by the + # compiler, it is considered special, and multiple + # occurrences thereof are not removed. Compare this + # with having the same library being listed as a + # dependency of multiple other libraries: in this case, + # we know (pedantically, we assume) the library does not + # need to be listed more than once, so we keep only the + # last copy. This is not always right, but it is rare + # enough that we require users that really mean to play + # such unportable linking tricks to link the library + # using -Wl,-lname, so that libtool does not consider it + # for duplicate removal. + case " $specialdeplibs " in + *" $deplib "*) new_libs="$deplib $new_libs" ;; + *) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$deplib $new_libs" ;; + esac + ;; + esac + ;; + esac + done + tmp_libs= + for deplib in $new_libs; do + case $deplib in + -L*) + case " $tmp_libs " in + *" $deplib "*) ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + done + eval $var=\"$tmp_libs\" + done # for var + fi + # Last step: remove runtime libs from dependency_libs + # (they stay in deplibs) + tmp_libs= + for i in $dependency_libs ; do + case " $predeps $postdeps $compiler_lib_search_path " in + *" $i "*) + i="" + ;; + esac + if test -n "$i" ; then + tmp_libs="$tmp_libs $i" + fi + done + dependency_libs=$tmp_libs + done # for pass + if test "$linkmode" = prog; then + dlfiles="$newdlfiles" + fi + if test "$linkmode" = prog || test "$linkmode" = lib; then + dlprefiles="$newdlprefiles" + fi + + case $linkmode in + oldlib) + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + func_warning "\`-dlopen' is ignored for archives" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "\`-l' and \`-L' are ignored for archives" ;; + esac + + test -n "$rpath" && \ + func_warning "\`-rpath' is ignored for archives" + + test -n "$xrpath" && \ + func_warning "\`-R' is ignored for archives" + + test -n "$vinfo" && \ + func_warning "\`-version-info/-version-number' is ignored for archives" + + test -n "$release" && \ + func_warning "\`-release' is ignored for archives" + + test -n "$export_symbols$export_symbols_regex" && \ + func_warning "\`-export-symbols' is ignored for archives" + + # Now set the variables for building old libraries. + build_libtool_libs=no + oldlibs="$output" + objs="$objs$old_deplibs" + ;; + + lib) + # Make sure we only generate libraries of the form `libNAME.la'. + case $outputname in + lib*) + func_stripname 'lib' '.la' "$outputname" + name=$func_stripname_result + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + ;; + *) + test "$module" = no && \ + func_fatal_help "libtool library \`$output' must begin with \`lib'" + + if test "$need_lib_prefix" != no; then + # Add the "lib" prefix for modules if required + func_stripname '' '.la' "$outputname" + name=$func_stripname_result + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + else + func_stripname '' '.la' "$outputname" + libname=$func_stripname_result + fi + ;; + esac + + if test -n "$objs"; then + if test "$deplibs_check_method" != pass_all; then + func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs" + else + $ECHO + $ECHO "*** Warning: Linking the shared library $output against the non-libtool" + $ECHO "*** objects $objs is not portable!" + libobjs="$libobjs $objs" + fi + fi + + test "$dlself" != no && \ + func_warning "\`-dlopen self' is ignored for libtool libraries" + + set dummy $rpath + shift + test "$#" -gt 1 && \ + func_warning "ignoring multiple \`-rpath's for a libtool library" + + install_libdir="$1" + + oldlibs= + if test -z "$rpath"; then + if test "$build_libtool_libs" = yes; then + # Building a libtool convenience library. + # Some compilers have problems with a `.al' extension so + # convenience libraries should have the same extension an + # archive normally would. + oldlibs="$output_objdir/$libname.$libext $oldlibs" + build_libtool_libs=convenience + build_old_libs=yes + fi + + test -n "$vinfo" && \ + func_warning "\`-version-info/-version-number' is ignored for convenience libraries" + + test -n "$release" && \ + func_warning "\`-release' is ignored for convenience libraries" + else + + # Parse the version information argument. + save_ifs="$IFS"; IFS=':' + set dummy $vinfo 0 0 0 + shift + IFS="$save_ifs" + + test -n "$7" && \ + func_fatal_help "too many parameters to \`-version-info'" + + # convert absolute version numbers to libtool ages + # this retains compatibility with .la files and attempts + # to make the code below a bit more comprehensible + + case $vinfo_number in + yes) + number_major="$1" + number_minor="$2" + number_revision="$3" + # + # There are really only two kinds -- those that + # use the current revision as the major version + # and those that subtract age and use age as + # a minor version. But, then there is irix + # which has an extra 1 added just for fun + # + case $version_type in + darwin|linux|osf|windows|none) + func_arith $number_major + $number_minor + current=$func_arith_result + age="$number_minor" + revision="$number_revision" + ;; + freebsd-aout|freebsd-elf|sunos) + current="$number_major" + revision="$number_minor" + age="0" + ;; + irix|nonstopux) + func_arith $number_major + $number_minor + current=$func_arith_result + age="$number_minor" + revision="$number_minor" + lt_irix_increment=no + ;; + *) + func_fatal_configuration "$modename: unknown library version type \`$version_type'" + ;; + esac + ;; + no) + current="$1" + revision="$2" + age="$3" + ;; + esac + + # Check that each of the things are valid numbers. + case $current in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "CURRENT \`$current' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + case $revision in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "REVISION \`$revision' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + case $age in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "AGE \`$age' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + if test "$age" -gt "$current"; then + func_error "AGE \`$age' is greater than the current interface number \`$current'" + func_fatal_error "\`$vinfo' is not valid version information" + fi + + # Calculate the version variables. + major= + versuffix= + verstring= + case $version_type in + none) ;; + + darwin) + # Like Linux, but with the current version available in + # verstring for coding it into the library header + func_arith $current - $age + major=.$func_arith_result + versuffix="$major.$age.$revision" + # Darwin ld doesn't like 0 for these options... + func_arith $current + 1 + minor_current=$func_arith_result + xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" + verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" + ;; + + freebsd-aout) + major=".$current" + versuffix=".$current.$revision"; + ;; + + freebsd-elf) + major=".$current" + versuffix=".$current" + ;; + + irix | nonstopux) + if test "X$lt_irix_increment" = "Xno"; then + func_arith $current - $age + else + func_arith $current - $age + 1 + fi + major=$func_arith_result + + case $version_type in + nonstopux) verstring_prefix=nonstopux ;; + *) verstring_prefix=sgi ;; + esac + verstring="$verstring_prefix$major.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$revision + while test "$loop" -ne 0; do + func_arith $revision - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring="$verstring_prefix$major.$iface:$verstring" + done + + # Before this point, $major must not contain `.'. + major=.$major + versuffix="$major.$revision" + ;; + + linux) + func_arith $current - $age + major=.$func_arith_result + versuffix="$major.$age.$revision" + ;; + + osf) + func_arith $current - $age + major=.$func_arith_result + versuffix=".$current.$age.$revision" + verstring="$current.$age.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$age + while test "$loop" -ne 0; do + func_arith $current - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring="$verstring:${iface}.0" + done + + # Make executables depend on our current version. + verstring="$verstring:${current}.0" + ;; + + qnx) + major=".$current" + versuffix=".$current" + ;; + + sunos) + major=".$current" + versuffix=".$current.$revision" + ;; + + windows) + # Use '-' rather than '.', since we only want one + # extension on DOS 8.3 filesystems. + func_arith $current - $age + major=$func_arith_result + versuffix="-$major" + ;; + + *) + func_fatal_configuration "unknown library version type \`$version_type'" + ;; + esac + + # Clear the version info if we defaulted, and they specified a release. + if test -z "$vinfo" && test -n "$release"; then + major= + case $version_type in + darwin) + # we can't check for "0.0" in archive_cmds due to quoting + # problems, so we reset it completely + verstring= + ;; + *) + verstring="0.0" + ;; + esac + if test "$need_version" = no; then + versuffix= + else + versuffix=".0.0" + fi + fi + + # Remove version info from name if versioning should be avoided + if test "$avoid_version" = yes && test "$need_version" = no; then + major= + versuffix= + verstring="" + fi + + # Check to see if the archive will have undefined symbols. + if test "$allow_undefined" = yes; then + if test "$allow_undefined_flag" = unsupported; then + func_warning "undefined symbols not allowed in $host shared libraries" + build_libtool_libs=no + build_old_libs=yes + fi + else + # Don't allow undefined symbols. + allow_undefined_flag="$no_undefined_flag" + fi + + fi + + func_generate_dlsyms "$libname" "$libname" "yes" + libobjs="$libobjs $symfileobj" + test "X$libobjs" = "X " && libobjs= + + if test "$mode" != relink; then + # Remove our outputs, but don't remove object files since they + # may have been created when compiling PIC objects. + removelist= + tempremovelist=`$ECHO "$output_objdir/*"` + for p in $tempremovelist; do + case $p in + *.$objext | *.gcno) + ;; + $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) + if test "X$precious_files_regex" != "X"; then + if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 + then + continue + fi + fi + removelist="$removelist $p" + ;; + *) ;; + esac + done + test -n "$removelist" && \ + func_show_eval "${RM}r \$removelist" + fi + + # Now set the variables for building old libraries. + if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then + oldlibs="$oldlibs $output_objdir/$libname.$libext" + + # Transform .lo files to .o files. + oldobjs="$objs "`$ECHO "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP` + fi + + # Eliminate all temporary directories. + #for path in $notinst_path; do + # lib_search_path=`$ECHO "X$lib_search_path " | $Xsed -e "s% $path % %g"` + # deplibs=`$ECHO "X$deplibs " | $Xsed -e "s% -L$path % %g"` + # dependency_libs=`$ECHO "X$dependency_libs " | $Xsed -e "s% -L$path % %g"` + #done + + if test -n "$xrpath"; then + # If the user specified any rpath flags, then add them. + temp_xrpath= + for libdir in $xrpath; do + temp_xrpath="$temp_xrpath -R$libdir" + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then + dependency_libs="$temp_xrpath $dependency_libs" + fi + fi + + # Make sure dlfiles contains only unique files that won't be dlpreopened + old_dlfiles="$dlfiles" + dlfiles= + for lib in $old_dlfiles; do + case " $dlprefiles $dlfiles " in + *" $lib "*) ;; + *) dlfiles="$dlfiles $lib" ;; + esac + done + + # Make sure dlprefiles contains only unique files + old_dlprefiles="$dlprefiles" + dlprefiles= + for lib in $old_dlprefiles; do + case "$dlprefiles " in + *" $lib "*) ;; + *) dlprefiles="$dlprefiles $lib" ;; + esac + done + + if test "$build_libtool_libs" = yes; then + if test -n "$rpath"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc*) + # these systems don't actually have a c library (as such)! + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C library is in the System framework + deplibs="$deplibs System.ltframework" + ;; + *-*-netbsd*) + # Don't link with libc until the a.out ld.so is fixed. + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + ;; + *) + # Add libc to deplibs on all other systems if necessary. + if test "$build_libtool_need_lc" = "yes"; then + deplibs="$deplibs -lc" + fi + ;; + esac + fi + + # Transform deplibs into only deplibs that can be linked in shared. + name_save=$name + libname_save=$libname + release_save=$release + versuffix_save=$versuffix + major_save=$major + # I'm not sure if I'm treating the release correctly. I think + # release should show up in the -l (ie -lgmp5) so we don't want to + # add it in twice. Is that correct? + release="" + versuffix="" + major="" + newdeplibs= + droppeddeps=no + case $deplibs_check_method in + pass_all) + # Don't check for shared/static. Everything works. + # This might be a little naive. We might want to check + # whether the library exists or not. But this is on + # osf3 & osf4 and I'm not really sure... Just + # implementing what was already the behavior. + newdeplibs=$deplibs + ;; + test_compile) + # This code stresses the "libraries are programs" paradigm to its + # limits. Maybe even breaks it. We compile a program, linking it + # against the deplibs as a proxy for the library. Then we can check + # whether they linked in statically or dynamically with ldd. + $opt_dry_run || $RM conftest.c + cat > conftest.c </dev/null` + for potent_lib in $potential_libs; do + # Follow soft links. + if ls -lLd "$potent_lib" 2>/dev/null | + $GREP " -> " >/dev/null; then + continue + fi + # The statement above tries to avoid entering an + # endless loop below, in case of cyclic links. + # We might still enter an endless loop, since a link + # loop can be closed while we follow links, + # but so what? + potlib="$potent_lib" + while test -h "$potlib" 2>/dev/null; do + potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` + case $potliblink in + [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; + *) potlib=`$ECHO "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";; + esac + done + if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | + $SED -e 10q | + $EGREP "$file_magic_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + $ECHO + $ECHO "*** Warning: linker path does not have real file for library $a_deplib." + $ECHO "*** I have the capability to make that library automatically link in when" + $ECHO "*** you link to this library. But I can only do this if you have a" + $ECHO "*** shared version of the library, which you do not appear to have" + $ECHO "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $ECHO "*** with $libname but no candidates were found. (...for file magic test)" + else + $ECHO "*** with $libname and none of the candidates passed a file format test" + $ECHO "*** using a file magic. Last file checked: $potlib" + fi + fi + ;; + *) + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + for a_deplib in $deplibs; do + case $a_deplib in + -l*) + func_stripname -l '' "$a_deplib" + name=$func_stripname_result + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $a_deplib "*) + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + ;; + esac + fi + if test -n "$a_deplib" ; then + libname=`eval "\\$ECHO \"$libname_spec\""` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + for potent_lib in $potential_libs; do + potlib="$potent_lib" # see symlink-check above in file_magic test + if eval "\$ECHO \"X$potent_lib\"" 2>/dev/null | $Xsed -e 10q | \ + $EGREP "$match_pattern_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + $ECHO + $ECHO "*** Warning: linker path does not have real file for library $a_deplib." + $ECHO "*** I have the capability to make that library automatically link in when" + $ECHO "*** you link to this library. But I can only do this if you have a" + $ECHO "*** shared version of the library, which you do not appear to have" + $ECHO "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" + else + $ECHO "*** with $libname and none of the candidates passed a file format test" + $ECHO "*** using a regex pattern. Last file checked: $potlib" + fi + fi + ;; + *) + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + none | unknown | *) + newdeplibs="" + tmp_deplibs=`$ECHO "X $deplibs" | $Xsed \ + -e 's/ -lc$//' -e 's/ -[LR][^ ]*//g'` + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + for i in $predeps $postdeps ; do + # can't use Xsed below, because $i might contain '/' + tmp_deplibs=`$ECHO "X $tmp_deplibs" | $Xsed -e "s,$i,,"` + done + fi + if $ECHO "X $tmp_deplibs" | $Xsed -e 's/[ ]//g' | + $GREP . >/dev/null; then + $ECHO + if test "X$deplibs_check_method" = "Xnone"; then + $ECHO "*** Warning: inter-library dependencies are not supported in this platform." + else + $ECHO "*** Warning: inter-library dependencies are not known to be supported." + fi + $ECHO "*** All declared inter-library dependencies are being dropped." + droppeddeps=yes + fi + ;; + esac + versuffix=$versuffix_save + major=$major_save + release=$release_save + libname=$libname_save + name=$name_save + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library with the System framework + newdeplibs=`$ECHO "X $newdeplibs" | $Xsed -e 's/ -lc / System.ltframework /'` + ;; + esac + + if test "$droppeddeps" = yes; then + if test "$module" = yes; then + $ECHO + $ECHO "*** Warning: libtool could not satisfy all declared inter-library" + $ECHO "*** dependencies of module $libname. Therefore, libtool will create" + $ECHO "*** a static module, that should work as long as the dlopening" + $ECHO "*** application is linked with the -dlopen flag." + if test -z "$global_symbol_pipe"; then + $ECHO + $ECHO "*** However, this would only work if libtool was able to extract symbol" + $ECHO "*** lists from a program, using \`nm' or equivalent, but libtool could" + $ECHO "*** not find such a program. So, this module is probably useless." + $ECHO "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + else + $ECHO "*** The inter-library dependencies that have been dropped here will be" + $ECHO "*** automatically added whenever a program is linked with this library" + $ECHO "*** or is declared to -dlopen it." + + if test "$allow_undefined" = no; then + $ECHO + $ECHO "*** Since this library must not contain undefined symbols," + $ECHO "*** because either the platform does not support them or" + $ECHO "*** it was explicitly requested with -no-undefined," + $ECHO "*** libtool will only create a static version of it." + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + fi + fi + # Done checking deplibs! + deplibs=$newdeplibs + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + case $host in + *-*-darwin*) + newdeplibs=`$ECHO "X $newdeplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + new_inherited_linker_flags=`$ECHO "X $new_inherited_linker_flags" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + deplibs=`$ECHO "X $deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + esac + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $deplibs " in + *" -L$path/$objdir "*) + new_libs="$new_libs -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$new_libs $deplib" ;; + esac + ;; + *) new_libs="$new_libs $deplib" ;; + esac + done + deplibs="$new_libs" + + # All the library-specific variables (install_libdir is set above). + library_names= + old_library= + dlname= + + # Test again, we may have decided not to build it any more + if test "$build_libtool_libs" = yes; then + if test "$hardcode_into_libs" = yes; then + # Hardcode the library paths + hardcode_libdirs= + dep_rpath= + rpath="$finalize_rpath" + test "$mode" != relink && rpath="$compile_rpath$rpath" + for libdir in $rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + dep_rpath="$dep_rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + if test -n "$hardcode_libdir_flag_spec_ld"; then + eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\" + else + eval dep_rpath=\"$hardcode_libdir_flag_spec\" + fi + fi + if test -n "$runpath_var" && test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" + fi + test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" + fi + + shlibpath="$finalize_shlibpath" + test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath" + if test -n "$shlibpath"; then + eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" + fi + + # Get the real and link names of the library. + eval shared_ext=\"$shrext_cmds\" + eval library_names=\"$library_names_spec\" + set dummy $library_names + shift + realname="$1" + shift + + if test -n "$soname_spec"; then + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + if test -z "$dlname"; then + dlname=$soname + fi + + lib="$output_objdir/$realname" + linknames= + for link + do + linknames="$linknames $link" + done + + # Use standard objects if they are pic + test -z "$pic_flag" && libobjs=`$ECHO "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + test "X$libobjs" = "X " && libobjs= + + delfiles= + if test -n "$export_symbols" && test -n "$include_expsyms"; then + $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" + export_symbols="$output_objdir/$libname.uexp" + delfiles="$delfiles $export_symbols" + fi + + orig_export_symbols= + case $host_os in + cygwin* | mingw* | cegcc*) + if test -n "$export_symbols" && test -z "$export_symbols_regex"; then + # exporting using user supplied symfile + if test "x`$SED 1q $export_symbols`" != xEXPORTS; then + # and it's NOT already a .def file. Must figure out + # which of the given symbols are data symbols and tag + # them as such. So, trigger use of export_symbols_cmds. + # export_symbols gets reassigned inside the "prepare + # the list of exported symbols" if statement, so the + # include_expsyms logic still works. + orig_export_symbols="$export_symbols" + export_symbols= + always_export_symbols=yes + fi + fi + ;; + esac + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then + func_verbose "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $opt_dry_run || $RM $export_symbols + cmds=$export_symbols_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + func_len " $cmd" + len=$func_len_result + if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + func_show_eval "$cmd" 'exit $?' + skipped_export=false + else + # The command line is too long to execute in one step. + func_verbose "using reloadable object file for export list..." + skipped_export=: + # Break out early, otherwise skipped_export may be + # set to false by a later but shorter cmd. + break + fi + done + IFS="$save_ifs" + if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + fi + + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols="$export_symbols" + test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" + $opt_dry_run || eval '$ECHO "X$include_expsyms" | $Xsed | $SP2NL >> "$tmp_export_symbols"' + fi + + if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + delfiles="$delfiles $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + + tmp_deplibs= + for test_deplib in $deplibs; do + case " $convenience " in + *" $test_deplib "*) ;; + *) + tmp_deplibs="$tmp_deplibs $test_deplib" + ;; + esac + done + deplibs="$tmp_deplibs" + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec" && + test "$compiler_needs_object" = yes && + test -z "$libobjs"; then + # extract the archives, so we have objects to list. + # TODO: could optimize this to just extract one archive. + whole_archive_flag_spec= + fi + if test -n "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + test "X$libobjs" = "X " && libobjs= + else + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $convenience + libobjs="$libobjs $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + fi + + if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then + eval flag=\"$thread_safe_flag_spec\" + linker_flags="$linker_flags $flag" + fi + + # Make a backup of the uninstalled library when relinking + if test "$mode" = relink; then + $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? + fi + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + eval test_cmds=\"$module_expsym_cmds\" + cmds=$module_expsym_cmds + else + eval test_cmds=\"$module_cmds\" + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + eval test_cmds=\"$archive_expsym_cmds\" + cmds=$archive_expsym_cmds + else + eval test_cmds=\"$archive_cmds\" + cmds=$archive_cmds + fi + fi + + if test "X$skipped_export" != "X:" && + func_len " $test_cmds" && + len=$func_len_result && + test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + : + else + # The command line is too long to link in one step, link piecewise + # or, if using GNU ld and skipped_export is not :, use a linker + # script. + + # Save the value of $output and $libobjs because we want to + # use them later. If we have whole_archive_flag_spec, we + # want to use save_libobjs as it was before + # whole_archive_flag_spec was expanded, because we can't + # assume the linker understands whole_archive_flag_spec. + # This may have to be revisited, in case too many + # convenience libraries get linked in and end up exceeding + # the spec. + if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + fi + save_output=$output + output_la=`$ECHO "X$output" | $Xsed -e "$basename"` + + # Clear the reloadable object creation command queue and + # initialize k to one. + test_cmds= + concat_cmds= + objlist= + last_robj= + k=1 + + if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then + output=${output_objdir}/${output_la}.lnkscript + func_verbose "creating GNU ld script: $output" + $ECHO 'INPUT (' > $output + for obj in $save_libobjs + do + $ECHO "$obj" >> $output + done + $ECHO ')' >> $output + delfiles="$delfiles $output" + elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then + output=${output_objdir}/${output_la}.lnk + func_verbose "creating linker input file list: $output" + : > $output + set x $save_libobjs + shift + firstobj= + if test "$compiler_needs_object" = yes; then + firstobj="$1 " + shift + fi + for obj + do + $ECHO "$obj" >> $output + done + delfiles="$delfiles $output" + output=$firstobj\"$file_list_spec$output\" + else + if test -n "$save_libobjs"; then + func_verbose "creating reloadable object files..." + output=$output_objdir/$output_la-${k}.$objext + eval test_cmds=\"$reload_cmds\" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + + # Loop over the list of objects to be linked. + for obj in $save_libobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + if test "X$objlist" = X || + test "$len" -lt "$max_cmd_len"; then + func_append objlist " $obj" + else + # The command $test_cmds is almost too long, add a + # command to the queue. + if test "$k" -eq 1 ; then + # The first file doesn't have a previous command to add. + eval concat_cmds=\"$reload_cmds $objlist $last_robj\" + else + # All subsequent reloadable object files will link in + # the last one created. + eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj~\$RM $last_robj\" + fi + last_robj=$output_objdir/$output_la-${k}.$objext + func_arith $k + 1 + k=$func_arith_result + output=$output_objdir/$output_la-${k}.$objext + objlist=$obj + func_len " $last_robj" + func_arith $len0 + $func_len_result + len=$func_arith_result + fi + done + # Handle the remaining objects by creating one last + # reloadable object file. All subsequent reloadable object + # files will link in the last one created. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\" + if test -n "$last_robj"; then + eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\" + fi + delfiles="$delfiles $output" + + else + output= + fi + + if ${skipped_export-false}; then + func_verbose "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $opt_dry_run || $RM $export_symbols + libobjs=$output + # Append the command to create the export file. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" + if test -n "$last_robj"; then + eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" + fi + fi + + test -n "$save_libobjs" && + func_verbose "creating a temporary reloadable object file: $output" + + # Loop through the commands generated above and execute them. + save_ifs="$IFS"; IFS='~' + for cmd in $concat_cmds; do + IFS="$save_ifs" + $opt_silent || { + func_quote_for_expand "$cmd" + eval "func_echo $func_quote_for_expand_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + if test -n "$export_symbols_regex" && ${skipped_export-false}; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + + if ${skipped_export-false}; then + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols="$export_symbols" + test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" + $opt_dry_run || eval '$ECHO "X$include_expsyms" | $Xsed | $SP2NL >> "$tmp_export_symbols"' + fi + + if test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + delfiles="$delfiles $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + fi + + libobjs=$output + # Restore the value of output. + output=$save_output + + if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + test "X$libobjs" = "X " && libobjs= + fi + # Expand the library linking commands again to reset the + # value of $libobjs for piecewise linking. + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + cmds=$module_expsym_cmds + else + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + cmds=$archive_expsym_cmds + else + cmds=$archive_cmds + fi + fi + fi + + if test -n "$delfiles"; then + # Append the command to remove temporary files to $cmds. + eval cmds=\"\$cmds~\$RM $delfiles\" + fi + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $dlprefiles + libobjs="$libobjs $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $opt_silent || { + func_quote_for_expand "$cmd" + eval "func_echo $func_quote_for_expand_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? + + if test -n "$convenience"; then + if test -z "$whole_archive_flag_spec"; then + func_show_eval '${RM}r "$gentop"' + fi + fi + + exit $EXIT_SUCCESS + fi + + # Create links to the real library. + for linkname in $linknames; do + if test "$realname" != "$linkname"; then + func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' + fi + done + + # If -module or -export-dynamic was specified, set the dlname. + if test "$module" = yes || test "$export_dynamic" = yes; then + # On all known operating systems, these are identical. + dlname="$soname" + fi + fi + ;; + + obj) + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + func_warning "\`-dlopen' is ignored for objects" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "\`-l' and \`-L' are ignored for objects" ;; + esac + + test -n "$rpath" && \ + func_warning "\`-rpath' is ignored for objects" + + test -n "$xrpath" && \ + func_warning "\`-R' is ignored for objects" + + test -n "$vinfo" && \ + func_warning "\`-version-info' is ignored for objects" + + test -n "$release" && \ + func_warning "\`-release' is ignored for objects" + + case $output in + *.lo) + test -n "$objs$old_deplibs" && \ + func_fatal_error "cannot build library object \`$output' from non-libtool objects" + + libobj=$output + func_lo2o "$libobj" + obj=$func_lo2o_result + ;; + *) + libobj= + obj="$output" + ;; + esac + + # Delete the old objects. + $opt_dry_run || $RM $obj $libobj + + # Objects from convenience libraries. This assumes + # single-version convenience libraries. Whenever we create + # different ones for PIC/non-PIC, this we'll have to duplicate + # the extraction. + reload_conv_objs= + gentop= + # reload_cmds runs $LD directly, so let us get rid of + # -Wl from whole_archive_flag_spec and hope we can get by with + # turning comma into space.. + wl= + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" + reload_conv_objs=$reload_objs\ `$ECHO "X$tmp_whole_archive_flags" | $Xsed -e 's|,| |g'` + else + gentop="$output_objdir/${obj}x" + generated="$generated $gentop" + + func_extract_archives $gentop $convenience + reload_conv_objs="$reload_objs $func_extract_archives_result" + fi + fi + + # Create the old-style object. + reload_objs="$objs$old_deplibs "`$ECHO "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test + + output="$obj" + func_execute_cmds "$reload_cmds" 'exit $?' + + # Exit if we aren't doing a library object file. + if test -z "$libobj"; then + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + fi + + if test "$build_libtool_libs" != yes; then + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + # Create an invalid libtool object if no PIC, so that we don't + # accidentally link it into a program. + # $show "echo timestamp > $libobj" + # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? + exit $EXIT_SUCCESS + fi + + if test -n "$pic_flag" || test "$pic_mode" != default; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs $reload_conv_objs" + output="$libobj" + func_execute_cmds "$reload_cmds" 'exit $?' + fi + + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + ;; + + prog) + case $host in + *cygwin*) func_stripname '' '.exe' "$output" + output=$func_stripname_result.exe;; + esac + test -n "$vinfo" && \ + func_warning "\`-version-info' is ignored for programs" + + test -n "$release" && \ + func_warning "\`-release' is ignored for programs" + + test "$preload" = yes \ + && test "$dlopen_support" = unknown \ + && test "$dlopen_self" = unknown \ + && test "$dlopen_self_static" = unknown && \ + func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support." + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + compile_deplibs=`$ECHO "X $compile_deplibs" | $Xsed -e 's/ -lc / System.ltframework /'` + finalize_deplibs=`$ECHO "X $finalize_deplibs" | $Xsed -e 's/ -lc / System.ltframework /'` + ;; + esac + + case $host in + *-*-darwin*) + # Don't allow lazy linking, it breaks C++ global constructors + # But is supposedly fixed on 10.4 or later (yay!). + if test "$tagname" = CXX ; then + case ${MACOSX_DEPLOYMENT_TARGET-10.0} in + 10.[0123]) + compile_command="$compile_command ${wl}-bind_at_load" + finalize_command="$finalize_command ${wl}-bind_at_load" + ;; + esac + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + compile_deplibs=`$ECHO "X $compile_deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + finalize_deplibs=`$ECHO "X $finalize_deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + esac + + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $compile_deplibs " in + *" -L$path/$objdir "*) + new_libs="$new_libs -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $compile_deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$new_libs $deplib" ;; + esac + ;; + *) new_libs="$new_libs $deplib" ;; + esac + done + compile_deplibs="$new_libs" + + + compile_command="$compile_command $compile_deplibs" + finalize_command="$finalize_command $finalize_deplibs" + + if test -n "$rpath$xrpath"; then + # If the user specified any rpath flags, then add them. + for libdir in $rpath $xrpath; do + # This is the magic to use -rpath. + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + fi + + # Now hardcode the library paths + rpath= + hardcode_libdirs= + for libdir in $compile_rpath $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$libdir:"*) ;; + ::) dllsearchpath=$libdir;; + *) dllsearchpath="$dllsearchpath:$libdir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) dllsearchpath="$dllsearchpath:$testbindir";; + esac + ;; + esac + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + compile_rpath="$rpath" + + rpath= + hardcode_libdirs= + for libdir in $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$finalize_perm_rpath " in + *" $libdir "*) ;; + *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + finalize_rpath="$rpath" + + if test -n "$libobjs" && test "$build_old_libs" = yes; then + # Transform all the library objects into standard objects. + compile_command=`$ECHO "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + finalize_command=`$ECHO "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + fi + + func_generate_dlsyms "$outputname" "@PROGRAM@" "no" + + # template prelinking step + if test -n "$prelink_cmds"; then + func_execute_cmds "$prelink_cmds" 'exit $?' + fi + + wrappers_required=yes + case $host in + *cygwin* | *mingw* ) + if test "$build_libtool_libs" != yes; then + wrappers_required=no + fi + ;; + *cegcc) + # Disable wrappers for cegcc, we are cross compiling anyway. + wrappers_required=no + ;; + *) + if test "$need_relink" = no || test "$build_libtool_libs" != yes; then + wrappers_required=no + fi + ;; + esac + if test "$wrappers_required" = no; then + # Replace the output file specification. + compile_command=`$ECHO "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + link_command="$compile_command$compile_rpath" + + # We have no uninstalled library dependencies, so finalize right now. + exit_status=0 + func_show_eval "$link_command" 'exit_status=$?' + + # Delete the generated files. + if test -f "$output_objdir/${outputname}S.${objext}"; then + func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"' + fi + + exit $exit_status + fi + + if test -n "$compile_shlibpath$finalize_shlibpath"; then + compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" + fi + if test -n "$finalize_shlibpath"; then + finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" + fi + + compile_var= + finalize_var= + if test -n "$runpath_var"; then + if test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + compile_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + if test -n "$finalize_perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $finalize_perm_rpath; do + rpath="$rpath$dir:" + done + finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + fi + + if test "$no_install" = yes; then + # We don't need to create a wrapper script. + link_command="$compile_var$compile_command$compile_rpath" + # Replace the output file specification. + link_command=`$ECHO "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + # Delete the old output file. + $opt_dry_run || $RM $output + # Link the executable and exit + func_show_eval "$link_command" 'exit $?' + exit $EXIT_SUCCESS + fi + + if test "$hardcode_action" = relink; then + # Fast installation is not supported + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + + func_warning "this platform does not like uninstalled shared libraries" + func_warning "\`$output' will be relinked during installation" + else + if test "$fast_install" != no; then + link_command="$finalize_var$compile_command$finalize_rpath" + if test "$fast_install" = yes; then + relink_command=`$ECHO "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'` + else + # fast_install is set to needless + relink_command= + fi + else + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + fi + fi + + # Replace the output file specification. + link_command=`$ECHO "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` + + # Delete the old output files. + $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname + + func_show_eval "$link_command" 'exit $?' + + # Now create the wrapper script. + func_verbose "creating $output" + + # Quote the relink command for shipping. + if test -n "$relink_command"; then + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + func_quote_for_eval "$var_value" + relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" + fi + done + relink_command="(cd `pwd`; $relink_command)" + relink_command=`$ECHO "X$relink_command" | $Xsed -e "$sed_quote_subst"` + fi + + # Quote $ECHO for shipping. + if test "X$ECHO" = "X$SHELL $progpath --fallback-echo"; then + case $progpath in + [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $progpath --fallback-echo";; + *) qecho="$SHELL `pwd`/$progpath --fallback-echo";; + esac + qecho=`$ECHO "X$qecho" | $Xsed -e "$sed_quote_subst"` + else + qecho=`$ECHO "X$ECHO" | $Xsed -e "$sed_quote_subst"` + fi + + # Only actually do things if not in dry run mode. + $opt_dry_run || { + # win32 will think the script is a binary if it has + # a .exe suffix, so we strip it off here. + case $output in + *.exe) func_stripname '' '.exe' "$output" + output=$func_stripname_result ;; + esac + # test for cygwin because mv fails w/o .exe extensions + case $host in + *cygwin*) + exeext=.exe + func_stripname '' '.exe' "$outputname" + outputname=$func_stripname_result ;; + *) exeext= ;; + esac + case $host in + *cygwin* | *mingw* ) + func_dirname_and_basename "$output" "" "." + output_name=$func_basename_result + output_path=$func_dirname_result + cwrappersource="$output_path/$objdir/lt-$output_name.c" + cwrapper="$output_path/$output_name.exe" + $RM $cwrappersource $cwrapper + trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 + + func_emit_cwrapperexe_src > $cwrappersource + + # The wrapper executable is built using the $host compiler, + # because it contains $host paths and files. If cross- + # compiling, it, like the target executable, must be + # executed on the $host or under an emulation environment. + $opt_dry_run || { + $LTCC $LTCFLAGS -o $cwrapper $cwrappersource + $STRIP $cwrapper + } + + # Now, create the wrapper script for func_source use: + func_ltwrapper_scriptname $cwrapper + $RM $func_ltwrapper_scriptname_result + trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 + $opt_dry_run || { + # note: this script will not be executed, so do not chmod. + if test "x$build" = "x$host" ; then + $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result + else + func_emit_wrapper no > $func_ltwrapper_scriptname_result + fi + } + ;; + * ) + $RM $output + trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 + + func_emit_wrapper no > $output + chmod +x $output + ;; + esac + } + exit $EXIT_SUCCESS + ;; + esac + + # See if we need to build an old-fashioned archive. + for oldlib in $oldlibs; do + + if test "$build_libtool_libs" = convenience; then + oldobjs="$libobjs_save $symfileobj" + addlibs="$convenience" + build_libtool_libs=no + else + if test "$build_libtool_libs" = module; then + oldobjs="$libobjs_save" + build_libtool_libs=no + else + oldobjs="$old_deplibs $non_pic_objects" + if test "$preload" = yes && test -f "$symfileobj"; then + oldobjs="$oldobjs $symfileobj" + fi + fi + addlibs="$old_convenience" + fi + + if test -n "$addlibs"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $addlibs + oldobjs="$oldobjs $func_extract_archives_result" + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then + cmds=$old_archive_from_new_cmds + else + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $dlprefiles + oldobjs="$oldobjs $func_extract_archives_result" + fi + + # POSIX demands no paths to be encoded in archives. We have + # to avoid creating archives with duplicate basenames if we + # might have to extract them afterwards, e.g., when creating a + # static archive out of a convenience library, or when linking + # the entirety of a libtool archive into another (currently + # not supported by libtool). + if (for obj in $oldobjs + do + func_basename "$obj" + $ECHO "$func_basename_result" + done | sort | sort -uc >/dev/null 2>&1); then + : + else + $ECHO "copying selected object files to avoid basename conflicts..." + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + func_mkdir_p "$gentop" + save_oldobjs=$oldobjs + oldobjs= + counter=1 + for obj in $save_oldobjs + do + func_basename "$obj" + objbase="$func_basename_result" + case " $oldobjs " in + " ") oldobjs=$obj ;; + *[\ /]"$objbase "*) + while :; do + # Make sure we don't pick an alternate name that also + # overlaps. + newobj=lt$counter-$objbase + func_arith $counter + 1 + counter=$func_arith_result + case " $oldobjs " in + *[\ /]"$newobj "*) ;; + *) if test ! -f "$gentop/$newobj"; then break; fi ;; + esac + done + func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" + oldobjs="$oldobjs $gentop/$newobj" + ;; + *) oldobjs="$oldobjs $obj" ;; + esac + done + fi + eval cmds=\"$old_archive_cmds\" + + func_len " $cmds" + len=$func_len_result + if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + cmds=$old_archive_cmds + else + # the command line is too long to link in one step, link in parts + func_verbose "using piecewise archive linking..." + save_RANLIB=$RANLIB + RANLIB=: + objlist= + concat_cmds= + save_oldobjs=$oldobjs + oldobjs= + # Is there a better way of finding the last object in the list? + for obj in $save_oldobjs + do + last_oldobj=$obj + done + eval test_cmds=\"$old_archive_cmds\" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + for obj in $save_oldobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + func_append objlist " $obj" + if test "$len" -lt "$max_cmd_len"; then + : + else + # the above command should be used before it gets too long + oldobjs=$objlist + if test "$obj" = "$last_oldobj" ; then + RANLIB=$save_RANLIB + fi + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" + objlist= + len=$len0 + fi + done + RANLIB=$save_RANLIB + oldobjs=$objlist + if test "X$oldobjs" = "X" ; then + eval cmds=\"\$concat_cmds\" + else + eval cmds=\"\$concat_cmds~\$old_archive_cmds\" + fi + fi + fi + func_execute_cmds "$cmds" 'exit $?' + done + + test -n "$generated" && \ + func_show_eval "${RM}r$generated" + + # Now create the libtool archive. + case $output in + *.la) + old_library= + test "$build_old_libs" = yes && old_library="$libname.$libext" + func_verbose "creating $output" + + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + func_quote_for_eval "$var_value" + relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" + fi + done + # Quote the link command for shipping. + relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" + relink_command=`$ECHO "X$relink_command" | $Xsed -e "$sed_quote_subst"` + if test "$hardcode_automatic" = yes ; then + relink_command= + fi + + # Only create the output if not a dry run. + $opt_dry_run || { + for installed in no yes; do + if test "$installed" = yes; then + if test -z "$install_libdir"; then + break + fi + output="$output_objdir/$outputname"i + # Replace all uninstalled libtool libraries with the installed ones + newdependency_libs= + for deplib in $dependency_libs; do + case $deplib in + *.la) + func_basename "$deplib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + test -z "$libdir" && \ + func_fatal_error "\`$deplib' is not a valid libtool archive" + newdependency_libs="$newdependency_libs $libdir/$name" + ;; + *) newdependency_libs="$newdependency_libs $deplib" ;; + esac + done + dependency_libs="$newdependency_libs" + newdlfiles= + + for lib in $dlfiles; do + case $lib in + *.la) + func_basename "$lib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "\`$lib' is not a valid libtool archive" + newdlfiles="$newdlfiles $libdir/$name" + ;; + *) newdlfiles="$newdlfiles $lib" ;; + esac + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + *.la) + # Only pass preopened files to the pseudo-archive (for + # eventual linking with the app. that links it) if we + # didn't already link the preopened objects directly into + # the library: + func_basename "$lib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "\`$lib' is not a valid libtool archive" + newdlprefiles="$newdlprefiles $libdir/$name" + ;; + esac + done + dlprefiles="$newdlprefiles" + else + newdlfiles= + for lib in $dlfiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + newdlfiles="$newdlfiles $abs" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + newdlprefiles="$newdlprefiles $abs" + done + dlprefiles="$newdlprefiles" + fi + $RM $output + # place dlname in correct position for cygwin + tdlname=$dlname + case $host,$output,$installed,$module,$dlname in + *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;; + esac + $ECHO > $output "\ +# $outputname - a libtool library file +# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='$tdlname' + +# Names of this library. +library_names='$library_names' + +# The name of the static archive. +old_library='$old_library' + +# Linker flags that can not go in dependency_libs. +inherited_linker_flags='$new_inherited_linker_flags' + +# Libraries that this one depends upon. +dependency_libs='$dependency_libs' + +# Names of additional weak libraries provided by this library +weak_library_names='$weak_libs' + +# Version information for $libname. +current=$current +age=$age +revision=$revision + +# Is this an already installed library? +installed=$installed + +# Should we warn about portability when linking against -modules? +shouldnotlink=$module + +# Files to dlopen/dlpreopen +dlopen='$dlfiles' +dlpreopen='$dlprefiles' + +# Directory that this library needs to be installed in: +libdir='$install_libdir'" + if test "$installed" = no && test "$need_relink" = yes; then + $ECHO >> $output "\ +relink_command=\"$relink_command\"" + fi + done + } + + # Do a symbolic link so that the libtool archive can be found in + # LD_LIBRARY_PATH before the program is installed. + func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' + ;; + esac + exit $EXIT_SUCCESS +} + +{ test "$mode" = link || test "$mode" = relink; } && + func_mode_link ${1+"$@"} + + +# func_mode_uninstall arg... +func_mode_uninstall () +{ + $opt_debug + RM="$nonopt" + files= + rmforce= + exit_status=0 + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + for arg + do + case $arg in + -f) RM="$RM $arg"; rmforce=yes ;; + -*) RM="$RM $arg" ;; + *) files="$files $arg" ;; + esac + done + + test -z "$RM" && \ + func_fatal_help "you must specify an RM program" + + rmdirs= + + origobjdir="$objdir" + for file in $files; do + func_dirname "$file" "" "." + dir="$func_dirname_result" + if test "X$dir" = X.; then + objdir="$origobjdir" + else + objdir="$dir/$origobjdir" + fi + func_basename "$file" + name="$func_basename_result" + test "$mode" = uninstall && objdir="$dir" + + # Remember objdir for removal later, being careful to avoid duplicates + if test "$mode" = clean; then + case " $rmdirs " in + *" $objdir "*) ;; + *) rmdirs="$rmdirs $objdir" ;; + esac + fi + + # Don't error if the file doesn't exist and rm -f was used. + if { test -L "$file"; } >/dev/null 2>&1 || + { test -h "$file"; } >/dev/null 2>&1 || + test -f "$file"; then + : + elif test -d "$file"; then + exit_status=1 + continue + elif test "$rmforce" = yes; then + continue + fi + + rmfiles="$file" + + case $name in + *.la) + # Possibly a libtool archive, so verify it. + if func_lalib_p "$file"; then + func_source $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + rmfiles="$rmfiles $objdir/$n" + done + test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library" + + case "$mode" in + clean) + case " $library_names " in + # " " in the beginning catches empty $dlname + *" $dlname "*) ;; + *) rmfiles="$rmfiles $objdir/$dlname" ;; + esac + test -n "$libdir" && rmfiles="$rmfiles $objdir/$name $objdir/${name}i" + ;; + uninstall) + if test -n "$library_names"; then + # Do each command in the postuninstall commands. + func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' + fi + + if test -n "$old_library"; then + # Do each command in the old_postuninstall commands. + func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' + fi + # FIXME: should reinstall the best remaining shared library. + ;; + esac + fi + ;; + + *.lo) + # Possibly a libtool object, so verify it. + if func_lalib_p "$file"; then + + # Read the .lo file + func_source $dir/$name + + # Add PIC object to the list of files to remove. + if test -n "$pic_object" && + test "$pic_object" != none; then + rmfiles="$rmfiles $dir/$pic_object" + fi + + # Add non-PIC object to the list of files to remove. + if test -n "$non_pic_object" && + test "$non_pic_object" != none; then + rmfiles="$rmfiles $dir/$non_pic_object" + fi + fi + ;; + + *) + if test "$mode" = clean ; then + noexename=$name + case $file in + *.exe) + func_stripname '' '.exe' "$file" + file=$func_stripname_result + func_stripname '' '.exe' "$name" + noexename=$func_stripname_result + # $file with .exe has already been added to rmfiles, + # add $file without .exe + rmfiles="$rmfiles $file" + ;; + esac + # Do a test to see if this is a libtool program. + if func_ltwrapper_p "$file"; then + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + relink_command= + func_source $func_ltwrapper_scriptname_result + rmfiles="$rmfiles $func_ltwrapper_scriptname_result" + else + relink_command= + func_source $dir/$noexename + fi + + # note $name still contains .exe if it was in $file originally + # as does the version of $file that was added into $rmfiles + rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}" + if test "$fast_install" = yes && test -n "$relink_command"; then + rmfiles="$rmfiles $objdir/lt-$name" + fi + if test "X$noexename" != "X$name" ; then + rmfiles="$rmfiles $objdir/lt-${noexename}.c" + fi + fi + fi + ;; + esac + func_show_eval "$RM $rmfiles" 'exit_status=1' + done + objdir="$origobjdir" + + # Try to remove the ${objdir}s in the directories where we deleted files + for dir in $rmdirs; do + if test -d "$dir"; then + func_show_eval "rmdir $dir >/dev/null 2>&1" + fi + done + + exit $exit_status +} + +{ test "$mode" = uninstall || test "$mode" = clean; } && + func_mode_uninstall ${1+"$@"} + +test -z "$mode" && { + help="$generic_help" + func_fatal_help "you must specify a MODE" +} + +test -z "$exec_cmd" && \ + func_fatal_help "invalid operation mode \`$mode'" + +if test -n "$exec_cmd"; then + eval exec "$exec_cmd" + exit $EXIT_FAILURE +fi + +exit $exit_status + + +# The TAGs below are defined such that we never get into a situation +# in which we disable both kinds of libraries. Given conflicting +# choices, we go for a static library, that is the most portable, +# since we can't tell whether shared libraries were disabled because +# the user asked for that or because the platform doesn't support +# them. This is particularly important on AIX, because we don't +# support having both static and shared libraries enabled at the same +# time on that platform, so we default to a shared-only configuration. +# If a disable-shared tag is given, we'll fallback to a static-only +# configuration. But we'll never go from static-only to shared-only. + +# ### BEGIN LIBTOOL TAG CONFIG: disable-shared +build_libtool_libs=no +build_old_libs=yes +# ### END LIBTOOL TAG CONFIG: disable-shared + +# ### BEGIN LIBTOOL TAG CONFIG: disable-static +build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` +# ### END LIBTOOL TAG CONFIG: disable-static + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: +# vi:sw=2 + diff --git a/apache2/configure b/apache2/configure new file mode 100755 index 0000000..ce64f39 --- /dev/null +++ b/apache2/configure @@ -0,0 +1,6499 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.64. +# +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software +# Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + # We cannot yet assume a decent shell, so we have to provide a + # neutralization value for shells without unset; and this also + # works around shells that cannot unset nonexistent variables. + BASH_ENV=/dev/null + ENV=/dev/null + (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error ERROR [LINENO LOG_FD] +# --------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with status $?, using 1 if that was 0. +as_fn_error () +{ + as_status=$?; test $as_status -eq 0 && as_status=1 + if test "$3"; then + as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 + fi + $as_echo "$as_me: error: $1" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= +PACKAGE_URL= + +ac_unique_file="mod_security2.c" +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='LTLIBOBJS +CURL_USES_GNUTLS +CURL_CFLAGS +CURL_LIBS +LUA_CFLAGS +LUA_LIBS +LIBXML2_CFLAGS +LIBXML2_LIBS +APU_LINK_LD +APU_LDFLAGS +APU_CFLAGS +APU_LIBS +APR_LINK_LD +APR_LDFLAGS +APR_CFLAGS +APR_LIBS +PCRE_CFLAGS +PCRE_LIBS +APXS_HTTPD +APXS_LIBEXECDIR +APXS_PROGNAME +APXS_SBINDIR +APXS_BINDIR +APXS_LIBDIR +APXS_CC +APXS_LIBTOOL +APXS_CFLAGS +APXS_LIBS +APXS_LDFLAGS +MODSEC_APXS_EXTRA_CFLAGS +APXS_EXTRA_CFLAGS +APXS_INCLUDES +APXS_INCLUDEDIR +APXS_WRAPPER +APXS +MODSEC_EXTRA_CFLAGS +EXTRA_CFLAGS +MSC_REGRESSION_DOCROOT_DIR +MSC_REGRESSION_LOGS_DIR +MSC_REGRESSION_CONF_DIR +MSC_REGRESSION_SERVERROOT_DIR +MSC_REGRESSION_DIR +MSC_TEST_DIR +MSC_PKGBASE_DIR +MSC_BASE_DIR +LIBOBJS +EGREP +ENV_CMD +PERL +GREP +RANLIB +SET_MAKE +LN_S +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +CPP +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +AWK +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +enable_errors +enable_verbose_output +enable_strict_compile +enable_debug_conf +enable_debug_cache +enable_debug_acmp +enable_debug_mem +enable_performance_measurement +enable_modsec_api +with_apxs +with_pcre +with_apr +with_apu +with_libxml +with_lua +with_curl +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CPP' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information." + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures this package to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF +_ACEOF +fi + +if test -n "$ac_init_help"; then + + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --disable-errors Disable errors during configure. + --enable-verbose-output Enable more verbose configure output. + --enable-strict-compile Enable strict compilation (warnings are errors). + --enable-debug-conf Enable debug during configuration. + --enable-debug-cache Enable debug for transformation caching. + --enable-debug-acmp Enable debugging acmp code. + --enable-debug-mem Enable debug during configuration. + --enable-performance-measurement + Enable performance-measurement stats. + --disable-modsec-api Disable the API; compiling against some older Apache + versions require this. + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-apxs=FILE FILE is the path to apxs; defaults to "apxs". + --with-pcre=PATH Path to pcre prefix or config script + --with-apr=PATH Path to apr prefix or config script + --with-apu=PATH Path to apu prefix or config script + --with-libxml=PATH Path to libxml2 prefix or config script + --with-lua=PATH Path to lua prefix or config script + --with-curl=PATH Path to curl prefix or config script + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to the package provider. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +configure +generated by GNU Autoconf 2.64 + +Copyright (C) 2009 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + return $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + return $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + return $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists, giving a warning if it cannot be compiled using +# the include files in INCLUDES and setting the cache variable VAR +# accordingly. +ac_fn_c_check_header_mongrel () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 +$as_echo_n "checking $2 usability... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_header_compiler=yes +else + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 +$as_echo_n "checking $2 presence... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <$2> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + ac_header_preproc=yes +else + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( + yes:no: ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; + no:yes:* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=\$ac_header_compiler" +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_check_header_mongrel + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_check_header_compile + +# ac_fn_c_check_type LINENO TYPE VAR INCLUDES +# ------------------------------------------- +# Tests whether TYPE exists after having included INCLUDES, setting cache +# variable VAR accordingly. +ac_fn_c_check_type () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=no" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof ($2)) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof (($2))) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + eval "$3=yes" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_check_type + +# ac_fn_c_find_uintX_t LINENO BITS VAR +# ------------------------------------ +# Finds an unsigned integer type with width BITS, setting cache variable VAR +# accordingly. +ac_fn_c_find_uintX_t () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint$2_t" >&5 +$as_echo_n "checking for uint$2_t... " >&6; } +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=no" + for ac_type in uint$2_t 'unsigned int' 'unsigned long int' \ + 'unsigned long long int' 'unsigned short int' 'unsigned char'; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(($ac_type) -1 >> ($2 - 1) == 1)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + case $ac_type in #( + uint$2_t) : + eval "$3=yes" ;; #( + *) : + eval "$3=\$ac_type" ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + eval as_val=\$$3 + if test "x$as_val" = x""no; then : + +else + break +fi + done +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_find_uintX_t + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + return $ac_retval + +} # ac_fn_c_try_link + +# ac_fn_c_check_func LINENO FUNC VAR +# ---------------------------------- +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_c_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case declares $2. + For example, HP-UX 11i declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $2 + +/* 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 $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_check_func +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by $as_me, which was +generated by GNU Autoconf 2.64. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------------- ## +## File substitutions. ## +## ------------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + ac_site_file1=$CONFIG_SITE +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +ac_config_headers="$ac_config_headers mod_security2_config.h" + +ac_aux_dir= +for ac_dir in build "$srcdir"/build; do + for ac_t in install-sh install.sh shtool; do + if test -f "$ac_dir/$ac_t"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/$ac_t -c" + break 2 + fi + done +done +if test -z "$ac_aux_dir"; then + as_fn_error "cannot find install-sh, install.sh, or shtool in build \"$srcdir\"/build" "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + + +# Checks for programs. +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_AWK+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AWK="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 +$as_echo "$AWK" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AWK" && break +done + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "no acceptable C compiler found in \$PATH +See \`config.log' for more details." "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + rm -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out conftest.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +if test -z "$ac_file"; then : + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ as_fn_set_status 77 +as_fn_error "C compiler cannot create executables +See \`config.log' for more details." "$LINENO" 5; }; } +fi +ac_exeext=$ac_cv_exeext + +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out conftest.out +ac_clean_files=$ac_clean_files_save +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." "$LINENO" 5; } +fi +rm -f conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if test "${ac_cv_objext+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "cannot compute suffix of object files: cannot compile +See \`config.log' for more details." "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if test "${ac_cv_c_compiler_gnu+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if test "${ac_cv_prog_cc_g+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if test "${ac_cv_prog_cc_c89+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in #(( + ./ | .// | /[cC]/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + + done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 +$as_echo_n "checking whether ln -s works... " >&6; } +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 +$as_echo "no, using $LN_S" >&6; } +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } +set x ${MAKE-make} +ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + SET_MAKE= +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_RANLIB+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +$as_echo "$RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +$as_echo "$ac_ct_RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if test "${ac_cv_path_GREP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +for ac_prog in perl perl5 +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_path_PERL+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + case $PERL in + [\\/]* | ?:[\\/]*) + ac_cv_path_PERL="$PERL" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_PERL="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PERL=$ac_cv_path_PERL +if test -n "$PERL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PERL" >&5 +$as_echo "$PERL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$PERL" && break +done + +for ac_prog in env printenv +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_path_ENV_CMD+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + case $ENV_CMD in + [\\/]* | ?:[\\/]*) + ac_cv_path_ENV_CMD="$ENV_CMD" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_ENV_CMD="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ENV_CMD=$ac_cv_path_ENV_CMD +if test -n "$ENV_CMD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ENV_CMD" >&5 +$as_echo "$ENV_CMD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ENV_CMD" && break +done + + +# Checks for header files. + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if test "${ac_cv_path_EGREP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if test "${ac_cv_header_stdc+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +eval as_val=\$$as_ac_Header + if test "x$as_val" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in fcntl.h limits.h stdlib.h string.h unistd.h sys/types.h sys/stat.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +eval as_val=\$$as_ac_Header + if test "x$as_val" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +# Checks for typedefs, structures, and compiler characteristics. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 +$as_echo_n "checking for an ANSI C-conforming const... " >&6; } +if test "${ac_cv_c_const+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +/* FIXME: Include the comments suggested by Paul. */ +#ifndef __cplusplus + /* Ultrix mips cc rejects this. */ + typedef int charset[2]; + const charset cs; + /* SunOS 4.1.1 cc rejects this. */ + char const *const *pcpcc; + char **ppc; + /* NEC SVR4.0.2 mips cc rejects this. */ + struct point {int x, y;}; + static struct point const zero = {0,0}; + /* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in + an arm of an if-expression whose if-part is not a constant + expression */ + const char *g = "string"; + pcpcc = &g + (g ? g-g : 0); + /* HPUX 7.0 cc rejects these. */ + ++pcpcc; + ppc = (char**) pcpcc; + pcpcc = (char const *const *) ppc; + { /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; + if (s) return 0; + } + { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; + } + { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; + } + { /* AIX XL C 1.02.0.0 rejects this saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; + } + { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; + if (!foo) return 0; + } + return !cs[0] && !zero.x; +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_const=yes +else + ac_cv_c_const=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5 +$as_echo "$ac_cv_c_const" >&6; } +if test $ac_cv_c_const = no; then + +$as_echo "#define const /**/" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 +$as_echo_n "checking for inline... " >&6; } +if test "${ac_cv_c_inline+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_c_inline=no +for ac_kw in inline __inline__ __inline; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifndef __cplusplus +typedef int foo_t; +static $ac_kw foo_t static_foo () {return 0; } +$ac_kw foo_t foo () {return 0; } +#endif + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_inline=$ac_kw +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + test "$ac_cv_c_inline" != no && break +done + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 +$as_echo "$ac_cv_c_inline" >&6; } + +case $ac_cv_c_inline in + inline | yes) ;; + *) + case $ac_cv_c_inline in + no) ac_val=;; + *) ac_val=$ac_cv_c_inline;; + esac + cat >>confdefs.h <<_ACEOF +#ifndef __cplusplus +#define inline $ac_val +#endif +_ACEOF + ;; +esac + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C/C++ restrict keyword" >&5 +$as_echo_n "checking for C/C++ restrict keyword... " >&6; } +if test "${ac_cv_c_restrict+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_c_restrict=no + # The order here caters to the fact that C++ does not require restrict. + for ac_kw in __restrict __restrict__ _Restrict restrict; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +typedef int * int_ptr; + int foo (int_ptr $ac_kw ip) { + return ip[0]; + } +int +main () +{ +int s[1]; + int * $ac_kw t = s; + t[0] = 0; + return foo(t) + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_restrict=$ac_kw +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + test "$ac_cv_c_restrict" != no && break + done + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_restrict" >&5 +$as_echo "$ac_cv_c_restrict" >&6; } + + case $ac_cv_c_restrict in + restrict) ;; + no) $as_echo "#define restrict /**/" >>confdefs.h + ;; + *) cat >>confdefs.h <<_ACEOF +#define restrict $ac_cv_c_restrict +_ACEOF + ;; + esac + +ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default" +if test "x$ac_cv_type_pid_t" = x""yes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define pid_t int +_ACEOF + +fi + +ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" +if test "x$ac_cv_type_size_t" = x""yes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define size_t unsigned int +_ACEOF + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5 +$as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; } +if test "${ac_cv_struct_tm+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include + +int +main () +{ +struct tm tm; + int *p = &tm.tm_sec; + return !p; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_struct_tm=time.h +else + ac_cv_struct_tm=sys/time.h +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_tm" >&5 +$as_echo "$ac_cv_struct_tm" >&6; } +if test $ac_cv_struct_tm = sys/time.h; then + +$as_echo "#define TM_IN_SYS_TIME 1" >>confdefs.h + +fi + +ac_fn_c_find_uintX_t "$LINENO" "8" "ac_cv_c_uint8_t" +case $ac_cv_c_uint8_t in #( + no|yes) ;; #( + *) + +$as_echo "#define _UINT8_T 1" >>confdefs.h + + +cat >>confdefs.h <<_ACEOF +#define uint8_t $ac_cv_c_uint8_t +_ACEOF +;; + esac + + +# Checks for library functions. +for ac_header in stdlib.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" +if test "x$ac_cv_header_stdlib_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STDLIB_H 1 +_ACEOF + +fi + +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible malloc" >&5 +$as_echo_n "checking for GNU libc compatible malloc... " >&6; } +if test "${ac_cv_func_malloc_0_nonnull+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ac_cv_func_malloc_0_nonnull=no +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#if defined STDC_HEADERS || defined HAVE_STDLIB_H +# include +#else +char *malloc (); +#endif + +int +main () +{ +return ! malloc (0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_func_malloc_0_nonnull=yes +else + ac_cv_func_malloc_0_nonnull=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_malloc_0_nonnull" >&5 +$as_echo "$ac_cv_func_malloc_0_nonnull" >&6; } +if test $ac_cv_func_malloc_0_nonnull = yes; then : + +$as_echo "#define HAVE_MALLOC 1" >>confdefs.h + +else + $as_echo "#define HAVE_MALLOC 0" >>confdefs.h + + case " $LIBOBJS " in + *" malloc.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS malloc.$ac_objext" + ;; +esac + + +$as_echo "#define malloc rpl_malloc" >>confdefs.h + +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working memcmp" >&5 +$as_echo_n "checking for working memcmp... " >&6; } +if test "${ac_cv_func_memcmp_working+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ac_cv_func_memcmp_working=no +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ + + /* Some versions of memcmp are not 8-bit clean. */ + char c0 = '\100', c1 = '\200', c2 = '\201'; + if (memcmp(&c0, &c2, 1) >= 0 || memcmp(&c1, &c2, 1) >= 0) + return 1; + + /* The Next x86 OpenStep bug shows up only when comparing 16 bytes + or more and with at least one buffer not starting on a 4-byte boundary. + William Lewis provided this test program. */ + { + char foo[21]; + char bar[21]; + int i; + for (i = 0; i < 4; i++) + { + char *a = foo + i; + char *b = bar + i; + strcpy (a, "--------01111111"); + strcpy (b, "--------10000000"); + if (memcmp (a, b, 16) >= 0) + return 1; + } + return 0; + } + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_func_memcmp_working=yes +else + ac_cv_func_memcmp_working=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_memcmp_working" >&5 +$as_echo "$ac_cv_func_memcmp_working" >&6; } +test $ac_cv_func_memcmp_working = no && case " $LIBOBJS " in + *" memcmp.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS memcmp.$ac_objext" + ;; +esac + + +for ac_func in atexit getcwd memmove memset strcasecmp strchr strdup strerror strncasecmp strrchr strstr strtol +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +eval as_val=\$$as_ac_var + if test "x$as_val" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + +# Some directories +MSC_BASE_DIR=`pwd` +MSC_PKGBASE_DIR="$MSC_BASE_DIR/.." +MSC_TEST_DIR="$MSC_BASE_DIR/t" +MSC_REGRESSION_DIR="$MSC_TEST_DIR/regression" +MSC_REGRESSION_SERVERROOT_DIR="$MSC_REGRESSION_DIR/server_root" +MSC_REGRESSION_CONF_DIR="$MSC_REGRESSION_SERVERROOT_DIR/conf" +MSC_REGRESSION_LOGS_DIR="$MSC_REGRESSION_SERVERROOT_DIR/logs" +MSC_REGRESSION_DOCROOT_DIR="$MSC_REGRESSION_SERVERROOT_DIR/htdocs" + + + + + + + + + + +### Configure Options + +# Ignore configure errors +# Check whether --enable-errors was given. +if test "${enable_errors+set}" = set; then : + enableval=$enable_errors; + if test "$enableval" != "no"; then + report_errors=1 + else + report_errors=0 + fi + +else + + report_errors=1 + +fi + + +# Verbose output +# Check whether --enable-verbose-output was given. +if test "${enable_verbose_output+set}" = set; then : + enableval=$enable_verbose_output; + if test "$enableval" != "no"; then + verbose_output=1 + else + verbose_output=0 + fi + +else + + verbose_output=0 + +fi + + +# Strict Compile +# Check whether --enable-strict-compile was given. +if test "${enable_strict_compile+set}" = set; then : + enableval=$enable_strict_compile; + if test "$enableval" != "no"; then + strict_compile="-std=c99 -Wstrict-overflow=1 -Wextra -Wno-missing-field-initializers -Wshadow -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes -Wno-unused-parameter -Wformat -Wformat-security -Werror -fstack-protector -D_FORTIFY_SOURCE=2" + else + strict_compile= + fi + +else + + strict_compile= + +fi + + +# DEBUG_CONF +# Check whether --enable-debug-conf was given. +if test "${enable_debug_conf+set}" = set; then : + enableval=$enable_debug_conf; + if test "$enableval" != "no"; then + debug_conf="-DDEBUG_CONF" + else + debug_conf= + fi + +else + + debug_conf= + +fi + + +# CACHE_DEBUG +# Check whether --enable-debug-cache was given. +if test "${enable_debug_cache+set}" = set; then : + enableval=$enable_debug_cache; + if test "$enableval" != "no"; then + debug_cache="-DCACHE_DEBUG" + else + debug_cache= + fi + +else + + debug_cache= + +fi + + +# DEBUG_ACMP +# Check whether --enable-debug-acmp was given. +if test "${enable_debug_acmp+set}" = set; then : + enableval=$enable_debug_acmp; + if test "$enableval" != "no"; then + debug_acmp="-DDEBUG_ACMP" + else + debug_acmp= + fi + +else + + debug_acmp= + +fi + + +# DEBUG_MEM +# Check whether --enable-debug-mem was given. +if test "${enable_debug_mem+set}" = set; then : + enableval=$enable_debug_mem; + if test "$enableval" != "no"; then + debug_mem="-DDEBUG_MEM" + else + debug_mem= + fi + +else + + debug_mem= + +fi + + +# PERFORMANCE_MEASUREMENT +# Check whether --enable-performance-measurement was given. +if test "${enable_performance_measurement+set}" = set; then : + enableval=$enable_performance_measurement; + if test "$enableval" != "no"; then + perf_meas="-DPERFORMANCE_MEASUREMENT" + else + perf_meas= + fi + +else + + perf_meas= + +fi + + +# NO_MODSEC_API +# Check whether --enable-modsec-api was given. +if test "${enable_modsec_api+set}" = set; then : + enableval=$enable_modsec_api; + if test "$enableval" != "yes"; then + modsec_api="-DNO_MODSEC_API" + else + modsec_api= + fi + +else + + modsec_api= + +fi + + +# Find apxs +{ $as_echo "$as_me:${as_lineno-$LINENO}: looking for Apache module support via DSO through APXS" >&5 +$as_echo "$as_me: looking for Apache module support via DSO through APXS" >&6;} + +# Check whether --with-apxs was given. +if test "${with_apxs+set}" = set; then : + withval=$with_apxs; + if test "$withval" = "yes"; then + APXS=apxs + else + APXS="$withval" + fi + +fi + + +if test -z "$APXS"; then + for i in /usr/local/apache22/bin \ + /usr/local/apache2/bin \ + /usr/local/apache/bin \ + /usr/local/sbin \ + /usr/local/bin \ + /usr/sbin \ + /usr/bin; + do + if test -f "$i/apxs2"; then + APXS="$i/apxs2" + break + elif test -f "$i/apxs"; then + APXS="$i/apxs" + break + fi + done +fi + +# arbitrarily picking the same version subversion looks for, don't know how +# accurate this really is, but at least it'll force us to have apache2... +HTTPD_WANTED_MMN=20020903 + +if test -n "$APXS" -a "$APXS" != "no" -a -x "$APXS" ; then + APXS_INCLUDE="`$APXS -q INCLUDEDIR`" + if test -r $APXS_INCLUDE/httpd.h; then + { $as_echo "$as_me:${as_lineno-$LINENO}: found apxs at $APXS" >&5 +$as_echo "$as_me: found apxs at $APXS" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: checking httpd version" >&5 +$as_echo "$as_me: checking httpd version" >&6;} + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include "$APXS_INCLUDE/ap_mmn.h" +#if AP_MODULE_MAGIC_AT_LEAST($HTTPD_WANTED_MMN,0) +VERSION_OK +#endif +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "VERSION_OK" >/dev/null 2>&1; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: httpd is recent enough" >&5 +$as_echo "$as_me: httpd is recent enough" >&6;} +else + + if test "$report_errors" -eq 1; then + { as_fn_set_status mmn must be at least $HTTPD_WANTED_MMN +as_fn_error "apache is too old" "$LINENO" 5; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: apache is too old" >&5 +$as_echo "$as_me: apache is too old" >&mmn must be at least $HTTPD_WANTED_MMN;} + fi + +fi +rm -f conftest* + + fi + APXS_INCLUDEDIR="`$APXS -q INCLUDEDIR`" + if test "$verbose_output" -eq 1; then { $as_echo "$as_me:${as_lineno-$LINENO}: apxs INCLUDEDIR: $APXS_INCLUDEDIR" >&5 +$as_echo "$as_me: apxs INCLUDEDIR: $APXS_INCLUDEDIR" >&6;}; fi + # Make sure the include dir is used + if test -n "$APXS_INCLUDEDIR"; then + APXS_INCLUDES="-I${APXS_INCLUDEDIR} `$APXS -q INCLUDES` `$APXS -q EXTRA_INCLUDES`" + else + APXS_INCLUDES="`$APXS -q INCLUDES` `$APXS -q EXTRA_INCLUDES`" + fi + if test "$verbose_output" -eq 1; then { $as_echo "$as_me:${as_lineno-$LINENO}: apxs INCLUDES: $APXS_INCLUDES" >&5 +$as_echo "$as_me: apxs INCLUDES: $APXS_INCLUDES" >&6;}; fi + APXS_CFLAGS="`$APXS -q CFLAGS` `$APXS -q EXTRA_CFLAGS`" + if test "$verbose_output" -eq 1; then { $as_echo "$as_me:${as_lineno-$LINENO}: apxs CFLAGS: $APXS_CFLAGS" >&5 +$as_echo "$as_me: apxs CFLAGS: $APXS_CFLAGS" >&6;}; fi + APXS_LDFLAGS="`$APXS -q LDFLAGS` `$APXS -q EXTRA_LDFLAGS`" + if test "$verbose_output" -eq 1; then { $as_echo "$as_me:${as_lineno-$LINENO}: apxs LDFLAGS: $APXS_LDFLAGS" >&5 +$as_echo "$as_me: apxs LDFLAGS: $APXS_LDFLAGS" >&6;}; fi + APXS_LIBDIR="`$APXS -q LIBDIR`" + if test "$verbose_output" -eq 1; then { $as_echo "$as_me:${as_lineno-$LINENO}: apxs LIBDIR: $APXS_LIBDIR" >&5 +$as_echo "$as_me: apxs LIBDIR: $APXS_LIBDIR" >&6;}; fi + # Make sure the lib dir is used + if test -n "$APXS_LIBDIR"; then + APXS_LIBS="-L{$APXS_LIBDIR} `$APXS -q LIBS` `$APXS -q EXTRA_LIBS`" + else + APXS_LIBS="`$APXS -q LIBS` `$APXS -q EXTRA_LIBS`" + fi + if test "$verbose_output" -eq 1; then { $as_echo "$as_me:${as_lineno-$LINENO}: apxs LIBS: $APXS_LIBS" >&5 +$as_echo "$as_me: apxs LIBS: $APXS_LIBS" >&6;}; fi + APXS_LIBTOOL="`$APXS -q LIBTOOL`" + if test "$verbose_output" -eq 1; then { $as_echo "$as_me:${as_lineno-$LINENO}: apxs LIBTOOL: $APXS_LIBTOOL" >&5 +$as_echo "$as_me: apxs LIBTOOL: $APXS_LIBTOOL" >&6;}; fi + APXS_CC="`$APXS -q CC`" + if test "$verbose_output" -eq 1; then { $as_echo "$as_me:${as_lineno-$LINENO}: apxs CC: $APXS_CC" >&5 +$as_echo "$as_me: apxs CC: $APXS_CC" >&6;}; fi + APXS_BINDIR="`$APXS -q BINDIR`" + if test "$verbose_output" -eq 1; then { $as_echo "$as_me:${as_lineno-$LINENO}: apxs BINDIR: $APXS_BINDIR" >&5 +$as_echo "$as_me: apxs BINDIR: $APXS_BINDIR" >&6;}; fi + APXS_SBINDIR="`$APXS -q SBINDIR`" + if test "$verbose_output" -eq 1; then { $as_echo "$as_me:${as_lineno-$LINENO}: apxs SBINDIR: $APXS_SBINDIR" >&5 +$as_echo "$as_me: apxs SBINDIR: $APXS_SBINDIR" >&6;}; fi + APXS_PROGNAME="`$APXS -q PROGNAME`" + if test "$verbose_output" -eq 1; then { $as_echo "$as_me:${as_lineno-$LINENO}: apxs PROGNAME: $APXS_PROGNAME" >&5 +$as_echo "$as_me: apxs PROGNAME: $APXS_PROGNAME" >&6;}; fi + APXS_LIBEXECDIR="`$APXS -q LIBEXECDIR`" + if test "$verbose_output" -eq 1; then { $as_echo "$as_me:${as_lineno-$LINENO}: apxs LIBEXECDIR: $APXS_LIBEXECDIR" >&5 +$as_echo "$as_me: apxs LIBEXECDIR: $APXS_LIBEXECDIR" >&6;}; fi + if test "$APXS_SBINDIR" = "/"; then + APXS_HTTPD="$APXS_SBINDIR/$APXS_PROGNAME" + else + APXS_HTTPD="$APXS_SBINDIR/$APXS_PROGNAME" + fi + if test "$verbose_output" -eq 1; then { $as_echo "$as_me:${as_lineno-$LINENO}: apxs HTTPD: $APXS_HTTPD" >&5 +$as_echo "$as_me: apxs HTTPD: $APXS_HTTPD" >&6;}; fi +else + if test "$report_errors" -eq 1; then + as_fn_error "couldn't find APXS" "$LINENO" 5 + else + { $as_echo "$as_me:${as_lineno-$LINENO}: couldn't find APXS" >&5 +$as_echo "$as_me: couldn't find APXS" >&6;} + fi +fi + +# Include M4 macros + +PCRE_CONFIG="" +PCRE_CFLAGS="" +PCRE_LIBS="" + + + + +APR_CONFIG="" +APR_CFLAGS="" +APR_LDFLAGS="" +APR_LIBS="" +APR_LINK_LD="" + + + + +APU_CONFIG="" +APU_CFLAGS="" +APU_LDFLAGS="" +APU_LIBS="" +APU_LINK_LD="" + + + + +LIBXML2_CONFIG="" +LIBXML2_CFLAGS="" +LIBXML2_LIBS="" + + + + +LUA_CONFIG="" +LUA_CFLAGS="" +LUA_LIBS="" +LUA_CONFIG=pkg-config +LUA_PKGNAMES="lua5.1 lua-5.1 lua_5.1 lua-51 lua_51 lua51 lua5 lua" +LUA_SONAMES="so la sl dll dylib" + + + + +CURL_CONFIG="" +CURL_CFLAGS="" +CURL_LIBS="" +CURL_MIN_VERSION="7.15.1" + + + + + +### Build *EXTRA_CFLAGS vars + +# Allow overriding EXTRA_CFLAGS +if $ENV_CMD | $GREP "^EXTRA_CFLAGS" > /dev/null 2>&1; then + if test -z "$debug_mem"; then + EXTRA_CFLAGS="$EXTRA_CFLAGS $strict_compile" + fi +else + if test -n "$debug_mem"; then + EXTRA_CFLAGS="-O0 -g -Wall" + else + EXTRA_CFLAGS="-O2 -g -Wall $strict_compile" + fi +fi +MODSEC_EXTRA_CFLAGS="$debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api" + +APXS_WRAPPER=build/apxs-wrapper +APXS_EXTRA_CFLAGS="" +for f in $EXTRA_CFLAGS; do + APXS_EXTRA_CFLAGS="$APXS_EXTRA_CFLAGS -Wc,$f" +done; +MODSEC_APXS_EXTRA_CFLAGS="" +for f in $MODSEC_EXTRA_CFLAGS; do + MODSEC_APXS_EXTRA_CFLAGS="$MODSEC_APXS_EXTRA_CFLAGS -Wc,$f" +done; + +### Substitute the vars + +save_CPPFLAGS=$CPPFLAGS +CPPFLAGS="$APXS_INCLUDES $CPPFLAGS" +save_LDFLAGS=$LDFLAGS +LDFLAGS="$APXS_LDFLAGS $LDFLAGS" + + + + + + + + + + + + + + + + + + + + + + + +# Check whether --with-pcre was given. +if test "${with_pcre+set}" = set; then : + withval=$with_pcre; test_paths="${with_pcre}" +else + test_paths="/usr/local/libpcre /usr/local/pcre /usr/local /opt/libpcre /opt/pcre /opt /usr" +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libpcre config script" >&5 +$as_echo_n "checking for libpcre config script... " >&6; } + +if test -z "${with_pcre}"; then + test_paths="/usr/local/pcre /usr/local /usr" +else + test_paths="${with_pcre}" +fi + +for x in ${test_paths}; do + if test ! -d "$x" -a -e "$x"; then + PCRE_CONFIG=$x + pcre_path="no" + break + fi + + for PCRE_CONFIG in pcre-config; do + if test -e "${x}/bin/${PCRE_CONFIG}"; then + pcre_path="${x}/bin" + break + elif test -e "${x}/${PCRE_CONFIG}"; then + pcre_path="${x}" + break + else + pcre_path="" + fi + done + if test -n "$pcre_path"; then + break + fi +done + CFLAGS=$save_CFLAGS + LDFLAGS=$save_LDFLAGS + +if test -n "${pcre_path}"; then + if test "${pcre_path}" != "no"; then + PCRE_CONFIG="${pcre_path}/${PCRE_CONFIG}" + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${PCRE_CONFIG}" >&5 +$as_echo "${PCRE_CONFIG}" >&6; } + PCRE_CFLAGS="`${PCRE_CONFIG} --cflags`" + if test "$verbose_output" -eq 1; then { $as_echo "$as_me:${as_lineno-$LINENO}: pcre CFLAGS: $PCRE_CFLAGS" >&5 +$as_echo "$as_me: pcre CFLAGS: $PCRE_CFLAGS" >&6;}; fi + PCRE_LIBS="`${PCRE_CONFIG} --libs`" + if test "$verbose_output" -eq 1; then { $as_echo "$as_me:${as_lineno-$LINENO}: pcre LIBS: $PCRE_LIBS" >&5 +$as_echo "$as_me: pcre LIBS: $PCRE_LIBS" >&6;}; fi + CFLAGS=$save_CFLAGS + LDFLAGS=$save_LDFLAGS +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + + +if test -z "${PCRE_LIBS}"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: *** pcre library not found." >&5 +$as_echo "$as_me: *** pcre library not found." >&6;} + as_fn_error "pcre library is required" "$LINENO" 5 +else + { $as_echo "$as_me:${as_lineno-$LINENO}: using '${PCRE_LIBS}' for pcre Library" >&5 +$as_echo "$as_me: using '${PCRE_LIBS}' for pcre Library" >&6;} + +fi + + + +# Check whether --with-apr was given. +if test "${with_apr+set}" = set; then : + withval=$with_apr; test_paths="${with_apr}" +else + test_paths="/usr/local/libapr /usr/local/apr /usr/local /opt/libapr /opt/apr /opt /usr" +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libapr config script" >&5 +$as_echo_n "checking for libapr config script... " >&6; } + +for x in ${test_paths}; do + if test ! -d "$x" -a -e "$x"; then + APR_CONFIG=$x + apr_path=no + break + fi + + for APR_CONFIG in apr-1-mt-config apr-1-config apr-config-1 apr-mt-config-1 apr-mt-config apr-config; do + if test -e "${x}/bin/${APR_CONFIG}"; then + apr_path="${x}/bin" + break + elif test -e "${x}/${APR_CONFIG}"; then + apr_path="${x}" + break + else + apr_path="" + fi + done + if test -n "$apr_path"; then + break + fi +done + +if test -n "${apr_path}"; then + if test "${apr_path}" != "no"; then + APR_CONFIG="${apr_path}/${APR_CONFIG}" + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${APR_CONFIG}" >&5 +$as_echo "${APR_CONFIG}" >&6; } + APR_CFLAGS="`${APR_CONFIG} --includes --cppflags --cflags`" + if test "$verbose_output" -eq 1; then { $as_echo "$as_me:${as_lineno-$LINENO}: apr CFLAGS: $APR_CFLAGS" >&5 +$as_echo "$as_me: apr CFLAGS: $APR_CFLAGS" >&6;}; fi + APR_LDFLAGS="`${APR_CONFIG} --ldflags`" + if test "$verbose_output" -eq 1; then { $as_echo "$as_me:${as_lineno-$LINENO}: apr LDFLAGS: $APR_LDFLAGS" >&5 +$as_echo "$as_me: apr LDFLAGS: $APR_LDFLAGS" >&6;}; fi + APR_LIBS="`${APR_CONFIG} --libs`" + if test "$verbose_output" -eq 1; then { $as_echo "$as_me:${as_lineno-$LINENO}: apr LIBS: $APR_LIBS" >&5 +$as_echo "$as_me: apr LIBS: $APR_LIBS" >&6;}; fi + APR_LINK_LD="`${APR_CONFIG} --link-ld`" + if test "$verbose_output" -eq 1; then { $as_echo "$as_me:${as_lineno-$LINENO}: apr LINK_LD: $APR_LINK_LD" >&5 +$as_echo "$as_me: apr LINK_LD: $APR_LINK_LD" >&6;}; fi + CFLAGS=$save_CFLAGS + LDFLAGS=$save_LDFLAGS +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + + + + +if test -z "${APR_LIBS}"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: *** apr library not found." >&5 +$as_echo "$as_me: *** apr library not found." >&6;} + as_fn_error "apr library is required" "$LINENO" 5 +else + { $as_echo "$as_me:${as_lineno-$LINENO}: using '${APR_LIBS}' for apr Library" >&5 +$as_echo "$as_me: using '${APR_LIBS}' for apr Library" >&6;} + +fi + + + +# Check whether --with-apu was given. +if test "${with_apu+set}" = set; then : + withval=$with_apu; test_paths="${with_apu}" +else + test_paths="/usr/local/libapr-util /usr/local/apr-util /usr/local/libapu /usr/local/apu /usr/local /opt/libapr-util /opt/apr-util /opt/libapu /opt/apu /opt /usr" +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libapu config script" >&5 +$as_echo_n "checking for libapu config script... " >&6; } + +for x in ${test_paths}; do + if test ! -d "$x" -a -e "$x"; then + APU_CONFIG=$x + apu_path="no" + break + fi + + for APU_CONFIG in apu-1-mt-config apu-1-config apu-config-1 apu-mt-config-1 apu-mt-config apu-config; do + if test -e "${x}/bin/${APU_CONFIG}"; then + apu_path="${x}/bin" + break + elif test -e "${x}/${APU_CONFIG}"; then + apu_path="${x}" + break + else + apu_path="" + fi + done + if test -n "$apu_path"; then + break + fi +done + +if test -n "${apu_path}"; then + if test "${apu_path}" != "no"; then + APU_CONFIG="${apu_path}/${APU_CONFIG}" + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${APU_CONFIG}" >&5 +$as_echo "${APU_CONFIG}" >&6; } + APU_CFLAGS="`${APU_CONFIG} --includes`" + if test "$verbose_output" -eq 1; then { $as_echo "$as_me:${as_lineno-$LINENO}: apu CFLAGS: $APU_CFLAGS" >&5 +$as_echo "$as_me: apu CFLAGS: $APU_CFLAGS" >&6;}; fi + APU_LDFLAGS="`${APU_CONFIG} --ldflags`" + if test "$verbose_output" -eq 1; then { $as_echo "$as_me:${as_lineno-$LINENO}: apu LDFLAGS: $APU_LDFLAGS" >&5 +$as_echo "$as_me: apu LDFLAGS: $APU_LDFLAGS" >&6;}; fi + APU_LIBS="`${APU_CONFIG} --libs`" + if test "$verbose_output" -eq 1; then { $as_echo "$as_me:${as_lineno-$LINENO}: apu LIBS: $APU_LIBS" >&5 +$as_echo "$as_me: apu LIBS: $APU_LIBS" >&6;}; fi + APU_LINK_LD="`${APU_CONFIG} --link-ld`" + if test "$verbose_output" -eq 1; then { $as_echo "$as_me:${as_lineno-$LINENO}: apu LINK_LD: $APU_LINK_LD" >&5 +$as_echo "$as_me: apu LINK_LD: $APU_LINK_LD" >&6;}; fi + CFLAGS=$save_CFLAGS + LDFLAGS=$save_LDFLAGS +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + + + + +if test -z "${APU_LIBS}"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: *** apu library not found." >&5 +$as_echo "$as_me: *** apu library not found." >&6;} + as_fn_error "apu library is required" "$LINENO" 5 +else + { $as_echo "$as_me:${as_lineno-$LINENO}: using '${APU_LIBS}' for apu Library" >&5 +$as_echo "$as_me: using '${APU_LIBS}' for apu Library" >&6;} + +fi + + + +# Check whether --with-libxml was given. +if test "${with_libxml+set}" = set; then : + withval=$with_libxml; test_paths="${with_libxml}" +else + test_paths="/usr/local/libxml2 /usr/local/xml2 /usr/local/xml /usr/local /opt/libxml2 /opt/libxml /opt/xml2 /opt/xml /opt /usr" +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libxml2 config script" >&5 +$as_echo_n "checking for libxml2 config script... " >&6; } + +for x in ${test_paths}; do + if test ! -d "$x" -a -e "$x"; then + LIBXML2_CONFIG=$x + libxml2_path="no" + break + fi + + for LIBXML2_CONFIG in xml2-config xml-2-config xml-config; do + if test -e "${x}/bin/${LIBXML2_CONFIG}"; then + libxml2_path="${x}/bin" + break + elif test -e "${x}/${LIBXML2_CONFIG}"; then + libxml2_path="${x}" + break + else + libxml2_path="" + fi + done + if test -n "$libxml2_path"; then + break + fi +done + CFLAGS=$save_CFLAGS + LDFLAGS=$save_LDFLAGS + +if test -n "${libxml2_path}"; then + if test "${libxml2_path}" != "no"; then + LIBXML2_CONFIG="${libxml2_path}/${LIBXML2_CONFIG}" + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${LIBXML2_CONFIG}" >&5 +$as_echo "${LIBXML2_CONFIG}" >&6; } + LIBXML2_CFLAGS="`${LIBXML2_CONFIG} --cflags`" + if test "$verbose_output" -eq 1; then { $as_echo "$as_me:${as_lineno-$LINENO}: xml CFLAGS: $LIBXML2_CFLAGS" >&5 +$as_echo "$as_me: xml CFLAGS: $LIBXML2_CFLAGS" >&6;}; fi + LIBXML2_LIBS="`${LIBXML2_CONFIG} --libs`" + if test "$verbose_output" -eq 1; then { $as_echo "$as_me:${as_lineno-$LINENO}: xml LIBS: $LIBXML2_LIBS" >&5 +$as_echo "$as_me: xml LIBS: $LIBXML2_LIBS" >&6;}; fi + CFLAGS=$save_CFLAGS + LDFLAGS=$save_LDFLAGS +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + + +if test -z "${LIBXML2_LIBS}"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: *** xml library not found." >&5 +$as_echo "$as_me: *** xml library not found." >&6;} + as_fn_error "libxml2 is required" "$LINENO" 5 +else + { $as_echo "$as_me:${as_lineno-$LINENO}: using '${LIBXML2_LIBS}' for libxml2" >&5 +$as_echo "$as_me: using '${LIBXML2_LIBS}' for libxml2" >&6;} + +fi + + + +# Check whether --with-lua was given. +if test "${with_lua+set}" = set; then : + withval=$with_lua; test_paths="${with_lua}" +else + test_paths="/usr/local/liblua /usr/local/lua /usr/local /opt/liblua /opt/lua /opt /usr"; +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for liblua config script" >&5 +$as_echo_n "checking for liblua config script... " >&6; } + +for x in ${test_paths}; do + if test ! -d "$x" -a -e "$x"; then + LUA_CONFIG=$x + break + fi + + for y in $LUA_CONFIG; do + if test -e "${x}/bin/${y}"; then + LUA_CONFIG="${x}/bin/${y}" + lua_config="${LUA_CONFIG}" + break + elif test -e "${x}/${y}"; then + LUA_CONFIG="${x}/${y}" + lua_config="${LUA_CONFIG}" + break + fi + done + if test -n "${lua_config}"; then + break + fi +done + +if test -n "${LUA_CONFIG}"; then + LUA_PKGNAME="" + for x in ${LUA_PKGNAMES}; do + if ${LUA_CONFIG} --exists ${x}; then + LUA_PKGNAME="$x" + break + fi + done +fi + +if test -n "${LUA_PKGNAME}"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${LUA_CONFIG}" >&5 +$as_echo "${LUA_CONFIG}" >&6; } + LUA_CFLAGS="`${LUA_CONFIG} ${LUA_PKGNAME} --cflags`" + if test "$verbose_output" -eq 1; then { $as_echo "$as_me:${as_lineno-$LINENO}: lua CFLAGS: $LUA_CFLAGS" >&5 +$as_echo "$as_me: lua CFLAGS: $LUA_CFLAGS" >&6;}; fi + LUA_LIBS="`${LUA_CONFIG} ${LUA_PKGNAME} --libs`" + if test "$verbose_output" -eq 1; then { $as_echo "$as_me:${as_lineno-$LINENO}: lua LIBS: $LUA_LIBS" >&5 +$as_echo "$as_me: lua LIBS: $LUA_LIBS" >&6;}; fi + CFLAGS=$save_CFLAGS + LDFLAGS=$save_LDFLAGS +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for lua install" >&5 +$as_echo_n "checking for lua install... " >&6; } + for x in ${test_paths}; do + for y in ${LUA_SONAMES}; do + if test -e "${x}/liblua5.1.${y}"; then + lua_lib_path="${x}" + lua_lib_name="lua5.1" + break + elif test -e "${x}/lib/liblua5.1.${y}"; then + lua_lib_path="${x}/lib" + lua_lib_name="lua5.1" + break + elif test -e "${x}/lib64/liblua5.1.${y}"; then + lua_lib_path="${x}/lib64" + lua_lib_name="lua5.1" + break + elif test -e "${x}/lib32/liblua5.1.${y}"; then + lua_lib_path="${x}/lib32" + lua_lib_name="lua5.1" + break + elif test -e "${x}/liblua51.${y}"; then + lua_lib_path="${x}" + lua_lib_name="lua51" + break + elif test -e "${x}/lib/liblua51.${y}"; then + lua_lib_path="${x}/lib" + lua_lib_name="lua51" + break + elif test -e "${x}/lib64/liblua51.${y}"; then + lua_lib_path="${x}/lib64" + lua_lib_name="lua51" + break + elif test -e "${x}/lib32/liblua51.${y}"; then + lua_lib_path="${x}/lib32" + lua_lib_name="lua51" + break + elif test -e "${x}/liblua.${y}"; then + lua_lib_path="${x}" + lua_lib_name="lua" + break + elif test -e "${x}/lib/liblua.${y}"; then + lua_lib_path="${x}/lib" + lua_lib_name="lua" + break + elif test -e "${x}/lib64/liblua.${y}"; then + lua_lib_path="${x}/lib64" + lua_lib_name="lua" + break + elif test -e "${x}/lib32/liblua.${y}"; then + lua_lib_path="${x}/lib32" + lua_lib_name="lua" + break + else + lua_lib_path="" + lua_lib_name="" + fi + done + if test -n "$lua_lib_path"; then + break + fi + done + for x in ${test_paths}; do + if test -e "${x}/include/lua.h"; then + lua_inc_path="${x}/include" + break + elif test -e "${x}/lua.h"; then + lua_inc_path="${x}" + break + fi + + for lua_pkg_name in ${lua_lib_name} ${LUA_PKGNAMES}; do + if test -e "${x}/include/${lua_pkg_name}/lua.h"; then + lua_inc_path="${x}/include" + break + elif test -e "${x}/${lua_pkg_name}/lua.h"; then + lua_inc_path="${x}" + break + else + lua_inc_path="" + fi + done + if test -n "$lua_inc_path"; then + break + fi + done + if test -n "${lua_lib_path}" -a -n "${lua_inc_path}"; then + LUA_CONFIG="" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lua_lib_path} ${lua_inc_path}" >&5 +$as_echo "${lua_lib_path} ${lua_inc_path}" >&6; } + LUA_CFLAGS="-I${lua_inc_path}" + LUA_LIBS="-L${lua_lib_path} -l${lua_lib_name}" + CFLAGS=$save_CFLAGS + LDFLAGS=$save_LDFLAGS + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi +fi + +if test -n "${LUA_LIBS}"; then + LUA_CFLAGS="-DWITH_LUA ${LUA_CFLAGS}" +fi + + + + +if test "${with_path}" != "no"; then + if test -z "${LUA_LIBS}"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: optional lua library not found" >&5 +$as_echo "$as_me: optional lua library not found" >&6;} + else + { $as_echo "$as_me:${as_lineno-$LINENO}: using '${LUA_LIBS}' for lua Library" >&5 +$as_echo "$as_me: using '${LUA_LIBS}' for lua Library" >&6;} + + fi +fi + + + +# Check whether --with-curl was given. +if test "${with_curl+set}" = set; then : + withval=$with_curl; test_paths="${with_curl}" +else + test_paths="/usr/local/libcurl /usr/local/curl /usr/local /opt/libcurl /opt/curl /opt /usr" +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libcurl config script" >&5 +$as_echo_n "checking for libcurl config script... " >&6; } + +for x in ${test_paths}; do + if test ! -d "$x" -a -e "$x"; then + CURL_CONFIG=$x + curl_path="no" + break + fi + + for CURL_CONFIG in curl-config; do + if test -e "${x}/bin/${CURL_CONFIG}"; then + curl_path="${x}/bin" + break + elif test -e "${x}/${CURL_CONFIG}"; then + curl_path="${x}" + break + else + curl_path="" + fi + done + if test -n "$curl_path"; then + break + fi +done + +if test -n "${curl_path}"; then + if test "${curl_path}" != "no"; then + CURL_CONFIG="${curl_path}/${CURL_CONFIG}" + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${CURL_CONFIG}" >&5 +$as_echo "${CURL_CONFIG}" >&6; } + CURL_CFLAGS="`${CURL_CONFIG} --cflags`" + if test "$verbose_output" -eq 1; then { $as_echo "$as_me:${as_lineno-$LINENO}: curl CFLAGS: $CURL_CFLAGS" >&5 +$as_echo "$as_me: curl CFLAGS: $CURL_CFLAGS" >&6;}; fi + CURL_LIBS="`${CURL_CONFIG} --libs`" + if test "$verbose_output" -eq 1; then { $as_echo "$as_me:${as_lineno-$LINENO}: curl LIBS: $CURL_LIBS" >&5 +$as_echo "$as_me: curl LIBS: $CURL_LIBS" >&6;}; fi + CURL_VERSION=`${CURL_CONFIG} --version | sed 's/^[^0-9][^[:space:]][^[:space:]]*[[:space:]]*//'` + if test "$verbose_output" -eq 1; then { $as_echo "$as_me:${as_lineno-$LINENO}: curl VERSION: $CURL_VERSION" >&5 +$as_echo "$as_me: curl VERSION: $CURL_VERSION" >&6;}; fi + CFLAGS=$save_CFLAGS + LDFLAGS=$save_LDFLAGS + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libcurl is at least v${CURL_MIN_VERSION}" >&5 +$as_echo_n "checking if libcurl is at least v${CURL_MIN_VERSION}... " >&6; } + curl_min_ver=`echo ${CURL_MIN_VERSION} | awk -F. '{print (\$ 1 * 1000000) + (\$ 2 * 1000) + \$ 3}'` + curl_ver=`echo ${CURL_VERSION} | awk -F. '{print (\$ 1 * 1000000) + (\$ 2 * 1000) + \$ 3}'` + if test "$curl_min_ver" -le "$curl_ver"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: NOTE: curl library may be too old: $CURL_VERSION" >&5 +$as_echo "$as_me: NOTE: curl library may be too old: $CURL_VERSION" >&6;} + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libcurl is linked with gnutls" >&5 +$as_echo_n "checking if libcurl is linked with gnutls... " >&6; } + curl_uses_gnutls=`echo ${CURL_LIBS} | grep gnutls | wc -l` + if test "$curl_uses_gnutls" -ne 0; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: NOTE: curl linked with gnutls may be buggy, openssl recommended" >&5 +$as_echo "$as_me: NOTE: curl linked with gnutls may be buggy, openssl recommended" >&6;} + CURL_USES_GNUTLS=yes + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + CURL_USES_GNUTLS=no + fi + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + + + +if test -z "${CURL_LIBS}"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: *** curl library not found." >&5 +$as_echo "$as_me: *** curl library not found." >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: NOTE: curl library is only required for building mlogc" >&5 +$as_echo "$as_me: NOTE: curl library is only required for building mlogc" >&6;} +else + { $as_echo "$as_me:${as_lineno-$LINENO}: using '${CURL_LIBS}' for curl Library" >&5 +$as_echo "$as_me: using '${CURL_LIBS}' for curl Library" >&6;} + +fi + + +ac_config_files="$ac_config_files Makefile" + +ac_config_files="$ac_config_files build/apxs-wrapper" + +if test -e "$PERL"; then + ac_config_files="$ac_config_files mlogc-src/mlogc-batch-load.pl" + + ac_config_files="$ac_config_files t/run-unit-tests.pl" + + ac_config_files="$ac_config_files t/run-regression-tests.pl" + + ac_config_files="$ac_config_files t/gen_rx-pm.pl" + + ac_config_files="$ac_config_files t/csv_rx-pm.pl" + + ac_config_files="$ac_config_files t/regression/server_root/conf/httpd.conf" + + + # Perl based tools + ac_config_files="$ac_config_files ../tools/rules-updater.pl" + +fi +if test -e "mlogc-src/Makefile.in"; then + ac_config_files="$ac_config_files mlogc-src/Makefile" + +fi + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + test "x$cache_file" != "x/dev/null" && + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + cat confcache >$cache_file + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +: ${CONFIG_STATUS=./config.status} +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error ERROR [LINENO LOG_FD] +# --------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with status $?, using 1 if that was 0. +as_fn_error () +{ + as_status=$?; test $as_status -eq 0 && as_status=1 + if test "$3"; then + as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 + fi + $as_echo "$as_me: error: $1" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by $as_me, which was +generated by GNU Autoconf 2.64. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + +case $ac_config_headers in *" +"*) set x $ac_config_headers; shift; ac_config_headers=$*;; +esac + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Report bugs to the package provider." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_version="\\ +config.status +configured by $0, generated by GNU Autoconf 2.64, + with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2009 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +AWK='$AWK' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_HEADERS " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + as_fn_error "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; + --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "mod_security2_config.h") CONFIG_HEADERS="$CONFIG_HEADERS mod_security2_config.h" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "build/apxs-wrapper") CONFIG_FILES="$CONFIG_FILES build/apxs-wrapper" ;; + "mlogc-src/mlogc-batch-load.pl") CONFIG_FILES="$CONFIG_FILES mlogc-src/mlogc-batch-load.pl" ;; + "t/run-unit-tests.pl") CONFIG_FILES="$CONFIG_FILES t/run-unit-tests.pl" ;; + "t/run-regression-tests.pl") CONFIG_FILES="$CONFIG_FILES t/run-regression-tests.pl" ;; + "t/gen_rx-pm.pl") CONFIG_FILES="$CONFIG_FILES t/gen_rx-pm.pl" ;; + "t/csv_rx-pm.pl") CONFIG_FILES="$CONFIG_FILES t/csv_rx-pm.pl" ;; + "t/regression/server_root/conf/httpd.conf") CONFIG_FILES="$CONFIG_FILES t/regression/server_root/conf/httpd.conf" ;; + "../tools/rules-updater.pl") CONFIG_FILES="$CONFIG_FILES ../tools/rules-updater.pl" ;; + "mlogc-src/Makefile") CONFIG_FILES="$CONFIG_FILES mlogc-src/Makefile" ;; + + *) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= + trap 'exit_status=$? + { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error "cannot create a temporary directory in ." "$LINENO" 5 + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\).*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\).*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ + || as_fn_error "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/ +s/:*\${srcdir}:*/:/ +s/:*@srcdir@:*/:/ +s/^\([^=]*=[ ]*\):*/\1/ +s/:*$// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$tmp/defines.awk" <<\_ACAWK || +BEGIN { +_ACEOF + +# Transform confdefs.h into an awk script `defines.awk', embedded as +# here-document in config.status, that substitutes the proper values into +# config.h.in to produce config.h. + +# Create a delimiter string that does not exist in confdefs.h, to ease +# handling of long lines. +ac_delim='%!_!# ' +for ac_last_try in false false :; do + ac_t=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_t"; then + break + elif $ac_last_try; then + as_fn_error "could not make $CONFIG_HEADERS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +# For the awk script, D is an array of macro values keyed by name, +# likewise P contains macro parameters if any. Preserve backslash +# newline sequences. + +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +sed -n ' +s/.\{148\}/&'"$ac_delim"'/g +t rset +:rset +s/^[ ]*#[ ]*define[ ][ ]*/ / +t def +d +:def +s/\\$// +t bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3"/p +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p +d +:bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3\\\\\\n"\\/p +t cont +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p +t cont +d +:cont +n +s/.\{148\}/&'"$ac_delim"'/g +t clear +:clear +s/\\$// +t bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/"/p +d +:bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p +b cont +' >$CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { + line = \$ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + as_fn_error "could not setup config headers machinery" "$LINENO" 5 +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$tmp/stdin" \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&2;} + + rm -f "$tmp/stdin" + case $ac_file in + -) cat "$tmp/out" && rm -f "$tmp/out";; + *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; + esac \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 + ;; + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" + } >"$tmp/config.h" \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +$as_echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$tmp/config.h" "$ac_file" \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error "could not create -" "$LINENO" 5 + fi + ;; + + + esac + + + case $ac_file$ac_mode in + "build/apxs-wrapper":F) chmod +x build/apxs-wrapper ;; + "mlogc-src/mlogc-batch-load.pl":F) chmod +x mlogc-src/mlogc-batch-load.pl ;; + "t/run-unit-tests.pl":F) chmod +x t/run-unit-tests.pl ;; + "t/run-regression-tests.pl":F) chmod +x t/run-regression-tests.pl ;; + "t/gen_rx-pm.pl":F) chmod +x t/gen_rx-pm.pl ;; + "t/csv_rx-pm.pl":F) chmod +x t/csv_rx-pm.pl ;; + "../tools/rules-updater.pl":F) chmod +x ../tools/rules-updater.pl ;; + + esac +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit $? +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + diff --git a/apache2/configure.in b/apache2/configure.in new file mode 100644 index 0000000..9052468 --- /dev/null +++ b/apache2/configure.in @@ -0,0 +1,391 @@ +dnl +dnl Autoconf configuration for ModSecurity +dnl +dnl Use ./buildconf to produce a configure script +dnl + +AC_PREREQ(2.63) + +AC_INIT +dnl AC_INIT(ModSecurity, 2.5, mod-security-users@lists.sourceforge.net, modsecurity-apache) +AC_CONFIG_SRCDIR([mod_security2.c]) +AC_CONFIG_HEADER([mod_security2_config.h]) +AC_CONFIG_AUX_DIR([build]) + +# Checks for programs. +AC_PROG_AWK +AC_PROG_CC +AC_PROG_CPP +AC_PROG_INSTALL +AC_PROG_LN_S +AC_PROG_MAKE_SET +AC_PROG_RANLIB +AC_PROG_GREP +AC_PATH_PROGS(PERL, [perl perl5], ) +AC_PATH_PROGS(ENV_CMD, [env printenv], ) + +# Checks for header files. +AC_HEADER_STDC +AC_CHECK_HEADERS([fcntl.h limits.h stdlib.h string.h unistd.h sys/types.h sys/stat.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_C_INLINE +AC_C_RESTRICT +AC_TYPE_PID_T +AC_TYPE_SIZE_T +AC_STRUCT_TM +AC_TYPE_UINT8_T + +# Checks for library functions. +AC_FUNC_MALLOC +AC_FUNC_MEMCMP +AC_CHECK_FUNCS([atexit getcwd memmove memset strcasecmp strchr strdup strerror strncasecmp strrchr strstr strtol]) + +# Some directories +MSC_BASE_DIR=`pwd` +MSC_PKGBASE_DIR="$MSC_BASE_DIR/.." +MSC_TEST_DIR="$MSC_BASE_DIR/t" +MSC_REGRESSION_DIR="$MSC_TEST_DIR/regression" +MSC_REGRESSION_SERVERROOT_DIR="$MSC_REGRESSION_DIR/server_root" +MSC_REGRESSION_CONF_DIR="$MSC_REGRESSION_SERVERROOT_DIR/conf" +MSC_REGRESSION_LOGS_DIR="$MSC_REGRESSION_SERVERROOT_DIR/logs" +MSC_REGRESSION_DOCROOT_DIR="$MSC_REGRESSION_SERVERROOT_DIR/htdocs" + +AC_SUBST(MSC_BASE_DIR) +AC_SUBST(MSC_PKGBASE_DIR) +AC_SUBST(MSC_TEST_DIR) +AC_SUBST(MSC_REGRESSION_DIR) +AC_SUBST(MSC_REGRESSION_SERVERROOT_DIR) +AC_SUBST(MSC_REGRESSION_CONF_DIR) +AC_SUBST(MSC_REGRESSION_LOGS_DIR) +AC_SUBST(MSC_REGRESSION_DOCROOT_DIR) + +### Configure Options + +# Ignore configure errors +AC_ARG_ENABLE(errors, + AS_HELP_STRING([--disable-errors], + [Disable errors during configure.]), +[ + if test "$enableval" != "no"; then + report_errors=1 + else + report_errors=0 + fi +], +[ + report_errors=1 +]) + +# Verbose output +AC_ARG_ENABLE(verbose-output, + AS_HELP_STRING([--enable-verbose-output], + [Enable more verbose configure output.]), +[ + if test "$enableval" != "no"; then + verbose_output=1 + else + verbose_output=0 + fi +], +[ + verbose_output=0 +]) + +# Strict Compile +AC_ARG_ENABLE(strict-compile, + AS_HELP_STRING([--enable-strict-compile], + [Enable strict compilation (warnings are errors).]), +[ + if test "$enableval" != "no"; then + strict_compile="-std=c99 -Wstrict-overflow=1 -Wextra -Wno-missing-field-initializers -Wshadow -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes -Wno-unused-parameter -Wformat -Wformat-security -Werror -fstack-protector -D_FORTIFY_SOURCE=2" + else + strict_compile= + fi +], +[ + strict_compile= +]) + +# DEBUG_CONF +AC_ARG_ENABLE(debug-conf, + AS_HELP_STRING([--enable-debug-conf], + [Enable debug during configuration.]), +[ + if test "$enableval" != "no"; then + debug_conf="-DDEBUG_CONF" + else + debug_conf= + fi +], +[ + debug_conf= +]) + +# CACHE_DEBUG +AC_ARG_ENABLE(debug-cache, + AS_HELP_STRING([--enable-debug-cache], + [Enable debug for transformation caching.]), +[ + if test "$enableval" != "no"; then + debug_cache="-DCACHE_DEBUG" + else + debug_cache= + fi +], +[ + debug_cache= +]) + +# DEBUG_ACMP +AC_ARG_ENABLE(debug-acmp, + AS_HELP_STRING([--enable-debug-acmp], + [Enable debugging acmp code.]), +[ + if test "$enableval" != "no"; then + debug_acmp="-DDEBUG_ACMP" + else + debug_acmp= + fi +], +[ + debug_acmp= +]) + +# DEBUG_MEM +AC_ARG_ENABLE(debug-mem, + AS_HELP_STRING([--enable-debug-mem], + [Enable debug during configuration.]), +[ + if test "$enableval" != "no"; then + debug_mem="-DDEBUG_MEM" + else + debug_mem= + fi +], +[ + debug_mem= +]) + +# PERFORMANCE_MEASUREMENT +AC_ARG_ENABLE(performance-measurement, + AS_HELP_STRING([--enable-performance-measurement], + [Enable performance-measurement stats.]), +[ + if test "$enableval" != "no"; then + perf_meas="-DPERFORMANCE_MEASUREMENT" + else + perf_meas= + fi +], +[ + perf_meas= +]) + +# NO_MODSEC_API +AC_ARG_ENABLE(modsec-api, + AS_HELP_STRING([--disable-modsec-api], + [Disable the API; compiling against some older Apache versions require this.]), +[ + if test "$enableval" != "yes"; then + modsec_api="-DNO_MODSEC_API" + else + modsec_api= + fi +], +[ + modsec_api= +]) + +# Find apxs +AC_MSG_NOTICE(looking for Apache module support via DSO through APXS) +AC_ARG_WITH(apxs, + [AS_HELP_STRING([[--with-apxs=FILE]], + [FILE is the path to apxs; defaults to "apxs".])], +[ + if test "$withval" = "yes"; then + APXS=apxs + else + APXS="$withval" + fi +]) + +if test -z "$APXS"; then + for i in /usr/local/apache22/bin \ + /usr/local/apache2/bin \ + /usr/local/apache/bin \ + /usr/local/sbin \ + /usr/local/bin \ + /usr/sbin \ + /usr/bin; + do + if test -f "$i/apxs2"; then + APXS="$i/apxs2" + break + elif test -f "$i/apxs"; then + APXS="$i/apxs" + break + fi + done +fi + +# arbitrarily picking the same version subversion looks for, don't know how +# accurate this really is, but at least it'll force us to have apache2... +HTTPD_WANTED_MMN=20020903 + +if test -n "$APXS" -a "$APXS" != "no" -a -x "$APXS" ; then + APXS_INCLUDE="`$APXS -q INCLUDEDIR`" + if test -r $APXS_INCLUDE/httpd.h; then + AC_MSG_NOTICE(found apxs at $APXS) + AC_MSG_NOTICE(checking httpd version) + AC_EGREP_CPP(VERSION_OK, + [ +#include "$APXS_INCLUDE/ap_mmn.h" +#if AP_MODULE_MAGIC_AT_LEAST($HTTPD_WANTED_MMN,0) +VERSION_OK +#endif], + [AC_MSG_NOTICE(httpd is recent enough)], + [ + if test "$report_errors" -eq 1; then + AC_MSG_ERROR(apache is too old, mmn must be at least $HTTPD_WANTED_MMN) + else + AC_MSG_NOTICE(apache is too old, mmn must be at least $HTTPD_WANTED_MMN) + fi + ]) + fi + APXS_INCLUDEDIR="`$APXS -q INCLUDEDIR`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs INCLUDEDIR: $APXS_INCLUDEDIR); fi + # Make sure the include dir is used + if test -n "$APXS_INCLUDEDIR"; then + APXS_INCLUDES="-I${APXS_INCLUDEDIR} `$APXS -q INCLUDES` `$APXS -q EXTRA_INCLUDES`" + else + APXS_INCLUDES="`$APXS -q INCLUDES` `$APXS -q EXTRA_INCLUDES`" + fi + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs INCLUDES: $APXS_INCLUDES); fi + APXS_CFLAGS="`$APXS -q CFLAGS` `$APXS -q EXTRA_CFLAGS`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs CFLAGS: $APXS_CFLAGS); fi + APXS_LDFLAGS="`$APXS -q LDFLAGS` `$APXS -q EXTRA_LDFLAGS`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs LDFLAGS: $APXS_LDFLAGS); fi + APXS_LIBDIR="`$APXS -q LIBDIR`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs LIBDIR: $APXS_LIBDIR); fi + # Make sure the lib dir is used + if test -n "$APXS_LIBDIR"; then + APXS_LIBS="-L{$APXS_LIBDIR} `$APXS -q LIBS` `$APXS -q EXTRA_LIBS`" + else + APXS_LIBS="`$APXS -q LIBS` `$APXS -q EXTRA_LIBS`" + fi + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs LIBS: $APXS_LIBS); fi + APXS_LIBTOOL="`$APXS -q LIBTOOL`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs LIBTOOL: $APXS_LIBTOOL); fi + APXS_CC="`$APXS -q CC`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs CC: $APXS_CC); fi + APXS_BINDIR="`$APXS -q BINDIR`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs BINDIR: $APXS_BINDIR); fi + APXS_SBINDIR="`$APXS -q SBINDIR`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs SBINDIR: $APXS_SBINDIR); fi + APXS_PROGNAME="`$APXS -q PROGNAME`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs PROGNAME: $APXS_PROGNAME); fi + APXS_LIBEXECDIR="`$APXS -q LIBEXECDIR`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs LIBEXECDIR: $APXS_LIBEXECDIR); fi + if test "$APXS_SBINDIR" = "/"; then + APXS_HTTPD="$APXS_SBINDIR/$APXS_PROGNAME" + else + APXS_HTTPD="$APXS_SBINDIR/$APXS_PROGNAME" + fi + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs HTTPD: $APXS_HTTPD); fi +else + if test "$report_errors" -eq 1; then + AC_MSG_ERROR(couldn't find APXS) + else + AC_MSG_NOTICE(couldn't find APXS) + fi +fi + +# Include M4 macros +sinclude(build/find_pcre.m4) +sinclude(build/find_apr.m4) +sinclude(build/find_apu.m4) +sinclude(build/find_xml.m4) +sinclude(build/find_lua.m4) +sinclude(build/find_curl.m4) + + +### Build *EXTRA_CFLAGS vars + +# Allow overriding EXTRA_CFLAGS +if $ENV_CMD | $GREP "^EXTRA_CFLAGS" > /dev/null 2>&1; then + if test -z "$debug_mem"; then + EXTRA_CFLAGS="$EXTRA_CFLAGS $strict_compile" + fi +else + if test -n "$debug_mem"; then + EXTRA_CFLAGS="-O0 -g -Wall" + else + EXTRA_CFLAGS="-O2 -g -Wall $strict_compile" + fi +fi +MODSEC_EXTRA_CFLAGS="$debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api" + +APXS_WRAPPER=build/apxs-wrapper +APXS_EXTRA_CFLAGS="" +for f in $EXTRA_CFLAGS; do + APXS_EXTRA_CFLAGS="$APXS_EXTRA_CFLAGS -Wc,$f" +done; +MODSEC_APXS_EXTRA_CFLAGS="" +for f in $MODSEC_EXTRA_CFLAGS; do + MODSEC_APXS_EXTRA_CFLAGS="$MODSEC_APXS_EXTRA_CFLAGS -Wc,$f" +done; + +### Substitute the vars + +save_CPPFLAGS=$CPPFLAGS +CPPFLAGS="$APXS_INCLUDES $CPPFLAGS" +save_LDFLAGS=$LDFLAGS +LDFLAGS="$APXS_LDFLAGS $LDFLAGS" + +AC_SUBST(EXTRA_CFLAGS) +AC_SUBST(MODSEC_EXTRA_CFLAGS) +AC_SUBST(APXS) +AC_SUBST(APXS_WRAPPER) +AC_SUBST(APXS_INCLUDEDIR) +AC_SUBST(APXS_INCLUDES) +AC_SUBST(APXS_EXTRA_CFLAGS) +AC_SUBST(MODSEC_APXS_EXTRA_CFLAGS) +AC_SUBST(APXS_LDFLAGS) +AC_SUBST(APXS_LIBS) +AC_SUBST(APXS_CFLAGS) +AC_SUBST(APXS_LIBTOOL) +AC_SUBST(APXS_CC) +AC_SUBST(APXS_LIBDIR) +AC_SUBST(APXS_BINDIR) +AC_SUBST(APXS_SBINDIR) +AC_SUBST(APXS_PROGNAME) +AC_SUBST(APXS_LIBEXECDIR) +AC_SUBST(APXS_HTTPD) + +CHECK_PCRE() +CHECK_APR() +CHECK_APU() +CHECK_LIBXML2() +CHECK_LUA() +CHECK_CURL() + +AC_CONFIG_FILES([Makefile]) +AC_CONFIG_FILES([build/apxs-wrapper], [chmod +x build/apxs-wrapper]) +if test -e "$PERL"; then + AC_CONFIG_FILES([mlogc-src/mlogc-batch-load.pl], [chmod +x mlogc-src/mlogc-batch-load.pl]) + AC_CONFIG_FILES([t/run-unit-tests.pl], [chmod +x t/run-unit-tests.pl]) + AC_CONFIG_FILES([t/run-regression-tests.pl], [chmod +x t/run-regression-tests.pl]) + AC_CONFIG_FILES([t/gen_rx-pm.pl], [chmod +x t/gen_rx-pm.pl]) + AC_CONFIG_FILES([t/csv_rx-pm.pl], [chmod +x t/csv_rx-pm.pl]) + AC_CONFIG_FILES([t/regression/server_root/conf/httpd.conf]) + + # Perl based tools + AC_CONFIG_FILES([../tools/rules-updater.pl], [chmod +x ../tools/rules-updater.pl]) +fi +if test -e "mlogc-src/Makefile.in"; then + AC_CONFIG_FILES([mlogc-src/Makefile]) +fi + +AC_OUTPUT diff --git a/apache2/mlogc-src/INSTALL b/apache2/mlogc-src/INSTALL new file mode 100644 index 0000000..095f5a4 --- /dev/null +++ b/apache2/mlogc-src/INSTALL @@ -0,0 +1,76 @@ +ModSecurity Audit Log Collector (mlogc) + +Mlogc is used to connect a ModSecurity sensor to the central +audit log repository. + +To Install: +=========== + + 1) Copy the mlogc executable to an appropriate location. + + A good location might be /usr/local/bin, /opt/mlogc/bin, etc. + + 2) Create sensor in the central audit log repository. Note the + username and the password (SENSOR_USERNAME, SENSOR_PASSWORD). + Also note the IP address central repository listens on + (CONSOLE_IP_ADDRESS). + + 3) Configure the ModSecurity sensor to use mlogc + + # Use ReleventOnly auditing + SecAuditEngine RelevantOnly + + # Must use concurrent logging + SecAuditLogType Concurrent + + # Send all audit log parts + SecAuditLogParts ABIDEFGHZ + + # Use the same /CollectorRoot/LogStorageDir as in mlogc.conf + SecAuditLogStorageDir /var/log/mlogc/data + + # Pipe audit log to mlogc with your configuration + SecAuditLog "|/usr/local/bin/mlogc /etc/mlogc.conf" + + 4) Using the mlogc-default.conf as a template, configure the logger. + + Typically these are the only directives that will need to be modified + to conform to your site: + + # Points to the root of the installation. All relative + # paths configured in this file will be resolved with the + # help of this path (LogStorageDir, TransactionLog, etc.) + # + # Typically, this will be the parent directory that is configured + # in ModSecurity for the SecAuditLogStorageDirectory. So, if + # your SecAuditLogStorageDirectory is set to /var/log/mlogc/data, + # then set this to /var/log/mlogc. + CollectorRoot "/var/log/mlogc" + + # ModSecurity Console receiving URI. You can change the host + # and the port parts but leave everything else as is. + ConsoleURI https://CONSOLE_IP_ADDRESS:8886/rpc/auditLogReceiver + + # Sensor credentials + SensorUsername "SENSOR_USERNAME" + SensorPassword "SENSOR_PASSWORD" + + # Base directory where the audit logs are stored. This can be specified + # as a path relative to the CollectorRoot, or a full path. It should + # resolve to the same path as ModSecurity's SecAuditLogStorageDirectory. + LogStorageDir "data" + + See the mlogc-default.conf configuration file for details on other + configuration directives. + + 5) Restart the ModSecurity sensor. + + From now on every audit log generated will go to the repository. Make + sure you create an alert. Transactions without alerts will be recorded + but not displayed on the home page. + + To troubleshoot, generate alerts and observe file "mlogc-error.log". + + If mlogc fails to connect to the server it will pause for a period + of time (60 seconds by default) before it will try again. + diff --git a/apache2/mlogc-src/Makefile.in b/apache2/mlogc-src/Makefile.in new file mode 100755 index 0000000..6b73c4d --- /dev/null +++ b/apache2/mlogc-src/Makefile.in @@ -0,0 +1,70 @@ +# Generated Makefile for ModSecurity Log Collector (mlogc) + +CC = @CC@ +EXTRA_CFLAGS = @EXTRA_CFLAGS@ + +srcdir = . +modsecsrcdir = $(srcdir)/.. +srclibdir = $(srcdir)/srclib + +MLOGC_VERSION = `grep '^\#define *VERSION ' mlogc.c | sed 's/.*VERSION *"\([^"]*\)"/\1/'` + +APR_FLAGS = @APR_CFLAGS@ +APR_LIBS = @APR_LINK_LD@ @APR_LIBS@ + +CURL_FLAGS = @CURL_CFLAGS@ +CURL_LIBS = @CURL_LIBS@ + +PCRE_FLAGS = @PCRE_CFLAGS@ +PCRE_LIBS = @PCRE_LIBS@ + +APR_S_FLAGS = `$(srclibdir)/install/apr/bin/apr-1-config --includes --cppflags --cflags` +APR_S_LIBS = `$(srclibdir)/install/apr/bin/apr-1-config --link-ld` + +CURL_S_FLAGS = `$(srclibdir)/install/curl/bin/curl-config --cflags` +CURL_S_LIBS = `$(srclibdir)/install/curl/bin/curl-config --libs` + +PCRE_S_FLAGS = `$(srclibdir)/install/pcre/bin/pcre-config --cflags` +PCRE_S_LIBS = `$(srclibdir)/install/pcre/bin/pcre-config --libs` + +all: mlogc + +mlogc: mlogc.c + @echo; \ + echo "Building dynamically linked mlogc..."; \ + $(CC) $(CFLAGS) -o mlogc mlogc.c \ + -I$(modsecsrcdir) \ + $(APR_FLAGS) $(CURL_FLAGS) $(PCRE_FLAGS) \ + $(APR_LIBS) $(CURL_LIBS) $(PCRE_LIBS); \ + chmod 755 mlogc; \ + echo; \ + echo "Build finished. Please follow the INSTALL instructions to complete the install."; \ + echo + +.archives-ok: + @if [ -n "$(MLOGC_NOVERIFY)" -a "$(MLOGC_NOVERIFY)" = "1" ]; then \ + touch .archives-ok; \ + else \ + $(srclibdir)/archives.sh && touch .archives-ok; \ + fi + +.support-libs-ok: + $(srclibdir)/build.sh && touch .support-libs-ok + +archives: .archives-ok + +support-libs: .support-libs-ok + +clean-build: + @rm -rf $(srclibdir)/build + +clean-install: + @rm -rf $(srclibdir)/install + +clean-mlogc: + @rm -rf core mlogc *~ *.o *.so *.lo *.la *.slo + +distclean: clean + +clean: clean-build clean-install clean-mlogc + diff --git a/apache2/mlogc-src/Makefile.win b/apache2/mlogc-src/Makefile.win new file mode 100755 index 0000000..a720bcb --- /dev/null +++ b/apache2/mlogc-src/Makefile.win @@ -0,0 +1,57 @@ +########################################################################### +### You Will need to modify the following variables for your system +########################################################################### +########################################################################### + +# Path to Apache httpd installation +BASE = C:\Apache2 + +# Paths to required libraries +PCRE = C:\work\pcre-7.0-lib +CURL = C:\work\libcurl-7.19.3-win32-ssl-msvc + +# Linking libraries +LIBS = $(BASE)\lib\libapr-1.lib \ + $(BASE)\lib\libaprutil-1.lib \ + $(PCRE)\lib\pcre.lib \ + $(CURL)\lib\Release\curllib.lib \ + wsock32.lib + +########################################################################### +########################################################################### + +CC = cL + +MT = mt + +DEFS = /nologo /O2 /W3 -DWIN32 -DWINNT -Dinline=APR_INLINE -D_CONSOLE + +EXE = mlogc.exe + +INCLUDES = -I. -I.. \ + -I$(PCRE)\include -I$(PCRE) \ + -I$(CURL)\include -I$(CURL) \ + -I$(BASE)\include + +CFLAGS= -MT $(INCLUDES) $(DEFS) + +LDFLAGS = + +OBJS = mlogc.obj + +all: $(EXE) + +.c.obj: + $(CC) $(CFLAGS) -c $< -Fo$@ + +.cpp.obj: + $(CC) $(CFLAGS) -c $< -Fo$@ + +$(EXE): $(OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) $(LIBS) /link /NODEFAULTLIB:MSVCRT.lib /subsystem:console + +install: $(EXE) + copy $(EXE) $(BASE)\bin + +clean: + del $(OBJS) $(EXE) *.dll *.lib *.pdb *.idb *.ilk *.exp *.res *.rc *.bin *.manifest diff --git a/apache2/mlogc-src/mlogc-batch-load.pl.in b/apache2/mlogc-src/mlogc-batch-load.pl.in new file mode 100755 index 0000000..a32f57f --- /dev/null +++ b/apache2/mlogc-src/mlogc-batch-load.pl.in @@ -0,0 +1,151 @@ +#!@PERL@ +# +# ModSecurity for Apache 2.x, http://www.modsecurity.org/ +# Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) +# +# This product is released under the terms of the General Public Licence, +# version 2 (GPLv2). Please refer to the file LICENSE (included with this +# distribution) which contains the complete text of the licence. +# +# There are special exceptions to the terms and conditions of the GPL +# as it is applied to this software. View the full text of the exception in +# file MODSECURITY_LICENSING_EXCEPTION in the directory of this software +# distribution. +# +# If any of the files related to licensing are missing or if you have any +# other questions related to licensing please contact Breach Security, Inc. +# directly using the email address support@breach.com. +# + +use strict; +use File::Find qw(find); +use File::Spec::Functions qw(catfile); +use Sys::Hostname qw(hostname); +use Digest::MD5 qw(md5_hex); + +my $ROOTDIR = $ARGV[0] || ''; +my $MLOGC = $ARGV[1] || ''; +my $MLOGCCONF = $ARGV[2] || ''; +my @AUDIT = (); + +if ($ROOTDIR eq '' or ! -e $MLOGC or ! -e $MLOGCCONF) { + printf STDERR "\nUsage: $0 \n\n"; + exit 1; +} + +open(MLOGC, "|$MLOGC -f $MLOGCCONF") or die "ERROR: could not open '$MLOGC' - $!\n"; + +find( + { + wanted => sub { + my($fn,$dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size); + + (($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size) = stat($_)) && + -f _ && + /^\d{8}-\d+-\w{24}$/s + && (($fn = $File::Find::name) =~ s/^\Q$ROOTDIR\E//) + && push(@AUDIT, [$fn, $size]); + }, + follow => 1, + }, + $ROOTDIR +); + +for my $audit (@AUDIT) { + my $fn = $audit->[0]; + my $line = ""; + my $err = 0; + my $ln = 0; + my $sln = 0; + my $sect = ""; + my $data = ""; + my %data = ( + hostname => hostname(), + remote_addr => "-", + remote_user => "-", + local_user => "-", + logtime => "-", + request => "-", + response_status => "-", + bytes_sent => "-", + referer => "-", + user_agent => "-", + uniqueid => "-", + sessionid => "-", + audit_file => $fn, + extra => "0", + audit_size => $audit->[1], + md5 => "-", + ); + + ### Parse the audit file in an attempt to recreate the original log line + open (AUDIT, "<".catfile($ROOTDIR,$fn)) or $err = 1; + if ($err == 1) { + print STDERR "ERROR: could not open '$fn' - $!\n"; + next; + } + + while($line = ) { + $data .= $line; + chop $line; + $ln++; + $sln++; + if ($line =~ m%^--[0-9A-Fa-f]{8}-([A-Z])--$%) { + $sect = $1; + $sln = 0; + next; + }; + if ($sect eq 'A') { + if ($line =~ m%^(\[[-\d/: a-zA-Z]{27}\]) (\S+) (\S+) (\d+) (\S+) (\d+)%) { + $data{logtime} = $1; + $data{uniqueid} = $2; + $data{remote_addr} = $3; + } + next; + } + elsif ($sect eq 'B') { + if ($sln == 1) { + $data{request} = $line; + } + elsif ($line =~ m%^User=Agent: (.*)%i) { + $data{user_agent} = $1; + } + elsif ($line =~ m%^Referer: (.*)%i) { + $data{referer} = $1; + } + next; + } + elsif ($sect eq 'F') { + if ($sln == 1 and $line =~ m%^\S+ (\d{3})\D?.*%) { + $data{response_status} = $1; + } + elsif ($line =~ m%^Content-Length: (\d+)%i) { + $data{bytes_sent} = $1; + } + next; + } + } + $data{md5} = md5_hex($data); + + printf MLOGC ( + "%s %s %s %s %s \"%s\" %s %s \"%s\" \"%s\" %s \"%s\" %s %s %s md5:%s\n", + $data{hostname}, + $data{remote_addr}, + $data{remote_user}, + $data{local_user}, + $data{logtime}, + $data{request}, + $data{response_status}, + $data{bytes_sent}, + $data{referer}, + $data{user_agent}, + $data{uniqueid}, + $data{sessionid}, + $data{audit_file}, + $data{extra}, + $data{audit_size}, + $data{md5}, + ); + +} + diff --git a/apache2/mlogc-src/mlogc-default.conf b/apache2/mlogc-src/mlogc-default.conf new file mode 100644 index 0000000..919b1ad --- /dev/null +++ b/apache2/mlogc-src/mlogc-default.conf @@ -0,0 +1,98 @@ +########################################################################## +# Required configuration +# At a minimum, the items in this section will need to be adjusted to +# fit your environment. The remaining options are optional. +########################################################################## + +# Points to the root of the installation. All relative +# paths will be resolved with the help of this path. +CollectorRoot "/var/log/mlogc" + +# ModSecurity Console receiving URI. You can change the host +# and the port parts but leave everything else as is. +ConsoleURI "https://CONSOLE_IP_ADDRESS:8888/rpc/auditLogReceiver" + +# Sensor credentials +SensorUsername "SENSOR_USERNAME" +SensorPassword "SENSOR_PASSWORD" + +# Base directory where the audit logs are stored. This can be specified +# as a path relative to the CollectorRoot, or a full path. +LogStorageDir "data" + +# Transaction log will contain the information on all log collector +# activities that happen between checkpoints. The transaction log +# is used to recover data in case of a crash (or if Apache kills +# the process). +TransactionLog "mlogc-transaction.log" + +# The file where the pending audit log entry data is kept. This file +# is updated on every checkpoint. +QueuePath "mlogc-queue.log" + +# The location of the error log. +ErrorLog "mlogc-error.log" + +# The location of the lock file. +LockFile "mlogc.lck" + +# Keep audit log entries after sending? (0=false 1=true) +# NOTE: This is required to be set in SecAuditLog mlogc config if you +# are going to use a secondary console via SecAuditLog2. +KeepEntries 0 + + +########################################################################## +# Optional configuration +########################################################################## + +# The error log level controls how much detail there +# will be in the error log. The levels are as follows: +# 0 - NONE +# 1 - ERROR +# 2 - WARNING +# 3 - NOTICE +# 4 - DEBUG +# 5 - DEBUG2 +# +ErrorLogLevel 3 + +# How many concurrent connections to the server +# are we allowed to open at the same time? Log collector uses +# multiple connections in order to speed up audit log transfer. +# This is especially needed when the communication takes place +# over a slow link (e.g. not over a LAN). +MaxConnections 10 + +# How many requests a worker will process before recycling itself. +# This is to help prevent problems due to any memory leaks that may +# exists. If this is set to 0, then no maximum is imposed. The default +# is 1000 requests per worker (the number of workers is controlled by the +# MaxConnections limit). +MaxWorkerRequests 1000 + +# The time each connection will sit idle before being reused, +# in milliseconds. Increase if you don't want ModSecurity Console +# to be hit with too many log collector requests. +TransactionDelay 50 + +# The time to wait before initialization on startup in milliseconds. +# Increase if mlogc is starting faster then termination when the +# sensor is reloaded. +StartupDelay 5000 + +# How often is the pending audit log entry data going to be written +# to a file. The default is 15 seconds. +CheckpointInterval 15 + +# If the server fails all threads will back down until the +# problem is sorted. The management thread will periodically +# launch a thread to test the server. The default is to test +# once in 60 seconds. +ServerErrorTimeout 60 + +# The following two parameters are not used yet, but +# reserved for future expansion. +# KeepAlive 150 +# KeepAliveTimeout 300 + diff --git a/apache2/mlogc-src/mlogc.c b/apache2/mlogc-src/mlogc.c new file mode 100644 index 0000000..c935a62 --- /dev/null +++ b/apache2/mlogc-src/mlogc.c @@ -0,0 +1,2059 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if APR_HAVE_UNISTD_H +#include /* for getpid() */ +#endif +#include +#include +#include +#include +#include + +#include "msc_release.h" + +static void logc_shutdown(int rc); +static void create_new_worker(int lock); +static void error_log(int level, void *thread, const char *text, ...) PRINTF_ATTRIBUTE(3,4); + + +/* -- Constants -- */ + +/* Error log levels. */ +#define LOG_ERROR 1 +#define LOG_WARNING 2 +#define LOG_NOTICE 3 +#define LOG_DEBUG 4 +#define LOG_DEBUG2 5 + +/* The management thread will wake up every five seconds. */ +#define MANAGER_SLEEP 5000000 +#define MANAGER_SUBSLEEP 10000 + +/* Hack to allow multiple mlogc with single delete */ +#define KEEP_ENTRIES_REMOVE_HACK 2600 +#define KEEP_ENTRIES_REMOVE_TIME 0l +#ifdef TEST_HACK +#define TEST_WITH_RAND_SLEEP(n) \ +do { \ + int sec = rand()/(RAND_MAX/n); \ + error_log(LOG_DEBUG2, NULL, "TEST_HACK: Sleeping for %ds", sec); \ + apr_sleep(apr_time_from_sec(sec)); \ +} while(0) +#else +#define TEST_WITH_RAND_SLEEP(n) +#endif + +#define CAPTUREVECTORSIZE 60 +#define PIPE_BUF_SIZE 65536 +#define MEMALLOC_ERROR_MSG "Memory allocation failed!" +#define VERSION MODSEC_VERSION + +#define CMDLINE_OPTS "fvh" + +#define TXIN 0 +#define TXOUT 1 + +#define STATUSBUF_SIZE 256 + +#define ISHEXCHAR(X) (((X >= '0')&&(X <= '9')) || ((X >= 'a')&&(X <= 'f')) || ((X >= 'A')&&(X <= 'F'))) + +/* -- Regex Patterns -- */ + +/** + * This regular expression is used to parse the entire + * log line we receive from Apache. The REQUEST_LINE is + * treated as a single parameter to allow for invalid + * requests. + */ +const char logline_pattern[] = + "^(\\S+)" + "\\ (\\S+)\\ (\\S+)\\ (\\S+)" + "\\ \\[([^:]+):(\\d+:\\d+:\\d+)\\ ([^\\]]+)\\]" + "\\ \"(.*)\"" + "\\ (\\d+)\\ (\\S+)" + "\\ \"(.*)\"\\ \"(.*)\"" + "\\ (\\S+)\\ \"(.*)\"" + "\\ /?(\\S+)\\ (\\d+)\\ (\\d+)" + "\\ (\\S+)" + "(.*)$"; + + +/** + * This regular expression can be used to parse + * a REQUEST_LINE field into method, URI, and + * protocol. + */ +const char requestline_pattern[] = + "(\\S+)\\ (.*?)\\ (\\S+)"; + + +/* -- Structures -- */ + +typedef struct { + unsigned long int id; + const char *line; + apr_size_t line_size; +} entry_t; + + +/* -- Global variables -- */ + +pid_t logc_pid = 0; +const char *conffile = NULL; +const char *lockfile = NULL; +int have_read_data = 0; +int checkpoint_interval = 60; +apr_time_t checkpoint_time_last = 0; +const char *collector_root = NULL; +apr_table_t *conf = NULL; +const char *console_uri = NULL; +apr_array_header_t *curl_handles = NULL; +int current_workers = 0; +int management_thread_active = 0; +unsigned long int entry_counter = 1; +const char *error_log_path = NULL; +apr_file_t *error_log_fd = NULL; +int error_log_level = 2; +apr_hash_t *in_progress = NULL; +int keep_alive = 150; /* Not used yet. */ +int keep_alive_timeout = 300; /* Not used yet. */ +int keep_entries = 0; +const char *log_repository = NULL; +void *logline_regex = NULL; +int max_connections = 10; +int max_worker_requests = 1000; +apr_global_mutex_t *gmutex = NULL; +apr_thread_mutex_t *mutex = NULL; +apr_pool_t *pool = NULL; +apr_pool_t *thread_pool = NULL; +apr_pool_t *recv_pool = NULL; +apr_array_header_t *queue = NULL; +const char *queue_path = NULL; +/* apr_time_t queue_time = 0; */ +void *requestline_regex = NULL; +int running = 0; +const char *sensor_password = NULL; +const char *sensor_username = NULL; +int server_error = 0; +apr_time_t server_error_last_check_time = 0; +int server_error_timeout = 60; +int startup_delay = 100; +int transaction_delay = 100; +const char *transaction_log_path = NULL; +apr_file_t *transaction_log_fd = NULL; + + +/* -- Commandline opts -- */ +int opt_force = 0; + + +/* -- Code -- */ + +static char *_log_escape(apr_pool_t *mp, const char *input, apr_size_t input_len) +{ + static const char c2x_table[] = "0123456789abcdef"; + unsigned char *d = NULL; + char *ret = NULL; + unsigned long int i; + + if (input == NULL) return NULL; + + ret = apr_palloc(mp, input_len * 4 + 1); + if (ret == NULL) return NULL; + d = (unsigned char *)ret; + + i = 0; + while(i < input_len) { + switch(input[i]) { + case '"' : + *d++ = '\\'; + *d++ = '"'; + break; + case '\b' : + *d++ = '\\'; + *d++ = 'b'; + break; + case '\n' : + *d++ = '\\'; + *d++ = 'n'; + break; + case '\r' : + *d++ = '\\'; + *d++ = 'r'; + break; + case '\t' : + *d++ = '\\'; + *d++ = 't'; + break; + case '\v' : + *d++ = '\\'; + *d++ = 'v'; + break; + case '\\' : + *d++ = '\\'; + *d++ = '\\'; + break; + default : + if ((input[i] <= 0x1f)||(input[i] >= 0x7f)) { + *d++ = '\\'; + *d++ = 'x'; + *d++ = c2x_table[input[i] >> 4]; + *d++ = c2x_table[input[i] & 0x0f]; + } else { + *d++ = input[i]; + } + break; + } + + i++; + } + + *d = 0; + + return ret; +} + +/** + * Converts a byte given as its hexadecimal representation + * into a proper byte. Handles uppercase and lowercase letters + * but does not check for overflows. + */ +static unsigned char x2c(unsigned char *what) { + register unsigned char digit; + + digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0')); + digit *= 16; + digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0')); + + return digit; +} + +/** + * URL Decodes a string in-place + */ +static int urldecode_inplace(unsigned char *input, apr_size_t input_len) { + unsigned char *d = (unsigned char *)input; + apr_size_t i; + + if (input == NULL) return 0; + + i = 0; + while (i < input_len) { + if (input[i] == '%') { + /* Character is a percent sign. */ + + /* Are there enough bytes available? */ + if (i + 2 < input_len) { + char c1 = input[i + 1]; + char c2 = input[i + 2]; + + if (ISHEXCHAR(c1) && ISHEXCHAR(c2)) { + /* Valid encoding - decode it. */ + *d++ = x2c(&input[i + 1]); + i += 3; + } else { + /* Not a valid encoding, skip this % */ + *d++ = input[i++]; + } + } else { + /* Not enough bytes available, copy the raw bytes. */ + *d++ = input[i++]; + } + } else { + /* Character is not a percent sign. */ + if (input[i] == '+') { + *d++ = ' '; + } else { + *d++ = input[i]; + } + i++; + } + } + + *d = '\0'; + + return 1; +} + +/** + * Detect a relative path and merge it with the collector root + * path. Leave absolute paths as they are. + */ +static const char *file_path(const char *path) +{ + char *newpath = NULL; + apr_status_t rc; + + if (path == NULL) return NULL; + + rc = apr_filepath_merge(&newpath, collector_root, path, APR_FILEPATH_TRUENAME, pool); + if ((newpath != NULL) && (rc == APR_SUCCESS || APR_STATUS_IS_EPATHWILD(rc) + || APR_STATUS_IS_ENOENT(rc) || APR_STATUS_IS_ENOTDIR(rc))) + { + return newpath; + } + else { + return NULL; + } +} + + +/** + * Returns the current datetime as a string. + */ +static char *current_logtime(char *dest, int dlen) +{ + apr_time_exp_t t; + apr_size_t len; + + apr_time_exp_lt(&t, apr_time_now()); + apr_strftime(dest, &len, dlen, "%a %b %d %H:%M:%S %Y", &t); + + return dest; +} + + +/** + * Logs error to the error log (if available) or + * to the stderr. + */ +static void error_log(int level, void *thread, const char *text, ...) +{ + char msg1[4096] = ""; + char msg2[4096] = ""; + char datetime[100]; + va_list ap; + + if (level > error_log_level) return; + + va_start(ap, text); + + apr_vsnprintf(msg1, sizeof(msg1), text, ap); + apr_snprintf(msg2, sizeof(msg2), "[%s] [%d] [%" APR_PID_T_FMT "/%pp] %s\n", current_logtime(datetime, sizeof(datetime)), level, logc_pid, (thread ? thread : 0), msg1); + + if (error_log_fd != NULL) { + apr_size_t nbytes_written; + apr_size_t nbytes = strlen(msg2); + apr_file_write_full(error_log_fd, msg2, nbytes, &nbytes_written); + } + else { + fprintf(stderr, "%s", msg2); + } + + va_end(ap); +} + + +/** + * Adds one entry to the internal queue. It will (optionally) start + * a new thread to handle it. + */ +static void add_entry(const char *data, int start_worker) +{ + entry_t *entry = NULL; + + entry = (entry_t *)malloc(sizeof(entry_t)); + entry->id = 0; + entry->line = strdup(data); + entry->line_size = strlen(entry->line); + + error_log(LOG_DEBUG, NULL, "Queue locking thread mutex."); + if (APR_STATUS_IS_EBUSY(apr_thread_mutex_trylock(mutex))) { + error_log(LOG_DEBUG, NULL, "Queue waiting on thread mutex."); + apr_thread_mutex_lock(mutex); + } + + /* Assign unique ID to this log entry. */ + entry->id = entry_counter++; + + /* Add the new audit log entry to the queue. */ + *(entry_t **)apr_array_push(queue) = entry; + + /* Create a new worker if we can, but not if there is a known problem with the server. */ + if ((start_worker != 0)&&(current_workers < max_connections)&&(server_error == 0)) { + create_new_worker(0); + } + + error_log(LOG_DEBUG, NULL, "Queue unlocking thread mutex."); + apr_thread_mutex_unlock(mutex); +} + + +/** + * Read the queue entries. + */ +static int read_queue_entries(apr_file_t *fd, apr_time_t *queue_time) +{ + char linebuf[4100]; + int line_count = -1; + + for(;;) { + apr_status_t rc = apr_file_gets(linebuf, 4096, fd); + char *p; + + if (rc == APR_EOF) break; + if (rc != APR_SUCCESS) { + error_log(LOG_ERROR, NULL, "Error reading from the queue file."); + logc_shutdown(1); + } + + if (line_count < 0) { + /* First line contains the queue time. */ + *queue_time = (apr_time_t)apr_atoi64(linebuf); + line_count = 0; + continue; + } + + p = &linebuf[0]; + + /* Remove the \n from the end of the line. */ + while(*p != '\0') { + if (*p == '\n') { + *p = '\0'; + break; + } + p++; + } + + if (linebuf[0] == '#') { /* Ignore comments. */ + continue; + } + + add_entry((const char *)&linebuf, 0); + + line_count++; + } + + apr_file_close(fd); + + return line_count; +} + + +/** + * Initialise the transaction log. This code should be + * executed only once at startup. + */ +static void transaction_log_init(void) +{ + /* ENH: These big enough? */ + char new_queue_path[256]; + char old_queue_path[256]; + apr_file_t *queue_fd = NULL; + apr_time_t queue_time; + + apr_snprintf(new_queue_path, sizeof(new_queue_path), "%s.new", queue_path); + apr_snprintf(old_queue_path, sizeof(old_queue_path), "%s.old", queue_path); + + /* Put a lock in place to ensure exclusivity. */ + error_log(LOG_DEBUG, NULL, "Transaction initialization locking global mutex."); + if (APR_STATUS_IS_EBUSY(apr_global_mutex_trylock(gmutex))) { + error_log(LOG_DEBUG, NULL, "Transaction initialization waiting on global mutex."); + apr_global_mutex_lock(gmutex); + } + + error_log(LOG_DEBUG, NULL, "Transaction initialization started."); + + /* Delete .new file if there is one. */ + apr_file_remove(new_queue_path, pool); + + /* Read in the data from the queue. */ + if (apr_file_open(&queue_fd, queue_path, APR_READ | APR_FILE_NOCLEANUP, + 0, pool) == APR_SUCCESS) + { + int line_count = read_queue_entries(queue_fd, &queue_time); + + apr_file_close(queue_fd); + + if (line_count > 0) { + error_log(LOG_NOTICE, NULL, "Loaded %d entries from the queue file.", line_count); + } + } + /* Try the old queue file. */ + else if (apr_file_open(&queue_fd, old_queue_path, APR_READ | APR_FILE_NOCLEANUP, + 0, pool) == APR_SUCCESS) + { + int line_count = read_queue_entries(queue_fd, &queue_time); + apr_file_close(queue_fd); + error_log(LOG_NOTICE, NULL, "Loaded %d entries from the OLD queue file.", line_count); + apr_file_rename(old_queue_path, queue_path, pool); + } + else { + error_log(LOG_NOTICE, NULL, "Queue file not found. New one will be created."); + } + + /* Delete the old queue file. */ + apr_file_remove(old_queue_path, pool); + + checkpoint_time_last = apr_time_now(); + + /* Start fresh with the transaction log. Do note that + * we do not truncate the transaction log on purpose. Apache + * will start copies of piped logging binaries during configuration + * testing. Truncating would erase the log of a currently running + * instance. + */ + if (apr_file_open(&transaction_log_fd, transaction_log_path, APR_WRITE | APR_CREATE + | APR_APPEND | APR_XTHREAD, APR_OS_DEFAULT, pool) != APR_SUCCESS) + { + error_log(LOG_ERROR, NULL, "Failed to open the transaction log: %s\n", transaction_log_path); + error_log(LOG_DEBUG, NULL, "Transaction initialization unlocking global mutex."); + apr_global_mutex_unlock(gmutex); + logc_shutdown(1); + } + + error_log(LOG_DEBUG, NULL, "Transaction initialization completed."); + + /* Unlock */ + error_log(LOG_DEBUG, NULL, "Transaction initialization unlocking global mutex."); + apr_global_mutex_unlock(gmutex); +} + + +/** + * Log entry event (incoming or outgoing) to the transaction log. + */ +static void transaction_log(int direction, const char *entry) +{ + apr_size_t nbytes, nbytes_written; + char msg[8196] = ""; + + apr_snprintf(msg, sizeof(msg), "%u %s: %s\n", (unsigned int)apr_time_sec(apr_time_now()), + (direction == TXIN ? "IN" : "OUT"), entry); + nbytes = strlen(msg); + apr_file_write_full(transaction_log_fd, msg, nbytes, &nbytes_written); +} + + +/** + * Executes a checkpoint, which causes the current queue to be + * written to a file and the transaction log to be truncated. + */ +static void transaction_checkpoint(void) +{ + /* ENH: These big enough? */ + char new_queue_path[256]; + char old_queue_path[256]; + apr_file_t *queue_fd = NULL; + apr_hash_index_t *hi = NULL; + char msg[256]; + int i; + apr_pool_t *cpool; + + apr_snprintf(new_queue_path, sizeof(new_queue_path), "%s.new", queue_path); + apr_snprintf(old_queue_path, sizeof(old_queue_path), "%s.old", queue_path); + apr_snprintf(msg, sizeof(msg), "%u\n", (unsigned int)apr_time_sec(apr_time_now())); + + if (! have_read_data) { + error_log(LOG_DEBUG, NULL, "Checkpoint not required."); + return; + } + + /* Put a lock in place to ensure exclusivity. */ + error_log(LOG_DEBUG, NULL, "Checkpoint locking global mutex."); + if (APR_STATUS_IS_EBUSY(apr_global_mutex_trylock(gmutex))) { + error_log(LOG_DEBUG, NULL, "Checkpoint waiting on global mutex."); + apr_global_mutex_lock(gmutex); + } + + error_log(LOG_DEBUG, NULL, "Checkpoint started."); + + apr_pool_create(&cpool, NULL); + + /* Dump active entries into a new queue file. */ + if (apr_file_open(&queue_fd, new_queue_path, APR_WRITE | APR_CREATE + | APR_EXCL | APR_TRUNCATE | APR_FILE_NOCLEANUP, APR_OS_DEFAULT, cpool) != APR_SUCCESS) + { + error_log(LOG_ERROR, NULL, "Failed to create file: %s", new_queue_path); + error_log(LOG_DEBUG, NULL, "Checkpoint unlocking global mutex."); + apr_pool_destroy(cpool); + apr_global_mutex_unlock(gmutex); + return; + } + + /* Write the time first. */ + apr_file_write_full(queue_fd, msg, strlen(msg), NULL); + + /* Dump the entries sitting in the queue first. */ + for (i = 0; i < queue->nelts; i++) { + entry_t *entry = ((entry_t **)queue->elts)[i]; + apr_file_write_full(queue_fd, entry->line, entry->line_size, NULL); + apr_file_write_full(queue_fd, &"\n", 1, NULL); + } + error_log(LOG_DEBUG2, NULL, "Checkpoint wrote %d queued entries to new queue.", i); + + /* Then dump the ones that are currently being processed. */ + i = 0; + for (hi = apr_hash_first(NULL, in_progress); hi != NULL; hi = apr_hash_next(hi)) { + void *e; + entry_t *entry = NULL; + + i++; + apr_hash_this(hi, NULL, NULL, &e); + entry = e; /* quiet type-punned warning */ + apr_file_write_full(queue_fd, entry->line, entry->line_size, NULL); + apr_file_write_full(queue_fd, &"\n", 1, NULL); + } + error_log(LOG_DEBUG2, NULL, "Checkpoint wrote %d additional entries to new queue.", i); + + apr_file_close(queue_fd); + + /* Switch the files and truncate the transaction log file. */ + apr_file_remove(old_queue_path, cpool); + apr_file_rename(queue_path, old_queue_path, cpool); + apr_file_rename(new_queue_path, queue_path, cpool); + apr_file_remove(old_queue_path, cpool); + apr_file_trunc(transaction_log_fd, 0); + + error_log(LOG_DEBUG, NULL, "Checkpoint completed."); + + apr_pool_destroy(cpool); + + /* Unlock and exit. */ + error_log(LOG_DEBUG, NULL, "Checkpoint unlocking global mutex."); + apr_global_mutex_unlock(gmutex); +} + + +/** + * Parse one confguration line and add it to the + * configuration table. + */ +static void parse_configuration_line(const char *line, int line_count) +{ + char *start = NULL, *command = NULL; + char *p = NULL; + + /* Remove the trailing newline character. */ + p = (char *)line; + while(*p != '\0') p++; + if ((p > start)&&(*(p - 1) == '\n')) *(p - 1) = '\0'; + + p = (char *)line; + /* Ignore whitespace at the beginning of the line. */ + while(apr_isspace(*p)) p++; + + /* Ignore empty lines and comments. */ + if ((*p == '\0')||(*p == '#')) return; + + start = p; + while(!apr_isspace(*p)&&(*p != '\0')) p++; + + command = apr_pstrmemdup(pool, start, p - start); + + while(apr_isspace(*p)) p++; + + /* Remove whitespace at the end. */ + start = p; + while(*p != '\0') p++; + if (p > start) { + p--; + while(apr_isspace(*p)) { + *p-- = '\0'; + } + } + + /* Remove quotes, but only if we have matching */ + if ((*start == '"') && (p > start) && (*p == '"')) { + start++; + *p-- = '\0'; + } + + /* Take the last directive */ + /* ENH: Error on dup directives? */ + apr_table_set(conf, command, start); +} + + +/** + * Reads configuration from a file. + */ +static void read_configuration(void) +{ + char linebuf[4096]; + apr_status_t rc; + apr_file_t *fd; + int line_count; + + conf = apr_table_make(pool, 32); + if (conf == NULL) { + error_log(LOG_ERROR, NULL, MEMALLOC_ERROR_MSG); + logc_shutdown(1); + } + + rc = apr_file_open(&fd, conffile, APR_READ | APR_FILE_NOCLEANUP, 0, pool); + if (rc != APR_SUCCESS) { + error_log(LOG_ERROR, NULL, "Unable to open configuration file: %s", conffile); + logc_shutdown(1); + } + + line_count = 0; + for(;;) { + rc = apr_file_gets(linebuf, 4096, fd); + if (rc == APR_EOF) return; + if (rc != APR_SUCCESS) { + error_log(LOG_ERROR, NULL, "Error reading from the configuration file."); + logc_shutdown(1); + } + + line_count++; + parse_configuration_line(linebuf, line_count); + } + + apr_file_close(fd); +} + + +/** + * Initialize the configuration. + */ +static void init_configuration(void) +{ + char errstr[1024]; + apr_status_t rc = 0; + const char *s = NULL; + + /* Other values may be based off the collector root. */ + s = apr_table_get(conf, "CollectorRoot"); + if (s != NULL) { + collector_root = s; + } + + /* Error Log */ + s = apr_table_get(conf, "ErrorLog"); + if (s != NULL) { + error_log_path = file_path(s); + } + + s = apr_table_get(conf, "ErrorLogLevel"); + if (s != NULL) { + error_log_level = atoi(s); + } + + if ((rc = apr_file_open(&error_log_fd, error_log_path, APR_WRITE | APR_CREATE | APR_APPEND, + APR_OS_DEFAULT, pool)) != APR_SUCCESS) + { + error_log(LOG_ERROR, NULL, "Failed to open the error log %s: %s\n", + error_log_path, apr_strerror(rc, errstr, 1024)); + logc_shutdown(1); + } + + error_log(LOG_NOTICE, NULL, "Configuring ModSecurity Audit Log Collector %s.", VERSION); + + /* Startup Delay */ + s = apr_table_get(conf, "StartupDelay"); + if (s != NULL) { + startup_delay = atoi(s); + } + + if ( startup_delay > 0 ) { + error_log(LOG_NOTICE, NULL, "Delaying execution for %dms.", startup_delay); + apr_sleep(startup_delay * 1000); + error_log(LOG_DEBUG, NULL, "Continuing execution after %dms delay.", startup_delay); + } + + /* Remaining Configuration */ + + error_log(LOG_DEBUG2, NULL, "CollectorRoot=%s", collector_root); + error_log(LOG_DEBUG2, NULL, "ErrorLog=%s", error_log_path); + error_log(LOG_DEBUG2, NULL, "ErrorLogLevel=%d", error_log_level); + error_log(LOG_DEBUG2, NULL, "StartupDelay=%d", startup_delay); + + s = apr_table_get(conf, "CheckpointInterval"); + if (s != NULL) { + checkpoint_interval = atoi(s); + error_log(LOG_DEBUG2, NULL, "CheckpointInterval=%d", checkpoint_interval); + } + + s = apr_table_get(conf, "QueuePath"); + if (s != NULL) { + queue_path = file_path(s); + error_log(LOG_DEBUG2, NULL, "QueuePath=%s", queue_path); + } + else { + error_log(LOG_ERROR, NULL, "QueuePath not defined in the configuration file."); + logc_shutdown(1); + } + + s = apr_table_get(conf, "LockFile"); + if (s != NULL) { + lockfile = file_path(s); + error_log(LOG_DEBUG2, NULL, "LockFile=%s", lockfile); + } + + s = apr_table_get(conf, "ServerErrorTimeout"); + if (s != NULL) { + server_error_timeout = atoi(s); + error_log(LOG_DEBUG2, NULL, "ServerErrorTimeout=%d", server_error_timeout); + } + + s = apr_table_get(conf, "TransactionDelay"); + if (s != NULL) { + transaction_delay = atoi(s); + error_log(LOG_DEBUG2, NULL, "TransactionDelay=%d", transaction_delay); + } + + s = apr_table_get(conf, "TransactionLog"); + if (s != NULL) { + transaction_log_path = file_path(s); + error_log(LOG_DEBUG2, NULL, "TransactionLog=%s", transaction_log_path); + } + + s = apr_table_get(conf, "MaxConnections"); + if (s != NULL) { + int v = atoi(s); + if (v >= 0) max_connections = v; + error_log(LOG_DEBUG2, NULL, "MaxConnections=%d", max_connections); + } + + s = apr_table_get(conf, "MaxWorkerRequests"); + if (s != NULL) { + int v = atoi(s); + if (v >= 0) max_worker_requests = v; + error_log(LOG_DEBUG2, NULL, "MaxWorkerRequests=%d", max_worker_requests); + } + + s = apr_table_get(conf, "KeepAlive"); + if (s != NULL) { + int v = atoi(s); + if (v >= 0) keep_alive = v; + error_log(LOG_DEBUG2, NULL, "KeepAlive=%d", keep_alive); + } + + s = apr_table_get(conf, "KeepAliveTimeout"); + if (s != NULL) { + int v = atoi(s); + if (v >= 0) keep_alive_timeout = v; + error_log(LOG_DEBUG2, NULL, "KeepAliveTimeout=%d", keep_alive_timeout); + } + + s = apr_table_get(conf, "LogStorageDir"); + if (s != NULL) { + log_repository = file_path(s); + error_log(LOG_DEBUG2, NULL, "LogStorageDir=%s", log_repository); + } + else { + error_log(LOG_ERROR, NULL, "Missing mandatory parameter LogStorageDir.\n"); + logc_shutdown(1); + } + + s = apr_table_get(conf, "ConsoleURI"); + if (s != NULL) { + console_uri = s; + error_log(LOG_DEBUG2, NULL, "ConsoleURI=%s", console_uri); + } + else { + error_log(LOG_ERROR, NULL, "Missing mandatory parameter ConsoleURI.\n"); + logc_shutdown(1); + } + + s = apr_table_get(conf, "SensorUsername"); + if (s != NULL) { + sensor_username = s; + error_log(LOG_DEBUG2, NULL, "SensorUsername=%s", sensor_username); + } + else { + error_log(LOG_ERROR, NULL, "Missing mandatory parameter SensorUsername.\n"); + logc_shutdown(1); + } + + s = apr_table_get(conf, "SensorPassword"); + if (s != NULL) { + sensor_password = s; + error_log(LOG_DEBUG2, NULL, "SensorPassword=%s", sensor_password); + } + else { + error_log(LOG_ERROR, NULL, "Missing mandatory parameter SensorPassword.\n"); + logc_shutdown(1); + } + + s = apr_table_get(conf, "KeepEntries"); + if (s != NULL) { + keep_entries = atoi(s); + } + else { + keep_entries = 0; + } + error_log(LOG_DEBUG2, NULL, "KeepEntries=%d", keep_entries); +} + + +/** + * Clean-up resources before process shutdown. + */ +static void logc_cleanup(void) +{ + curl_global_cleanup(); +} + + +/** + * Shutdown the logger. + */ +static void logc_shutdown(int rc) +{ + /* Tell the threads to shut down. */ + running = 0; + + error_log(LOG_DEBUG, NULL, "Shutting down"); + + /* Wait for the management thread to stop */ + /* ENH: Need a fixed timeout if this never happens */ + while(management_thread_active != 0) { + apr_sleep(10 * 1000); + } + + if (rc == 0) { + error_log(LOG_NOTICE, NULL, "ModSecurity Audit Log Collector %s terminating normally.", VERSION); + } + else { + error_log(LOG_NOTICE, NULL, "ModSecurity Audit Log Collector %s terminating with error %d", VERSION, rc); + } + + if (error_log_fd != NULL) { + apr_file_flush(error_log_fd); + } + + exit(rc); +} + + +/** + * Handle signals. + */ +static int handle_signals(int signum) +{ + switch (signum) { + case SIGINT: + error_log(LOG_NOTICE, NULL, "Caught SIGINT, shutting down."); + logc_shutdown(0); + case SIGTERM: + error_log(LOG_NOTICE, NULL, "Caught SIGTERM, shutting down."); + logc_shutdown(0); +#ifndef WIN32 + case SIGHUP: + error_log(LOG_NOTICE, NULL, "Caught SIGHUP, ignored."); + /* ENH: reload config? */ + return 0; + case SIGALRM: + error_log(LOG_DEBUG, NULL, "Caught SIGALRM, ignored."); + return 0; + case SIGTSTP: + error_log(LOG_DEBUG, NULL, "Caught SIGTSTP, ignored."); + return 0; +#endif /* WIN32 */ + } +#ifndef WIN32 + error_log(LOG_NOTICE, NULL, "Caught unexpected signal %d: %s", signum, apr_signal_description_get(signum)); +#else + error_log(LOG_NOTICE, NULL, "Caught unexpected signal %d", signum); +#endif /* WIN32 */ + logc_shutdown(1); + + return 0; /* should never reach */ +} + + +/** + * This function is invoked by Curl to read the response + * body. Since we don't care about the response body the function + * pretends it is retrieving data where it isn't. + */ +size_t curl_writefunction(void *ptr, size_t size, size_t nmemb, void *stream) +{ + unsigned char *data = (unsigned char *)ptr; + unsigned char *status = (unsigned char *)stream; + + /* Grab the status line text from the first line of output */ + if ((status[0] == 0) && (status[1] == 1)) { + apr_size_t i, j; + int ismsg = 0; + + status[1] = 0; /* reset hidden init flag */ + + for (i = 0, j = 0; i < STATUSBUF_SIZE; i++) { + /* We found a line ending so we are done */ + if ( data[i] == '\r' ) { + break; + } + /* Skip to after the first space (where msg is) */ + if (ismsg < 3) { + if ((ismsg == 1) && !isspace(data[i])) { + ismsg++; + } + else if (isspace(data[i])) { + ismsg++; + } + continue; + } + + /* Copy data (msg) from data to status */ + status[j++] = data[i]; + } + status[j] = '\0'; + urldecode_inplace(status, j); + } + + /* do nothing */ + return (size * nmemb); +} + + +/** + * This function is invoked by Curl whenever it has something + * to say. We forward its messages to the error log at level + * DEBUG. + */ +int curl_debugfunction(CURL *curl, curl_infotype infotype, char *data, size_t datalen, void *ourdata) +{ + apr_size_t i, effectivelen; + apr_thread_t *thread = (apr_thread_t *)ourdata; + + if (error_log_level < LOG_DEBUG) return 0; + + effectivelen = datalen; + for(i = 0; i < datalen; i++) { + if ((data[i] == 0x0a)||(data[i] == 0x0d)) { + effectivelen = i; + break; + } + } + + if (error_log_level >= LOG_DEBUG) { + if (infotype == CURLINFO_TEXT) { + error_log(LOG_DEBUG, thread, "CURL: %s", _log_escape(apr_thread_pool_get(thread), data, effectivelen)); + } + } + if (error_log_level >= LOG_DEBUG2) { + if (infotype == CURLINFO_HEADER_IN) { + error_log(LOG_DEBUG2, thread, "CURL: HEADER_IN %s", _log_escape(apr_thread_pool_get(thread), data, effectivelen)); + } + else if (infotype == CURLINFO_HEADER_OUT) { + error_log(LOG_DEBUG2, thread, "CURL: HEADER_OUT %s", _log_escape(apr_thread_pool_get(thread), data, effectivelen)); + } + else if (infotype == CURLINFO_DATA_IN) { + error_log(LOG_DEBUG2, thread, "CURL: DATA_IN %s", _log_escape(apr_thread_pool_get(thread), data, effectivelen)); + } + else if (infotype == CURLINFO_DATA_OUT) { + error_log(LOG_DEBUG2, thread, "CURL: DATA_OUT %s", _log_escape(apr_thread_pool_get(thread), data, effectivelen)); + } + } + + return 0; +} + + +/** + * Initialise the necessary resources and structures. + */ +static void logc_init(void) +{ + char errstr[1024]; + apr_status_t rc = 0; + const char *errptr = NULL; + int i, erroffset; + + queue = apr_array_make(pool, 64, sizeof(entry_t *)); + if (queue == NULL) { + error_log(LOG_ERROR, NULL, MEMALLOC_ERROR_MSG); + logc_shutdown(1); + } + + in_progress = apr_hash_make(pool); + if (in_progress == NULL) { + error_log(LOG_ERROR, NULL, MEMALLOC_ERROR_MSG); + logc_shutdown(1); + } + + if ((rc = apr_global_mutex_create(&gmutex, lockfile, APR_LOCK_DEFAULT, pool)) != APR_SUCCESS) { + error_log(LOG_ERROR, NULL, "Failed to create global mutex: %s", + apr_strerror(rc, errstr, 1024)); + logc_shutdown(1); + } + + if ((rc = apr_thread_mutex_create(&mutex, APR_THREAD_MUTEX_UNNESTED, pool)) != APR_SUCCESS) { + error_log(LOG_ERROR, NULL, "Failed to create thread mutex: %s", + apr_strerror(rc, errstr, 1024)); + logc_shutdown(1); + } + + entry_counter = 1; + + curl_handles = apr_array_make(pool, max_connections, sizeof(CURL *)); + if (curl_handles == NULL) { + error_log(LOG_ERROR, NULL, MEMALLOC_ERROR_MSG); + logc_shutdown(1); + } + + /* Initialise a number of Curl handles. */ + for(i = 0; i < max_connections; i++) { + CURL *curl = NULL; + + /* Create cURL handle. */ + curl = curl_easy_init(); + + /* Pre-configure the handle. */ + curl_easy_setopt(curl, CURLOPT_UPLOAD, TRUE); + curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, (char *)NULL); + curl_easy_setopt(curl, CURLOPT_URL, console_uri); + curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0); + /* SSLv3 works better overall as some servers have issues with TLS */ + curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_SSLv3); + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 15); + curl_easy_setopt(curl, CURLOPT_NOSIGNAL, TRUE); + curl_easy_setopt(curl, CURLOPT_HEADER, TRUE); + + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_writefunction); + + *(CURL **)apr_array_push(curl_handles) = curl; + } + + logline_regex = pcre_compile(logline_pattern, PCRE_CASELESS, &errptr, &erroffset, NULL); + if (logline_regex == NULL) { + error_log(LOG_ERROR, NULL, "Failed to compile pattern: %s\n", logline_pattern); + logc_shutdown(1); + } + + requestline_regex = pcre_compile(requestline_pattern, PCRE_CASELESS, &errptr, &erroffset, NULL); + if (requestline_regex == NULL) { + error_log(LOG_ERROR, NULL, "Failed to compile pattern: %s\n", requestline_pattern); + logc_shutdown(1); + } +} + + +/** + * HACK: To allow two mlogcs running against a single dataset we use the + * mtime as a flag for deletion. + * + * 1) Check file date. + * 2) If it is KEEP_ENTRIES_REMOVE_TIME, then remove the file. + * 3) Otherwise set the date and let the other mlogc remove it. + */ +static void keep_entries_hack(apr_pool_t *mp, apr_thread_t *thread, const char *fn) +{ + apr_file_t *f = NULL; + apr_finfo_t finfo; + char errstr[1024]; + apr_status_t rc; + + /* Opening for write as required for exclusive lock */ + if ((rc = apr_file_open(&f, fn, APR_READ|APR_WRITE|APR_APPEND, APR_OS_DEFAULT, mp)) != APR_SUCCESS) { + error_log(LOG_ERROR, thread, "Could not open \"%s\": %s", fn, apr_strerror(rc, errstr, 1024)); + return; + } + + if ((rc = apr_file_lock(f, APR_FLOCK_EXCLUSIVE|APR_FLOCK_NONBLOCK)) != APR_SUCCESS) { + error_log(LOG_DEBUG2, thread, "Waiting for lock on \"%s\": %s", fn, apr_strerror(rc, errstr, 1024)); + if ((rc = apr_file_lock(f, APR_FLOCK_EXCLUSIVE)) != APR_SUCCESS) { + error_log(LOG_ERROR, thread, "Could not lock \"%s\": %s", fn, apr_strerror(rc, errstr, 1024)); + apr_file_close(f); + return; + } + } + error_log(LOG_DEBUG2, thread, "Locked: %s", fn); + + /* For testing only */ + TEST_WITH_RAND_SLEEP(2); + + if ((rc = apr_stat(&finfo, fn, APR_FINFO_MIN, mp)) != APR_SUCCESS) { + error_log(LOG_ERROR, thread, "Could not stat \"%s\": %s", fn, apr_strerror(rc, errstr, 1024)); + error_log(LOG_DEBUG2, thread, "Unlocked: %s", fn); + apr_file_close(f); + return; + } + + if (error_log_level >= LOG_DEBUG) { + error_log(LOG_DEBUG, thread, "STAT \"%s\" {uid=%d; gid=%d; size=%" APR_OFF_T_FMT "; csize=%" APR_OFF_T_FMT "; atime=%" APR_TIME_T_FMT "; ctime=%" APR_TIME_T_FMT "; mtime=%" APR_TIME_T_FMT "}", fn, finfo.user, finfo.group, finfo.size, finfo.csize, finfo.atime, finfo.ctime, finfo.mtime); + } + + if (finfo.mtime != KEEP_ENTRIES_REMOVE_TIME) { + error_log(LOG_DEBUG2, thread, "Set mtime: %s", fn); + if ((rc = apr_file_mtime_set(fn, (apr_time_t)KEEP_ENTRIES_REMOVE_TIME, mp)) != APR_SUCCESS) { + error_log(LOG_ERROR, thread, "Could not set mtime on \"%s\": %s", fn, apr_strerror(rc, errstr, 1024)); + } + error_log(LOG_DEBUG2, thread, "Unlocked: %s", fn); + apr_file_close(f); + return; + } + + + error_log(LOG_DEBUG, thread, "Removing: %s", fn); + error_log(LOG_DEBUG2, thread, "Unlocked: %s", fn); + apr_file_close(f); + apr_file_remove(fn, mp); +} + + +/** + * Worker thread. Works in a loop, fetching jobs from the queue, + * until the queue is empty or it is otherwise told to quit. + */ +static void * APR_THREAD_FUNC thread_worker(apr_thread_t *thread, void *data) +{ + unsigned int loop_count = 0; + CURL *curl = (CURL *)data; + entry_t **entryptr = NULL; + entry_t *entry = NULL; + apr_status_t rc; + apr_finfo_t finfo; + int capturevector[CAPTUREVECTORSIZE]; + int take_new = 1; + apr_pool_t *tpool; + struct curl_slist *headerlist = NULL; + char curl_error_buffer[CURL_ERROR_SIZE] = ""; + int num_requests = 0; + + /* There is no need to do the sleep if this was an invalid entry + * as the sleep is just to protect flooding the console server + * with rapid requests. With an invalid entry we never hit the + * server, so we should not delay processing the next event. + */ + int nodelay = 0; + + + error_log(LOG_DEBUG, thread, "Worker thread starting."); + + /* Each worker uses its own pool to manage memory. To avoid + * memory leaks the pool is cleared after each processed + * entry. + */ + apr_pool_create(&tpool, thread_pool); + + /* Process jobs in a queue until there are no more jobs to process. */ + for(;;) { + nodelay = 0; + + /* Do we need to shut down? */ + if (running == 0) { + error_log(LOG_DEBUG, thread, "We were told to shut down."); + goto THREAD_SHUTDOWN; + } + + /* Is there a problem with the server? We need + * to shut down if there is. Except that we don't + * want to shut down if we were launched to investigate + * if the server came back online (loop_count will be + * zero in that case). + */ + if ((server_error == 1)&&(loop_count != 0)) { + error_log(LOG_DEBUG, thread, "Shutting down due to server error."); + goto THREAD_SHUTDOWN; + } + + loop_count++; + + /* Get a new entry, but only if we need one. */ + if (take_new) { + error_log(LOG_DEBUG, thread, "Worker fetch locking thread mutex."); + if (APR_STATUS_IS_EBUSY(apr_thread_mutex_trylock(mutex))) { + error_log(LOG_DEBUG, thread, "Worker fetch waiting on thread mutex."); + apr_thread_mutex_lock(mutex); + } + + error_log(LOG_DEBUG, thread, "Worker fetch started."); + + /* Deal with the previous entry. */ + if (entry != NULL) { + error_log(LOG_DEBUG, thread, "Removing previous entry from storage."); + transaction_log(TXOUT, entry->line); + + /* Remove previous entry from storage. */ + apr_hash_set(in_progress, &entry->id, sizeof(entry->id), NULL); + + /* Release the memory it used to occupy. */ + free((void *)entry->line); + free(entry); + entry = NULL; + } + + error_log(LOG_DEBUG, thread, "Getting one entry from the queue."); + + /* Get one entry. */ + entryptr = (entry_t **)apr_array_pop(queue); + if (entryptr == NULL) { + error_log(LOG_DEBUG, thread, "Worker fetch unlocking thread mutex."); + apr_thread_mutex_unlock(mutex); + error_log(LOG_DEBUG, thread, "No more work for this thread, exiting."); + + goto THREAD_SHUTDOWN; + } + + entry = *entryptr; + apr_hash_set(in_progress, &entry->id, sizeof(entry->id), entry); + + error_log(LOG_DEBUG, thread, "Worker fetch completed."); + + error_log(LOG_DEBUG, thread, "Worker fetch unlocking thread mutex."); + apr_thread_mutex_unlock(mutex); + } + + /* Send one entry. */ + + error_log(LOG_DEBUG, thread, "Processing entry."); + take_new = 0; + + /* Keep track of requests processed if we need to */ + if (max_worker_requests > 0) { + num_requests++; + } + + rc = pcre_exec(logline_regex, NULL, entry->line, entry->line_size, 0, 0, + capturevector, CAPTUREVECTORSIZE); + if (rc == PCRE_ERROR_NOMATCH) { /* No match. */ + error_log(LOG_WARNING, thread, "Invalid entry (failed to match regex): %s", _log_escape(tpool, entry->line, entry->line_size)); + take_new = 1; + nodelay = 1; + } + else if (rc < 0) { /* Error condition. */ + error_log(LOG_WARNING, thread, "Invalid entry (PCRE error %d): %s", rc, _log_escape(tpool, entry->line, entry->line_size)); + take_new = 1; + nodelay = 1; + } + else { /* We have a match. */ + char *uniqueid = NULL; + char *auditlogentry = NULL; + char *hash = NULL; + char *summary = NULL; + char *credentials = NULL; + + error_log(LOG_DEBUG, thread, "Regular expression matched."); + + /* For testing only */ + TEST_WITH_RAND_SLEEP(2); + + uniqueid = apr_psprintf(tpool, "%.*s", + (capturevector[2*13+1] - capturevector[2*13]), (entry->line + capturevector[2*13])); + auditlogentry = apr_psprintf(tpool, "%s/%.*s", log_repository, + (capturevector[2*15+1] - capturevector[2*15]), (entry->line + capturevector[2*15])); + hash = apr_psprintf(tpool, "X-Content-Hash: %.*s", + (capturevector[2*18+1] - capturevector[2*15]), (entry->line + capturevector[2*18])); + summary = apr_psprintf(tpool, "X-ForensicLog-Summary: %s", entry->line); + credentials = apr_psprintf(tpool, "%s:%s", sensor_username, sensor_password); + + rc = apr_stat(&finfo, auditlogentry, APR_FINFO_SIZE, tpool); + if (rc == APR_SUCCESS) { + FILE *hd_src; + char response_buf[STATUSBUF_SIZE]; + CURLcode res; + + if (error_log_level >= LOG_DEBUG) { + error_log(LOG_DEBUG, thread, "STAT \"%s\" {uid=%d; gid=%d; size=%" APR_OFF_T_FMT "; csize=%" APR_OFF_T_FMT "; atime=%" APR_TIME_T_FMT "; ctime=%" APR_TIME_T_FMT "; mtime=%" APR_TIME_T_FMT "}", auditlogentry, finfo.user, finfo.group, finfo.size, finfo.csize, finfo.atime, finfo.ctime, finfo.mtime); + } + + /* Initialize the respone buffer with a hidden value */ + response_buf[0] = 0; + response_buf[1] = 1; + + if (finfo.size == 0) { + error_log(LOG_WARNING, thread, "File found (%" APR_SIZE_T_FMT " bytes), skipping.", finfo.size); + take_new = 1; + nodelay = 1; + goto THREAD_CLEANUP; + } + else { + error_log(LOG_DEBUG, thread, "File found (%" APR_SIZE_T_FMT " bytes), activating cURL.", finfo.size); + } + + + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); + curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, curl_debugfunction); + curl_easy_setopt(curl, CURLOPT_DEBUGDATA, thread); + curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_error_buffer); + curl_easy_setopt(curl, CURLOPT_USERPWD, credentials); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (char *)response_buf); + + headerlist = curl_slist_append(headerlist, "Expect:"); + headerlist = curl_slist_append(headerlist, hash); + headerlist = curl_slist_append(headerlist, summary); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist); + + hd_src = fopen(auditlogentry, "rb"); + if (hd_src == NULL) { + error_log(LOG_WARNING, thread, "Invalid entry (failed to open file for reading): %s", auditlogentry); + take_new = 1; + nodelay = 1; + goto THREAD_CLEANUP; + } + + curl_easy_setopt(curl, CURLOPT_READDATA, hd_src); + curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, finfo.size); +#if 0 + mandatory on win32? + curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback); +#endif + + res = curl_easy_perform(curl); + + fclose(hd_src); + + if (res == 0) { + long response_code = 0; + + res = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + error_log(LOG_DEBUG, thread, "Request returned with status \"%ld %s\": %s", response_code, response_buf, uniqueid); + + + if (response_code == 0) { + /* Assume problem with connection */ + error_log(LOG_WARNING, thread, "Flagging server as errored after failure to retrieve response code for entry %s (cURL code %d): Possible SSL negotiation error", + uniqueid, res); + apr_sleep(1000 * 1000); + take_new = 0; + server_error = 1; + server_error_last_check_time = apr_time_now(); + } + else if (res != 0) { + error_log(LOG_WARNING, thread, "Flagging server as errored after failure to retrieve response code for entry %s (cURL code %d): %s", + uniqueid, res, curl_error_buffer); + apr_sleep(1000 * 1000); + take_new = 0; + server_error = 1; + server_error_last_check_time = apr_time_now(); + } + else { + if (response_code == 200) { + double total_time, upload_size; + + if (server_error == 1) { + error_log(LOG_NOTICE, thread, "Clearing the server error flag after successful entry submission: %s", uniqueid); + } + server_error = 0; + server_error_last_check_time = 0; + + curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &total_time); + curl_easy_getinfo(curl, CURLINFO_SIZE_UPLOAD, &upload_size); + + if (!keep_entries) { + error_log(LOG_DEBUG, thread, "Removing: %s", auditlogentry); + apr_file_remove(auditlogentry, tpool); + } + else if (keep_entries == KEEP_ENTRIES_REMOVE_HACK) { + keep_entries_hack(tpool, thread, auditlogentry); + } + + error_log(LOG_NOTICE, thread, "Entry completed (%.3f seconds, %.0f bytes): %s", + total_time, upload_size, + uniqueid); + take_new = 1; + } + else if (response_code == 409) { + /* Assume problem with audit log entry. */ + error_log(LOG_WARNING, thread, "Failed to submit entry with \"409 %s\": %s", + response_buf, uniqueid); + take_new = 1; + } + else { + /* Assume problem with server. */ + error_log(LOG_WARNING, thread, "Flagging server as errored after failure to submit entry %s with HTTP response code %ld: %s", + uniqueid, response_code, response_buf); + server_error = 1; + server_error_last_check_time = apr_time_now(); + take_new = 0; + } + } + } + else { /* Something isn't right. */ + error_log(LOG_WARNING, thread, "Flagging server as errored after failure to submit entry %s (cURL code %d): %s", uniqueid, res, curl_error_buffer); + server_error = 1; + server_error_last_check_time = apr_time_now(); + take_new = 0; + + } + } + else { + error_log(LOG_WARNING, thread, "Invalid entry (file not found %d): %s", rc, auditlogentry); + take_new = 1; + nodelay = 1; + } + + /* If we are tracking num_requests, then shutdown if we are + * over our threshold. + */ + if (num_requests && (num_requests >= max_worker_requests)) { + error_log(LOG_NOTICE, thread, "Reached max requests (%d) for this worker, exiting.", max_worker_requests); + + goto THREAD_SHUTDOWN; + } + } + + THREAD_CLEANUP: + + /* Sleep if we sent data to the server so we do not flood */ + /* ENH: Need to sleep for 1ms in a loop checking for shutdown */ + if ((nodelay == 0) && (transaction_delay > 0)) { + error_log(LOG_DEBUG, thread, "Sleeping for %d msec.", transaction_delay); + apr_sleep(transaction_delay * 1000); + } + + if (headerlist != NULL) { + curl_slist_free_all(headerlist); + headerlist = NULL; + } + + apr_pool_clear(tpool); + + error_log(LOG_DEBUG, thread, "Worker processing completed."); + } + + THREAD_SHUTDOWN: + + error_log(LOG_DEBUG, thread, "Worker shutdown locking thread mutex."); + if (APR_STATUS_IS_EBUSY(apr_thread_mutex_trylock(mutex))) { + error_log(LOG_DEBUG, thread, "Worker shutdown waiting on thread mutex."); + apr_thread_mutex_lock(mutex); + } + + /* Deal with the previous entry, if any. */ + if (entry != NULL) { + apr_hash_set(in_progress, &entry->id, sizeof(entry->id), NULL); + + if (take_new == 0) { /* Not done. */ + *(entry_t **)apr_array_push(queue) = entry; + } + else { + transaction_log(TXOUT, entry->line); + free((void *)entry->line); + free(entry); + } + + entry = NULL; + } + + /* Return curl handle to the pool for reuse. */ + *(CURL **)apr_array_push(curl_handles) = curl; + + /* No more work, exit. */ + current_workers--; + + error_log(LOG_DEBUG, thread, "Worker shutdown unlocking thread mutex."); + apr_thread_mutex_unlock(mutex); + + apr_pool_destroy(tpool); + + error_log(LOG_DEBUG, thread, "Worker thread completed."); + + apr_thread_exit(thread, 0); + + return NULL; +} + + +/** + * Creates one new worker, giving it one of the available + * Curl handles to work with. + */ +static void create_new_worker(int lock) +{ + apr_thread_t *thread = NULL; + CURL **curlptr = NULL; + + if (lock) { + error_log(LOG_DEBUG, NULL, "Worker creation locking thread mutex."); + if (APR_STATUS_IS_EBUSY(apr_thread_mutex_trylock(mutex))) { + error_log(LOG_DEBUG, NULL, "Worker creation waiting on thread mutex."); + apr_thread_mutex_lock(mutex); + } + } + + error_log(LOG_DEBUG, NULL, "Worker creation started."); + + /* A sanity check: this part executes under lock and + * we want to make *sure* we don't create more threads + * than we are allowed. + */ + if (current_workers >= max_connections) { + if (lock) { + error_log(LOG_DEBUG, NULL, "Worker creation unlocking thread mutex."); + apr_thread_mutex_unlock(mutex); + } + return; + } + + /* Cleanup thread pool when idle */ + if (current_workers <= 0) { + if (thread_pool != NULL) { + error_log(LOG_DEBUG, NULL, "Destroying thread_pool."); + apr_pool_destroy(thread_pool); + thread_pool = NULL; + } + error_log(LOG_DEBUG, NULL, "Creating thread_pool."); + apr_pool_create(&thread_pool, NULL); + } + + curlptr = (CURL **)apr_array_pop(curl_handles); + if (curlptr != NULL) { + apr_threadattr_t *thread_attrs; + apr_status_t rc; + + apr_threadattr_create(&thread_attrs, thread_pool); + apr_threadattr_detach_set(thread_attrs, 1); + apr_threadattr_stacksize_set(thread_attrs, 1024); + + rc = apr_thread_create(&thread, thread_attrs, thread_worker, *curlptr, thread_pool); + if (rc != APR_SUCCESS) { + if (lock) { + error_log(LOG_DEBUG, NULL, "Worker creation unlocking thread mutex."); + apr_thread_mutex_unlock(mutex); + } + error_log(LOG_ERROR, NULL, "Failed to create new worker thread: %d", rc); + logc_shutdown(1); + } + + current_workers++; + } + else { + if (lock) { + error_log(LOG_DEBUG, NULL, "Worker creation unlocking thread mutex."); + apr_thread_mutex_unlock(mutex); + } + error_log(LOG_ERROR, NULL, "No more cURL handles (Internal Error)."); + logc_shutdown(1); + } + + error_log(LOG_DEBUG, NULL, "Worker creation completed: %pp", thread); + + if (lock) { + error_log(LOG_DEBUG, NULL, "Worker creation unlocking thread mutex."); + apr_thread_mutex_unlock(mutex); + } +} + + +/** + * This function implements the management thread. + */ +static void * APR_THREAD_FUNC thread_manager(apr_thread_t *thread, void *data) +{ + apr_time_t last = 0; + apr_time_t now = 0; + + error_log(LOG_DEBUG, thread, "Management thread: Starting."); + + for(;;) { + now = apr_time_now(); + + /* Should we stop running? */ + if (running == 0) { + /* We need to be last */ + error_log(LOG_DEBUG, thread, "Management thread: Waiting for worker threads to finish."); + while(current_workers > 0) { + apr_sleep(10 * 1000); + } + + if (have_read_data) { + error_log(LOG_NOTICE, thread, "Running final transaction checkpoint."); + transaction_checkpoint(); + } + + error_log(LOG_DEBUG, thread, "Management thread: Exiting."); + management_thread_active = 0; + apr_thread_exit(thread, 0); + } + + /* Sleep for a while, but wake up often to check running status */ + if ((last > 0) && ((now - last) < MANAGER_SLEEP)) { + apr_sleep(MANAGER_SUBSLEEP); + continue; + } + last = now; + + error_log(LOG_DEBUG2, thread, "Management thread: Processing"); + + /* When the server is flagged errored we need to + * create a worker thread from time to time to + * investigate. + */ + if (server_error) { + if ((current_workers == 0)&& + (apr_time_sec(now - server_error_last_check_time) > server_error_timeout)) + { + server_error_last_check_time = now; + error_log(LOG_DEBUG, thread, "Management thread: Creating worker thread to investigate server."); + create_new_worker(1); + } + } + else { + if ((current_workers < max_connections)&&(queue->nelts > current_workers)) { + error_log(LOG_DEBUG, thread, "Management thread: Creating worker thread to catch up with the queue."); + create_new_worker(1); + } + } + + /* Initiate a transaction log checkpoint if enough time passed since the last one. */ + if (apr_time_sec(now - checkpoint_time_last) > checkpoint_interval) { + error_log(LOG_DEBUG, thread, "Management thread: Initiating a checkpoint" + " (previous was %" APR_TIME_T_FMT " seconds ago).", apr_time_sec(now - checkpoint_time_last)); + checkpoint_time_last = now; + transaction_checkpoint(); + } + else { + error_log(LOG_DEBUG2, thread, "Management thread: Last checkpoint was %" APR_TIME_T_FMT " seconds ago.", + apr_time_sec(now - checkpoint_time_last)); + } + } + + return NULL; +} + +#ifndef WIN32 +/** + * Thread to handle all signals + */ +static void * APR_THREAD_FUNC thread_signals(apr_thread_t *thread, void *data) +{ + apr_status_t rc; + + error_log(LOG_DEBUG, thread, "Signal thread: Starting."); + rc = apr_signal_thread(handle_signals); + if (rc != APR_SUCCESS) { + error_log(LOG_DEBUG, thread, "Signal thread: Error %d", rc); + logc_shutdown(1); + } + + return NULL; +} +#endif /* WIN32 */ + +/** + * The main loop where we receive log entries from + * Apache and add them to the queue, sometimes creating + * new worker threads to handle them. + */ +static void receive_loop(void) { + apr_file_t *fd_stdin; + apr_size_t nbytes = PIPE_BUF_SIZE; + char *buf = apr_palloc(pool, PIPE_BUF_SIZE + 1); + char errstr[1024]; + apr_size_t evnt = 0; /* Index in buf to first event char */ + apr_size_t curr = 0; /* Index in buf to current processing char */ + apr_size_t next = 0; /* Index in buf to next unused char */ + int done = 0; + int drop_next = 0; + int buffered_events = 0; + int count = 0; + apr_pool_t *tmp_pool; + + /* Open stdin. */ + if (apr_file_open_stdin(&fd_stdin, pool) != APR_SUCCESS) { + error_log(LOG_ERROR, NULL, "Unable to open stdin for reading"); + logc_shutdown(1); + } + + /* Always want this NUL terminated */ + buf[PIPE_BUF_SIZE] = '\0'; + + apr_pool_create(&tmp_pool, NULL); + + /* Loop forever receiving entries from stdin. */ + while(!done || (curr < next)) { + apr_status_t rc; + + if (error_log_level >= LOG_DEBUG2) { + error_log(LOG_DEBUG2, NULL, "Internal state: [evnt \"%" APR_SIZE_T_FMT "\"][curr \"%" APR_SIZE_T_FMT "\"][next \"%" APR_SIZE_T_FMT "\"][nbytes \"%" APR_SIZE_T_FMT "\"]", evnt, curr, next, nbytes); + } + + /* If we are not done and have the space, read more */ + if (!done && (nbytes > 0)) { + buffered_events = 0; + nbytes = PIPE_BUF_SIZE - next; + rc = apr_file_read(fd_stdin, (buf + next), &nbytes); + if (rc != APR_SUCCESS) { + if (have_read_data) { + error_log(LOG_NOTICE, NULL, "No more data to read, emptying buffer: %s", apr_strerror(rc, errstr, 1024)); + } + done = 1; + } + else { + have_read_data = 1; + if (error_log_level == LOG_DEBUG) { + error_log(LOG_DEBUG, NULL, "Read %" APR_SIZE_T_FMT " bytes from pipe", nbytes); + } + else { + error_log(LOG_DEBUG2, NULL, "Read %" APR_SIZE_T_FMT " bytes from pipe: `%s'", nbytes, _log_escape(tmp_pool, (buf + next), nbytes)); + } + } + + next += nbytes; + } + + /** + * Each chunk of data we receive can contain one or more lines for + * which we need to find the EOL marker and then queue the event + * up to that. So, find/queue as many lines in the buffer as we + * can. Any remaining data will get shifted back to the beginning + * of the buffer and the buffer size for the next read adjusted. + */ + while(curr < next) { + /* Look for EOL so we can parse the event */ + while((curr < next) && (buf[curr] != 0x0a)) { + curr++; + } + if (buf[curr] == 0x0a) { + buf[curr] = '\0'; + + /* We may have to drop this one if it previously failed */ + if (drop_next) { + error_log(LOG_ERROR, NULL, "Dropping remaining portion of failed event: `%s'", _log_escape(tmp_pool, (buf + evnt), (curr - evnt))); + drop_next = 0; + } + else { + transaction_log(TXIN, buf + evnt); + error_log(LOG_DEBUG2, NULL, "Received audit log entry (count %lu queue %d workers %d): %s", + entry_counter, queue->nelts, current_workers, _log_escape(tmp_pool, (buf + evnt), strlen(buf + evnt))); + add_entry(buf + evnt, 1); + buffered_events++; + } + + /* Advance indexes to next event in buf */ + evnt = curr = curr + 1; + } + else { + error_log(LOG_DEBUG2, NULL, "Event buffer contains partial event: `%s'", _log_escape(tmp_pool, (buf + evnt), (next - evnt))); + break; + } + } + + + if (buffered_events > 0) { + error_log(LOG_DEBUG, NULL, "Processed %d entries from buffer.", buffered_events); + + /* Move the unused portion of the buffer to the beginning */ + next -= evnt; + curr -= evnt; + memmove(buf, (buf + evnt), next); + + error_log(LOG_DEBUG2, NULL, "Shifted buffer back %" APR_SIZE_T_FMT " and offset %" APR_SIZE_T_FMT " bytes for next read: `%s'", evnt, next, _log_escape(tmp_pool, buf, next)); + + evnt = 0; + } + else if (next == PIPE_BUF_SIZE) { + /** + * There is a chance we could fill the buffer, but not have finished + * reading the event (no EOL yet), so we need to say so and drop + * all data until we find the end of the event that is too large. + */ + + if (drop_next) { + error_log(LOG_ERROR, NULL, "Event continuation too large, dropping it as well: `%s'", _log_escape(tmp_pool, buf, PIPE_BUF_SIZE)); + } + else { + error_log(LOG_ERROR, NULL, "Event too large, dropping event: `%s'", _log_escape(tmp_pool, buf, PIPE_BUF_SIZE)); + } + + /* Rewind buf and mark that we need to drop up to the next event */ + evnt = curr = next = 0; + drop_next = 1; + } + + nbytes = PIPE_BUF_SIZE - next; + + if (count++ > 1000) { + count = 0; + error_log(LOG_DEBUG, NULL, "Recycling tmp_pool."); + apr_pool_destroy(tmp_pool); + apr_pool_create(&tmp_pool, NULL); + } + else { + apr_pool_clear(tmp_pool); + } + } + + /* Wait for queue to empty if specified */ + if ((server_error == 0) && (opt_force != 0) && (queue->nelts > 0)) { + error_log(LOG_NOTICE, NULL, "Waiting for queue to empty (%d active).", queue->nelts); + while ((server_error == 0) && (opt_force != 0) && (queue->nelts > 0)) { + apr_sleep(10 * 1000); + } + if (queue->nelts > 0) { + error_log(LOG_ERROR, NULL, "Could not empty queue (%d active).", queue->nelts); + } + } +} + + +/** + * Creates the management thread. + */ +static void start_management_thread(void) +{ + apr_thread_t *thread = NULL; + apr_threadattr_t *thread_attrs; + apr_status_t rc; + + apr_threadattr_create(&thread_attrs, pool); + apr_threadattr_detach_set(thread_attrs, 1); + apr_threadattr_stacksize_set(thread_attrs, 1024); + + management_thread_active = 1; + + rc = apr_thread_create(&thread, thread_attrs, thread_manager, NULL, pool); + if (rc != APR_SUCCESS) { + error_log(LOG_ERROR, NULL, "Failed to create new management thread: %d", rc); + management_thread_active = 0; + logc_shutdown(1); + } +} +#ifndef WIN32 +/** + * Creates a thread to handle all signals + */ +static void start_signal_thread(void) +{ + apr_thread_t *thread = NULL; + apr_threadattr_t *thread_attrs; + apr_status_t rc; + + apr_threadattr_create(&thread_attrs, pool); + apr_threadattr_detach_set(thread_attrs, 1); + apr_threadattr_stacksize_set(thread_attrs, 1024); + + rc = apr_thread_create(&thread, thread_attrs, thread_signals, NULL, pool); + if (rc != APR_SUCCESS) { + error_log(LOG_ERROR, NULL, "Failed to create new signal thread: %d", rc); + logc_shutdown(1); + } +} +#endif /* WIN32 */ + +/** + * Usage text. + */ +static void usage(void) { + fprintf(stderr, "ModSecurity Log Collector (mlogc) v%s\n", VERSION); + fprintf(stderr, " Usage: mlogc [options] /path/to/the/mlogc.conf\n"); + fprintf(stderr, "\n"); + fprintf(stderr, " Options:\n"); + fprintf(stderr, " -f Force depletion of queue on exit\n"); + fprintf(stderr, " -v Version information\n"); + fprintf(stderr, " -h This help\n\n"); +} + +/** + * Version text. + */ +static void version(void) { + fprintf(stderr, "ModSecurity Log Collector (mlogc) v%s\n", VERSION); + fprintf(stderr, " APR: compiled=\"%s\"; loaded=\"%s\"\n", APR_VERSION_STRING, apr_version_string()); + fprintf(stderr, " PCRE: compiled=\"%d.%d\"; loaded=\"%s\"\n", PCRE_MAJOR, PCRE_MINOR, pcre_version()); + fprintf(stderr, " cURL: compiled=\"%s\"; loaded=\"%s\"\n", LIBCURL_VERSION, curl_version()); + fprintf(stderr, "\n"); +} + +/** + * This is the main entry point. + */ +int main(int argc, const char * const argv[]) { + apr_getopt_t *opt; + apr_status_t rc; + + apr_app_initialize(&argc, &argv, NULL); + atexit(apr_terminate); + + curl_global_init(CURL_GLOBAL_ALL); + atexit(logc_cleanup); + + logc_pid = getpid(); + apr_pool_create(&pool, NULL); + apr_pool_create(&recv_pool, NULL); + +#ifndef WIN32 + apr_setup_signal_thread(); +#else + apr_signal(SIGINT, handle_signals); + apr_signal(SIGTERM, handle_signals); +#endif /* WIN32 */ + + if (argc < 2) { + usage(); + logc_shutdown(1); + } + + /* Commandline opts */ + rc = apr_getopt_init(&opt, pool, argc, argv); + if (rc != APR_SUCCESS) { + usage(); + logc_shutdown(1); + } + + do { + char ch; + const char *val; + rc = apr_getopt(opt, CMDLINE_OPTS, &ch, &val); + switch (rc) { + case APR_SUCCESS: + switch (ch) { + case 'f': + opt_force = 1; + break; + case 'v': + version(); + logc_shutdown(0); + case 'h': + usage(); + logc_shutdown(0); + } + break; + case APR_BADCH: + case APR_BADARG: + usage(); + logc_shutdown(1); + } + } while (rc != APR_EOF); + + /* Conf file is last */ + conffile = argv[argc - 1]; + + read_configuration(); + init_configuration(); + + logc_init(); + transaction_log_init(); + + running = 1; + server_error = 0; + + start_management_thread(); +#ifndef WIN32 + start_signal_thread(); +#endif /* WIN32 */ + + /* Process stdin until EOF */ + receive_loop(); + + logc_shutdown(0); + + return 0; +} diff --git a/apache2/mod_security2.c b/apache2/mod_security2.c new file mode 100644 index 0000000..01ff01e --- /dev/null +++ b/apache2/mod_security2.c @@ -0,0 +1,1158 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ +#include + +#include "http_core.h" +#include "http_request.h" + +#include "modsecurity.h" +#include "apache2.h" +#include "http_main.h" +#include "pdf_protect.h" + +#include "msc_logging.h" +#include "msc_util.h" + + +/* ModSecurity structure */ + +msc_engine DSOLOCAL *modsecurity = NULL; + +/* Global module variables; these are used for the Apache-specific functionality */ + +char DSOLOCAL *chroot_dir = NULL; + +unsigned int DSOLOCAL chroot_completed = 0; + +char DSOLOCAL *new_server_signature = NULL; + +char DSOLOCAL *real_server_signature = NULL; + +char DSOLOCAL *guardianlog_name = NULL; + +apr_file_t DSOLOCAL *guardianlog_fd = NULL; + +char DSOLOCAL *guardianlog_condition = NULL; + + +/* -- Miscellaneous functions -- */ + +/** + * Intercepts transaction, using the method specified + * in the structure itself. MUST return an HTTP status code, + * which will be used to terminate the transaction. + */ +int perform_interception(modsec_rec *msr) { + msre_actionset *actionset = NULL; + const char *message = NULL; + const char *phase_text = ""; + int status = DECLINED; + int log_level = 1; + + /* Sanity checks first. */ + + if (msr->was_intercepted == 0) { + msr_log(msr, 1, "Internal Error: Asked to intercept request but was_intercepted is zero"); + return DECLINED; + } + + if (msr->phase > 4) { + msr_log(msr, 1, "Internal Error: Asked to intercept request in phase %d.", msr->phase); + msr->was_intercepted = 0; + return DECLINED; + } + + /* OK, we're good to go. */ + + actionset = msr->intercept_actionset; + phase_text = apr_psprintf(msr->mp, " (phase %d)", msr->phase); + + /* By default we log at level 1 but we switch to 4 + * if a nolog action was used or this is not the initial request + * to hide the message. + */ + log_level = (actionset->log != 1) ? 4 : 1; + + /* Pause the request first (if configured and the initial request). */ + if (actionset->intercept_pause) { + msr_log(msr, (log_level > 3 ? log_level : log_level + 1), "Pausing transaction for " + "%d msec.", actionset->intercept_pause); + /* apr_sleep accepts microseconds */ + apr_sleep((apr_interval_time_t)(actionset->intercept_pause * 1000)); + } + + /* Determine how to respond and prepare the log message. */ + switch(actionset->intercept_action) { + case ACTION_DENY : + if (actionset->intercept_status != 0) { + status = actionset->intercept_status; + message = apr_psprintf(msr->mp, "Access denied with code %d%s.", + status, phase_text); + } else { + log_level = 1; + status = HTTP_INTERNAL_SERVER_ERROR; + message = apr_psprintf(msr->mp, "Access denied with code 500%s " + "(Internal Error: Invalid status code requested %d).", + phase_text, actionset->intercept_status); + } + break; + + case ACTION_PROXY : + if (msr->phase < 3) { + if (ap_find_linked_module("mod_proxy.c") == NULL) { + log_level = 1; + status = HTTP_INTERNAL_SERVER_ERROR; + message = apr_psprintf(msr->mp, "Access denied with code 500%s " + "(Configuration Error: Proxy action to %s requested but mod_proxy not found).", + phase_text, + log_escape_nq(msr->mp, actionset->intercept_uri)); + } else { + msr->r->filename = apr_psprintf(msr->mp, "proxy:%s", actionset->intercept_uri); + msr->r->proxyreq = PROXYREQ_REVERSE; + msr->r->handler = "proxy-server"; + status = OK; + message = apr_psprintf(msr->mp, "Access denied using proxy to%s %s.", + phase_text, + log_escape_nq(msr->mp, actionset->intercept_uri)); + } + } else { + log_level = 1; + status = HTTP_INTERNAL_SERVER_ERROR; + message = apr_psprintf(msr->mp, "Access denied with code 500%s " + "(Configuration Error: Proxy action requested but it does not work in output phases).", + phase_text); + } + break; + + case ACTION_DROP : + /* ENH This does not seem to work on Windows. Is there a + * better way to drop a connection anyway? + */ + #ifndef WIN32 + { + extern module core_module; + apr_socket_t *csd = ap_get_module_config(msr->r->connection->conn_config, + &core_module); + + if (csd) { + if (apr_socket_close(csd) == APR_SUCCESS) { + status = HTTP_FORBIDDEN; + message = apr_psprintf(msr->mp, "Access denied with connection close%s.", + phase_text); + } else { + log_level = 1; + status = HTTP_INTERNAL_SERVER_ERROR; + message = apr_psprintf(msr->mp, "Access denied with code 500%s " + "(Error: Connection drop requested but failed to close the " + " socket).", + phase_text); + } + } else { + log_level = 1; + status = HTTP_INTERNAL_SERVER_ERROR; + message = apr_psprintf(msr->mp, "Access denied with code 500%s " + "(Error: Connection drop requested but socket not found.", + phase_text); + } + } + #else + log_level = 1; + status = HTTP_INTERNAL_SERVER_ERROR; + message = apr_psprintf(msr->mp, "Access denied with code 500%s " + "(Error: Connection drop not implemented on this platform).", + phase_text); + #endif + break; + + case ACTION_REDIRECT : + apr_table_setn(msr->r->headers_out, "Location", actionset->intercept_uri); + if ((actionset->intercept_status == 301)||(actionset->intercept_status == 302) + ||(actionset->intercept_status == 303)||(actionset->intercept_status == 307)) + { + status = actionset->intercept_status; + } else { + status = HTTP_MOVED_TEMPORARILY; + } + message = apr_psprintf(msr->mp, "Access denied with redirection to %s using " + "status %d%s.", + log_escape_nq(msr->mp, actionset->intercept_uri), status, + phase_text); + break; + + case ACTION_ALLOW : + status = DECLINED; + message = apr_psprintf(msr->mp, "Access allowed%s.", phase_text); + msr->was_intercepted = 0; + msr->allow_scope = ACTION_ALLOW; + break; + + case ACTION_ALLOW_PHASE : + status = DECLINED; + message = apr_psprintf(msr->mp, "Access to phase allowed%s.", phase_text); + msr->was_intercepted = 0; + msr->allow_scope = ACTION_ALLOW_PHASE; + break; + + case ACTION_ALLOW_REQUEST : + status = DECLINED; + message = apr_psprintf(msr->mp, "Access to request allowed%s.", phase_text); + msr->was_intercepted = 0; + msr->allow_scope = ACTION_ALLOW_REQUEST; + break; + + default : + log_level = 1; + status = HTTP_INTERNAL_SERVER_ERROR; + message = apr_psprintf(msr->mp, "Access denied with code 500%s " + "(Internal Error: invalid interception action %d).", + phase_text, actionset->intercept_action); + break; + } + + /* Log the message now. */ + msc_alert(msr, log_level, actionset, message, msr->intercept_message); + + return status; +} + +/** + * Retrieves a previously stored transaction context by + * looking at the main request, and the previous requests. + */ +static modsec_rec *retrieve_tx_context(request_rec *r) { + modsec_rec *msr = NULL; + request_rec *rx = NULL; + + /* Look in the current request first. */ + msr = (modsec_rec *)apr_table_get(r->notes, NOTE_MSR); + if (msr != NULL) { + msr->r = r; + return msr; + } + + /* If this is a subrequest then look in the main request. */ + if (r->main != NULL) { + msr = (modsec_rec *)apr_table_get(r->main->notes, NOTE_MSR); + if (msr != NULL) { + msr->r = r; + return msr; + } + } + + /* If the request was redirected then look in the previous requests. */ + rx = r->prev; + while(rx != NULL) { + msr = (modsec_rec *)apr_table_get(rx->notes, NOTE_MSR); + if (msr != NULL) { + msr->r = r; + return msr; + } + rx = rx->prev; + } + + return NULL; +} + +/** + * Stores transaction context where it can be found in subsequent + * phases, redirections, or subrequests. + */ +static void store_tx_context(modsec_rec *msr, request_rec *r) { + apr_table_setn(r->notes, NOTE_MSR, (void *)msr); +} + +/** + * Creates a new transaction context. + */ +static modsec_rec *create_tx_context(request_rec *r) { + apr_allocator_t *allocator = NULL; + modsec_rec *msr = NULL; + + msr = (modsec_rec *)apr_pcalloc(r->pool, sizeof(modsec_rec)); + if (msr == NULL) return NULL; + + apr_allocator_create(&allocator); + apr_allocator_max_free_set(allocator, 1024); + apr_pool_create_ex(&msr->mp, r->pool, NULL, allocator); + if (msr->mp == NULL) return NULL; + apr_allocator_owner_set(allocator, msr->mp); + + msr->modsecurity = modsecurity; + msr->r = r; + msr->r_early = r; + msr->request_time = r->request_time; + msr->dcfg1 = (directory_config *)ap_get_module_config(r->per_dir_config, + &security2_module); + + /** + * Create a special user configuration. This is where + * explicit instructions will be stored. This will be used + * to override the default settings (and to override the + * configuration in the second phase, dcfg2, with the user + * setting executed in the first phase. + */ + msr->usercfg = create_directory_config(msr->mp, NULL); + if (msr->usercfg == NULL) return NULL; + + /* Create a transaction context and populate + * it using the directory config we just + * got from Apache. + */ + msr->txcfg = create_directory_config(msr->mp, NULL); + if (msr->txcfg == NULL) return NULL; + + if (msr->dcfg1 != NULL) { + msr->txcfg = merge_directory_configs(msr->mp, msr->txcfg, msr->dcfg1); + if (msr->txcfg == NULL) return NULL; + } + init_directory_config(msr->txcfg); + + msr->txid = get_env_var(r, "UNIQUE_ID"); + if (msr->txid == NULL) { + ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r->server, + "ModSecurity: ModSecurity requires mod_unique_id to be installed."); + return NULL; + } + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Initialising transaction (txid %s).", msr->txid); + } + + /* Populate tx fields */ + msr->error_messages = apr_array_make(msr->mp, 5, sizeof(error_message *)); + msr->alerts = apr_array_make(msr->mp, 5, sizeof(char *)); + + msr->server_software = real_server_signature; + msr->local_addr = r->connection->local_ip; + msr->local_port = r->connection->local_addr->port; + + msr->remote_addr = r->connection->remote_ip; + msr->remote_port = r->connection->remote_addr->port; + + msr->request_line = r->the_request; + msr->request_uri = r->uri; + msr->request_method = r->method; + msr->query_string = r->args; + msr->request_protocol = r->protocol; + msr->request_headers = apr_table_copy(msr->mp, r->headers_in); + msr->hostname = ap_get_server_name(r); + + msr->msc_rule_mptmp = NULL; + + /* Invoke the engine to continue with initialisation */ + if (modsecurity_tx_init(msr) < 0) { + msr_log(msr, 1, "Failed to initialise transaction (txid %s).", msr->txid); + return NULL; + } + + store_tx_context(msr, r); + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Transaction context created (dcfg %pp).", msr->dcfg1); + } + + return msr; +} + + +/* -- Hooks -- */ + +/* + * Change the signature of the server if change was requested in + * configuration. We do this by locating the signature in server + * memory and writing over it. + */ +static apr_status_t change_server_signature(server_rec *s) { + char *server_version = NULL; + + if (new_server_signature == NULL) return 0; + + server_version = (char *)apache_get_server_version(); + + if (server_version == NULL) { + ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, s, + "SecServerSignature: Apache returned null as signature."); + return -1; + } + + if (strlen(server_version) >= strlen(new_server_signature)) { + strcpy(server_version, new_server_signature); + } + else { + ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, s, + "SecServerSignature: original signature too short. Please set " + "ServerTokens to Full."); + return -1; + } + + /* Check that it really changed. This assumes that what we got was + * not a copy and this could change in future versions of Apache. + */ + server_version = (char *)apache_get_server_version(); + if ((server_version == NULL) || (strcmp(server_version, new_server_signature) != 0)) { + ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, s, "SecServerSignature: Failed to change server signature to \"%s\".", new_server_signature); + return 0; + } + else { + ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, s, "SecServerSignature: Changed server signature to \"%s\".", server_version); + } + + return 1; +} + +/** + * Executed at the end of server lifetime to cleanup the allocated resources. + */ +static apr_status_t module_cleanup(void *data) { + modsecurity_shutdown(modsecurity); + return APR_SUCCESS; +} + +/** + * Pre-configuration initialisation hook. + */ +static int hook_pre_config(apr_pool_t *mp, apr_pool_t *mp_log, apr_pool_t *mp_temp) { + /* Initialise ModSecurity engine */ + modsecurity = modsecurity_create(mp, MODSEC_ONLINE); + if (modsecurity == NULL) { + ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, + "ModSecurity: Failed to initialise engine."); + return HTTP_INTERNAL_SERVER_ERROR; + } + + return OK; +} + +/** + * Main (post-configuration) module initialisation. + */ +static int hook_post_config(apr_pool_t *mp, apr_pool_t *mp_log, apr_pool_t *mp_temp, server_rec *s) { + void *init_flag = NULL; + int first_time = 0; + + /* ENH Figure out a way to validate config before we start + * - skipafter: need to make sure we found all of our targets + */ + + /* Figure out if we are here for the first time */ + apr_pool_userdata_get(&init_flag, "modsecurity-init-flag", s->process->pool); + if (init_flag == NULL) { + first_time = 1; + apr_pool_userdata_set((const void *)1, "modsecurity-init-flag", + apr_pool_cleanup_null, s->process->pool); + } else { + modsecurity_init(modsecurity, mp); + } + + /* Store the original server signature */ + real_server_signature = apr_pstrdup(mp, apache_get_server_version()); + + /* Make some space in the server signature for later */ + if (new_server_signature != NULL) { + ap_add_version_component(mp, new_server_signature); + change_server_signature(s); + } + + #if (!(defined(WIN32) || defined(NETWARE))) + + /* Internal chroot functionality */ + + if (chroot_dir != NULL) { + + /* ENH Is it safe to simply return with an error, instead + * of using exit()? + */ + + if (first_time == 0) { + ap_log_error(APLOG_MARK, APLOG_NOTICE | APLOG_NOERRNO, 0, s, + "ModSecurity: chroot checkpoint #2 (pid=%ld ppid=%ld)", (long)getpid(), (long)getppid()); + + if (chdir(chroot_dir) < 0) { + ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, s, + "ModSecurity: chroot failed, unable to chdir to %s, errno=%d (%s)", + chroot_dir, errno, strerror(errno)); + exit(1); + } + + if (chroot(chroot_dir) < 0) { + ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, s, + "ModSecurity: chroot failed, path=%s, errno=%d(%s)", + chroot_dir, errno, strerror(errno)); + exit(1); + } + + if (chdir("/") < 0) { + ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, s, + "ModSecurity: chdoot failed, unable to chdir to /, errno=%d (%s)", + errno, strerror(errno)); + exit(1); + } + + chroot_completed = 1; + + ap_log_error(APLOG_MARK, APLOG_NOTICE | APLOG_NOERRNO, 0, s, + "ModSecurity: chroot successful, path=%s", chroot_dir); + } else { + ap_log_error(APLOG_MARK, APLOG_NOTICE | APLOG_NOERRNO, 0, s, + "ModSecurity: chroot checkpoint #1 (pid=%ld ppid=%ld)", (long)getpid(), (long)getppid()); + } + } + #endif + + /* Schedule main cleanup for later, when the main pool is destroyed. */ + apr_pool_cleanup_register(mp, (void *)s, module_cleanup, apr_pool_cleanup_null); + + /* Log our presence to the error log. */ + if (first_time) { + ap_log_error(APLOG_MARK, APLOG_NOTICE | APLOG_NOERRNO, 0, s, + "%s configured.", MODSEC_MODULE_NAME_FULL); + + /* If we've changed the server signature make note of the original. */ + if (new_server_signature != NULL) { + ap_log_error(APLOG_MARK, APLOG_NOTICE | APLOG_NOERRNO, 0, s, + "Original server signature: %s", real_server_signature); + } + } + + srand((unsigned int)(time(NULL) * getpid())); + + return OK; +} + +/** + * Initialisation performed for every new child process. + */ +static void hook_child_init(apr_pool_t *mp, server_rec *s) { + modsecurity_child_init(modsecurity); +} + +/** + * Initial request processing, executed immediatelly after + * Apache receives the request headers. + */ +static int hook_request_early(request_rec *r) { + modsec_rec *msr = NULL; + int rc; + + /* This function needs to run only once per transaction + * (i.e. subrequests and redirects are excluded). + */ + if ((r->main != NULL)||(r->prev != NULL)) { + return DECLINED; + } + + /* Initialise transaction context and + * create the initial configuration. + */ + msr = create_tx_context(r); + if (msr == NULL) return DECLINED; + + /* Are we allowed to continue? */ + if (msr->txcfg->is_enabled == MODSEC_DISABLED) { + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Processing disabled, skipping (hook request_early)."); + } + return DECLINED; + } + + /* Process phase REQUEST_HEADERS */ + rc = DECLINED; + if (modsecurity_process_phase(msr, PHASE_REQUEST_HEADERS) > 0) { + rc = perform_interception(msr); + } + + if ( (msr->txcfg->is_enabled != MODSEC_DISABLED) + && (msr->txcfg->reqbody_access == 1) + && (rc == DECLINED)) + { + /* Check request body limit (non-chunked requests only). */ + if (msr->request_content_length > msr->txcfg->reqbody_limit) { + msr_log(msr, 1, "Request body (Content-Length) is larger than the " + "configured limit (%ld).", msr->txcfg->reqbody_limit); + return HTTP_REQUEST_ENTITY_TOO_LARGE; + } + } + + return rc; +} + +/** + * Invoked as the first hook in the handler chain, this function + * executes the second phase of ModSecurity request processing. + */ +static int hook_request_late(request_rec *r) { + char *my_error_msg = NULL; + modsec_rec *msr = NULL; + int rc; + + /* This function needs to run only once per transaction + * (i.e. subrequests and redirects are excluded). + */ + if ((r->main != NULL)||(r->prev != NULL)) { + return DECLINED; + } + + /* Find the transaction context and make sure + * we are supposed to proceed. + */ + msr = retrieve_tx_context(r); + if (msr == NULL) { + /* If we can't find the context that probably means it's + * a subrequest that was not initiated from the outside. + */ + return DECLINED; + } + + /* Has this phase been completed already? */ + if (msr->phase_request_body_complete) { + msr_log(msr, 1, "Internal Error: Attempted to process the request body more than once."); + return DECLINED; + } + msr->phase_request_body_complete = 1; + + msr->remote_user = r->user; + + /* Get the second configuration context. */ + msr->dcfg2 = (directory_config *)ap_get_module_config(r->per_dir_config, + &security2_module); + + /* Create a transaction context. */ + msr->txcfg = create_directory_config(msr->mp, NULL); + if (msr->txcfg == NULL) return DECLINED; + if (msr->dcfg2 != NULL) { + msr->txcfg = merge_directory_configs(msr->mp, msr->txcfg, msr->dcfg2); + if (msr->txcfg == NULL) return DECLINED; + } + + /* Update with the explicit user settings. */ + msr->txcfg = merge_directory_configs(msr->mp, msr->txcfg, msr->usercfg); + + init_directory_config(msr->txcfg); + + /* Perform the PDF tests now. */ + rc = pdfp_check(msr); + if (rc > 0) { + /* The PDF protection module has decided it needs to + * redirect the current transaction. So we let it do that. + */ + return rc; + } + + if (msr->txcfg->is_enabled == 0) { + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Processing disabled, skipping (hook request_late)."); + } + return DECLINED; + } + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Second phase starting (dcfg %pp).", msr->dcfg2); + } + + /* Figure out whether or not to extract multipart files. */ + if ((msr->txcfg->upload_keep_files != KEEP_FILES_OFF) /* user might want to keep them */ + || (msr->txcfg->upload_validates_files)) /* user might want to validate them */ + { + msr->upload_extract_files = 1; + msr->upload_remove_files = 1; + } + + rc = read_request_body(msr, &my_error_msg); + if (rc < 0) { + switch(rc) { + case -1 : + if (my_error_msg != NULL) { + msr_log(msr, 1, "%s", my_error_msg); + } + return HTTP_INTERNAL_SERVER_ERROR; + break; + case -4 : /* Timeout. */ + if (my_error_msg != NULL) { + msr_log(msr, 4, "%s", my_error_msg); + } + r->connection->keepalive = AP_CONN_CLOSE; + return HTTP_REQUEST_TIME_OUT; + break; + case -5 : /* Request body limit reached. */ + if (my_error_msg != NULL) { + msr_log(msr, 1, "%s", my_error_msg); + } + r->connection->keepalive = AP_CONN_CLOSE; + return HTTP_REQUEST_ENTITY_TOO_LARGE; + break; + default : + /* allow through */ + break; + } + + msr->msc_reqbody_error = 1; + msr->msc_reqbody_error_msg = my_error_msg; + } + + /* Update the request headers. They might have changed after + * the body was read (trailers). + */ + /* NOTE We still need to keep a copy of the original headers + * to log in the audit log. + */ + msr->request_headers = apr_table_copy(msr->mp, r->headers_in); + + /* Process phase REQUEST_BODY */ + record_time_checkpoint(msr, 1); + + rc = DECLINED; + if (modsecurity_process_phase(msr, PHASE_REQUEST_BODY) > 0) { + rc = perform_interception(msr); + } + + record_time_checkpoint(msr, 2); + + return rc; +} + +/** + * Invoked every time Apache has something to write to the error log. + */ +static void hook_error_log(const char *file, int line, int level, apr_status_t status, + const server_rec *s, const request_rec *r, apr_pool_t *mp, const char *fmt) +{ + modsec_rec *msr = NULL; + error_message *em = NULL; + + if (r == NULL) return; + msr = retrieve_tx_context((request_rec *)r); + + /* Create a context for requests we never had the chance to process */ + if ((msr == NULL) + && ((level & APLOG_LEVELMASK) < APLOG_DEBUG) + && apr_table_get(r->subprocess_env, "UNIQUE_ID")) + { + msr = create_tx_context((request_rec *)r); + if (msr->txcfg->debuglog_level >= 9) { + if (msr == NULL) { + msr_log(msr, 9, "Failed to create context after request failure."); + } + else { + msr_log(msr, 9, "Context created after request failure."); + } + } + } + + if (msr == NULL) return; + + /* Store the error message for later */ + em = (error_message *)apr_pcalloc(msr->mp, sizeof(error_message)); + if (em == NULL) return; + + if (file != NULL) em->file = apr_pstrdup(msr->mp, file); + em->line = line; + em->level = level; + em->status = status; + if (fmt != NULL) em->message = apr_pstrdup(msr->mp, fmt); + + /* Remove \n from the end of the message */ + if (em->message != NULL) { + char *p = (char *)em->message; + while(*p != '\0') { + if ((*(p + 1) == '\0')&&(*p == '\n')) { + *p = '\0'; + break; + } + p++; + } + } + + *(const error_message **)apr_array_push(msr->error_messages) = em; +} + +/** + * Guardian logger is used to interface to the external + * script for web server protection - httpd_guardian. + */ +static void sec_guardian_logger(request_rec *r, request_rec *origr, modsec_rec *msr) { + char *str1, *str2, *text; + char *modsec_message = "-"; + int modsec_rating = 0; /* not used yet */ + apr_size_t nbytes, nbytes_written; + apr_time_t duration = (apr_time_now() - origr->request_time); + int limit, was_limited; + + /* bail out if we do not have where to write */ + if ((guardianlog_name == NULL)||(guardianlog_fd == NULL)) return; + + /* process the condition, if we have one */ + if (guardianlog_condition != NULL) { + if (*guardianlog_condition == '!') { + if (apr_table_get(r->subprocess_env, guardianlog_condition + 1) != NULL) { + return; + } + } + else { + if (apr_table_get(r->subprocess_env, guardianlog_condition) == NULL) { + return; + } + } + } + + /* + * Log format is as follows: + * + * %V %h %l %u %t "%r" %>s %b "%{Referer}i" "%{User-agent}i" %{UNIQUE_ID}e + * "SESSION_ID" %T %D "MODSEC_MESSAGE" MODSEC_RATING + * + * The fields SESSION_ID, MODSEC_MESSAGE, and MODSEC_RATING are not used at the moment. + */ + + str2 = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT " %" APR_TIME_T_FMT " \"%s\" %d", + duration, apr_time_sec(duration), log_escape(msr->mp, modsec_message), modsec_rating); + if (str2 == NULL) return; + + /* We do not want the index line to be longer than 3980 bytes. */ + limit = 3980; + was_limited = 0; + + /* If we are logging to a pipe we need to observe and + * obey the pipe atomic write limit - PIPE_BUF. For + * more details see the discussion in sec_guardian_logger, + * above. + */ + if (msr->txcfg->auditlog_name[0] == '|') { + if (PIPE_BUF < limit) { + limit = PIPE_BUF; + } + } + + limit = limit - strlen(str2) - 5; + if (limit <= 0) { + msr_log(msr, 1, "Audit Log: Atomic PIPE write buffer too small: %d", PIPE_BUF); + return; + } + + str1 = construct_log_vcombinedus_limited(msr, limit, &was_limited); + if (str1 == NULL) return; + + if (was_limited == 0) { + text = apr_psprintf(msr->mp, "%s %s \n", str1, str2); + } else { + text = apr_psprintf(msr->mp, "%s %s L\n", str1, str2); + } + if (text == NULL) return; + + nbytes = strlen(text); + apr_file_write_full(guardianlog_fd, text, nbytes, &nbytes_written); +} + +/** + * Invoked at the end of each transaction. + */ +static int hook_log_transaction(request_rec *r) { + const apr_array_header_t *arr = NULL; + request_rec *origr = NULL; + modsec_rec *msr = NULL; + + msr = retrieve_tx_context(r); + if (msr == NULL) { + return DECLINED; + } + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Initialising logging."); + } + + /* Find the first (origr) and the last (r) request */ + origr = r; + while(origr->prev) { + origr = origr->prev; + } + while(r->next) { + r = r->next; + } + + /* At this point r is the last request in the + * chain. However, we now need to detect a case when + * a bad ErrorDocument was used and back out of it. That's + * how Apache does it internally. Except where Apache knows + * exactly what is happening we will have to rely on the missing + * headers in the final request to detect this condition. + */ + arr = apr_table_elts(r->headers_out); + while ((arr->nelts == 0)&&(r->prev != NULL)) { + r = r->prev; + arr = apr_table_elts(r->headers_out); + } + + msr->r = r; + msr->response_status = r->status; + msr->status_line = ((r->status_line != NULL) + ? r->status_line : ap_get_status_line(r->status)); + msr->response_protocol = get_response_protocol(origr); + msr->response_headers = apr_table_copy(msr->mp, r->headers_out); + if (!r->assbackwards) msr->response_headers_sent = 1; + msr->bytes_sent = r->bytes_sent; + msr->local_user = r->user; + msr->remote_user = r->connection->remote_logname; + + /* -- Guardian -- */ + + sec_guardian_logger(r, origr, msr); + + /* Invoke the engine to do the rest of the work now. */ + modsecurity_process_phase(msr, PHASE_LOGGING); + + return DECLINED; +} + +/** + * Invoked right before request processing begins. This is + * when we need to decide if we want to hook into the output + * filter chain. + */ +static void hook_insert_filter(request_rec *r) { + modsec_rec *msr = NULL; + + /* Find the transaction context first. */ + msr = retrieve_tx_context(r); + if (msr == NULL) return; + + /* Add the input filter, but only if we need it to run. */ + if (msr->if_status == IF_STATUS_WANTS_TO_RUN) { + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Hook insert_filter: Adding input forwarding filter %s(r %pp).", + (((r->main != NULL)||(r->prev != NULL)) ? "for subrequest " : ""), r); + } + + ap_add_input_filter("MODSECURITY_IN", msr, r, r->connection); + } + + /* The output filters only need to be added only once per transaction + * (i.e. subrequests and redirects are excluded). + */ + if ((r->main != NULL)||(r->prev != NULL)) { + return; + } + + /* We always add the PDF XSS protection filter. */ + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Hook insert_filter: Adding PDF XSS protection output filter (r %pp).", r); + } + + ap_add_output_filter("PDFP_OUT", msr, r, r->connection); + + /* Only proceed to add the second filter if the engine is enabled. */ + if (msr->txcfg->is_enabled == 0) { + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Hook insert_filter: Processing disabled, skipping."); + } + + return; + } + + /* We always add the output filter because that's where we need to + * initiate our 3rd and 4th processing phases from. The filter is + * smart enough not to buffer the data if it is not supposed to. + */ + if (msr->of_status != OF_STATUS_COMPLETE) { + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Hook insert_filter: Adding output filter (r %pp).", r); + } + + ap_add_output_filter("MODSECURITY_OUT", msr, r, r->connection); + } +} + +// TODO: Holding off on this for now (needs more testing) +#if 0 +/** + * Invoked whenever Apache starts processing an error. A chance + * to insert ourselves into the output filter chain. + */ +static void hook_insert_error_filter(request_rec *r) { + modsec_rec *msr = NULL; + + /* Find the transaction context and make sure we are + * supposed to proceed. + */ + msr = retrieve_tx_context(r); + if (msr == NULL) return; + + /* Do not run if not enabled. */ + if (msr->txcfg->is_enabled == 0) { + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Hook insert_error_filter: Processing disabled, skipping."); + } + return; + } + + /* Do not run if the output filter already completed. This will + * happen if we intercept in phase 4. + */ + if (msr->of_status != OF_STATUS_COMPLETE) { + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Hook insert_error_filter: Adding output filter (r %pp).", r); + } + + /* Make a note that the output we will be receiving is a + * result of error processing. + */ + msr->of_is_error = 1; + + ap_add_output_filter("MODSECURITY_OUT", msr, r, r->connection); + } else { + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Hook insert_error_filter: Output buffering already complete."); + } + } +} +#endif + +#if (!defined(NO_MODSEC_API)) +/** + * This function is exported for other Apache modules to + * register new transformation functions. + */ +static void modsec_register_tfn(const char *name, void *fn) { + if (modsecurity != NULL) { + msre_engine_tfn_register(modsecurity->msre, name, (fn_tfn_execute_t)fn); + } +} + +/** + * This function is exported for other Apache modules to + * register new operators. + */ +static void modsec_register_operator(const char *name, void *fn_init, void *fn_exec) { + if (modsecurity != NULL) { + msre_engine_op_register(modsecurity->msre, name, (fn_op_param_init_t)fn_init, (fn_op_execute_t)fn_exec); + } +} + +/** + * This function is exported for other Apache modules to + * register new variables. + */ +static void modsec_register_variable(const char *name, unsigned int type, + unsigned int argc_min, unsigned int argc_max, + void *fn_validate, void *fn_generate, + unsigned int is_cacheable, unsigned int availability) { + if (modsecurity != NULL) { + msre_engine_variable_register(modsecurity->msre, name, type, argc_min, argc_max, (fn_var_validate_t)fn_validate, (fn_var_generate_t)fn_generate, is_cacheable, availability); + } + else { + fprintf(stderr,"modsecurity is NULL\n"); + } +} +#endif + +/** + * Registers module hooks with Apache. + */ +static void register_hooks(apr_pool_t *mp) { + static const char *postconfig_beforeme_list[] = { + "mod_unique_id.c", + "mod_ssl.c", + NULL + }; + static const char *postconfig_afterme_list[] = { + "mod_fcgid.c", + "mod_cgid.c", + NULL + }; + static const char *postread_beforeme_list[] = { + "mod_rpaf.c", + "mod_rpaf-2.0.c", + "mod_extract_forwarded2.c", + "mod_custom_header.c", + "mod_breach_realip.c", + "mod_breach_trans.c", + "mod_unique_id.c", + NULL + }; + static const char *postread_afterme_list[] = { + "mod_log_forensic.c", + NULL + }; + + /* Add the MODSEC_a.b define */ + *(char **)apr_array_push(ap_server_config_defines) = apr_psprintf(mp, "MODSEC_%s.%s", MODSEC_VERSION_MAJOR, MODSEC_VERSION_MINOR); + +#if (!defined(NO_MODSEC_API)) + /* Export optional functions. */ + APR_REGISTER_OPTIONAL_FN(modsec_register_tfn); + APR_REGISTER_OPTIONAL_FN(modsec_register_operator); + APR_REGISTER_OPTIONAL_FN(modsec_register_variable); +#endif + + /* Main hooks */ + ap_hook_pre_config(hook_pre_config, NULL, NULL, APR_HOOK_FIRST); + ap_hook_post_config(hook_post_config, postconfig_beforeme_list, + postconfig_afterme_list, APR_HOOK_REALLY_LAST); + ap_hook_child_init(hook_child_init, NULL, NULL, APR_HOOK_MIDDLE); + + /* Our own hook to handle RPC transactions (not used at the moment). + * // ap_hook_handler(hook_handler, NULL, NULL, APR_HOOK_MIDDLE); + */ + + /* Transaction processing hooks */ + ap_hook_post_read_request(hook_request_early, + postread_beforeme_list, postread_afterme_list, APR_HOOK_REALLY_FIRST); + + ap_hook_fixups(hook_request_late, NULL, NULL, APR_HOOK_REALLY_FIRST); + + /* Logging */ + ap_hook_error_log(hook_error_log, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_log_transaction(hook_log_transaction, NULL, NULL, APR_HOOK_MIDDLE); + + /* Filter hooks */ + ap_hook_insert_filter(hook_insert_filter, NULL, NULL, APR_HOOK_FIRST); +#if 0 + ap_hook_insert_error_filter(hook_insert_error_filter, NULL, NULL, APR_HOOK_FIRST); +#endif + + ap_register_input_filter("MODSECURITY_IN", input_filter, + NULL, AP_FTYPE_CONTENT_SET); + + /* Ensure that the output filter runs before other modules so that + * we get a request that has a better chance of not being modified: + * + * Currently: + * mod_expires = -2 + * mod_cache = -1 + * mod_deflate = -1 + * mod_headers = 0 + */ + ap_register_output_filter("MODSECURITY_OUT", output_filter, + NULL, AP_FTYPE_CONTENT_SET - 3); + + ap_register_output_filter("PDFP_OUT", pdfp_output_filter, + NULL, AP_FTYPE_CONTENT_SET); +} + +/* Defined in apache2_config.c */ +extern const command_rec module_directives[]; + +/* Module entry points */ +module AP_MODULE_DECLARE_DATA security2_module = { + STANDARD20_MODULE_STUFF, + create_directory_config, + merge_directory_configs, + NULL, /* create_server_config */ + NULL, /* merge_server_configs */ + module_directives, + register_hooks +}; diff --git a/apache2/mod_security2_config.h.in b/apache2/mod_security2_config.h.in new file mode 100644 index 0000000..6e740e0 --- /dev/null +++ b/apache2/mod_security2_config.h.in @@ -0,0 +1,139 @@ +/* mod_security2_config.h.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if you have the `atexit' function. */ +#undef HAVE_ATEXIT + +/* Define to 1 if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define to 1 if you have the `getcwd' function. */ +#undef HAVE_GETCWD + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIMITS_H + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#undef HAVE_MALLOC + +/* Define to 1 if you have the `memmove' function. */ +#undef HAVE_MEMMOVE + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `memset' function. */ +#undef HAVE_MEMSET + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the `strcasecmp' function. */ +#undef HAVE_STRCASECMP + +/* Define to 1 if you have the `strchr' function. */ +#undef HAVE_STRCHR + +/* Define to 1 if you have the `strdup' function. */ +#undef HAVE_STRDUP + +/* Define to 1 if you have the `strerror' function. */ +#undef HAVE_STRERROR + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `strncasecmp' function. */ +#undef HAVE_STRNCASECMP + +/* Define to 1 if you have the `strrchr' function. */ +#undef HAVE_STRRCHR + +/* Define to 1 if you have the `strstr' function. */ +#undef HAVE_STRSTR + +/* Define to 1 if you have the `strtol' function. */ +#undef HAVE_STRTOL + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define to 1 if your declares `struct tm'. */ +#undef TM_IN_SYS_TIME + +/* Define for Solaris 2.5.1 so the uint8_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +#undef _UINT8_T + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +#undef inline +#endif + +/* Define to rpl_malloc if the replacement function should be used. */ +#undef malloc + +/* Define to `int' if does not define. */ +#undef pid_t + +/* Define to the equivalent of the C99 'restrict' keyword, or to + nothing if this is not supported. Do not define if restrict is + supported directly. */ +#undef restrict +/* Work around a bug in Sun C++: it does not support _Restrict or + __restrict__, even though the corresponding Sun C compiler ends up with + "#define restrict _Restrict" or "#define restrict __restrict__" in the + previous line. Perhaps some future version of Sun C++ will work with + restrict; if so, hopefully it defines __RESTRICT like Sun C does. */ +#if defined __SUNPRO_CC && !defined __RESTRICT +# define _Restrict +# define __restrict__ +#endif + +/* Define to `unsigned int' if does not define. */ +#undef size_t + +/* Define to the type of an unsigned integer type of width exactly 8 bits if + such a type exists and the standard includes do not define it. */ +#undef uint8_t diff --git a/apache2/mod_security2_config.hw b/apache2/mod_security2_config.hw new file mode 100644 index 0000000..c950044 --- /dev/null +++ b/apache2/mod_security2_config.hw @@ -0,0 +1 @@ +/* This file is left empty for building on Windows. */ diff --git a/apache2/modsecurity.c b/apache2/modsecurity.c new file mode 100644 index 0000000..9655783 --- /dev/null +++ b/apache2/modsecurity.c @@ -0,0 +1,609 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ +#include + +#include "apr_global_mutex.h" + +#include "modsecurity.h" +#include "msc_parsers.h" +#include "msc_util.h" +#include "msc_xml.h" + +/** + * Format an alert message. + */ +const char * msc_alert_message(modsec_rec *msr, msre_actionset *actionset, const char *action_message, + const char *rule_message) +{ + const char *message = NULL; + + if (rule_message == NULL) rule_message = "Unknown error."; + + if (action_message == NULL) { + message = apr_psprintf(msr->mp, "%s%s", + rule_message, msre_format_metadata(msr, actionset)); + } + else { + message = apr_psprintf(msr->mp, "%s %s%s", action_message, + rule_message, msre_format_metadata(msr, actionset)); + } + + return message; +} + +/** + * Log an alert message to the log, adding the rule metadata at the end. + */ +void msc_alert(modsec_rec *msr, int level, msre_actionset *actionset, const char *action_message, + const char *rule_message) +{ + const char *message = msc_alert_message(msr, actionset, action_message, rule_message); + + msr_log(msr, level, "%s", message); +} + +#if 0 +/** + * Return phase name associated with the given phase number. + */ +static const char *phase_name(int phase) { + switch(phase) { + case 1 : + return "REQUEST_HEADERS"; + break; + case 2 : + return "REQUEST_BODY"; + break; + case 3 : + return "RESPONSE_HEADERS"; + break; + case 4 : + return "RESPONSE_BODY"; + break; + case 5 : + return "LOGGING"; + break; + } + return "INVALID"; +} +#endif + +/** + * Creates and initialises a ModSecurity engine instance. + */ +msc_engine *modsecurity_create(apr_pool_t *mp, int processing_mode) { + msc_engine *msce = NULL; + + msce = apr_pcalloc(mp, sizeof(msc_engine)); + if (msce == NULL) return NULL; + + msce->mp = mp; + msce->processing_mode = processing_mode; + + msce->msre = msre_engine_create(msce->mp); + if (msce->msre == NULL) return NULL; + msre_engine_register_default_variables(msce->msre); + msre_engine_register_default_operators(msce->msre); + msre_engine_register_default_tfns(msce->msre); + msre_engine_register_default_actions(msce->msre); + + return msce; +} + +/** + * Initialise the modsecurity engine. This function must be invoked + * after configuration processing is complete as Apache needs to know the + * username it is running as. + */ +int modsecurity_init(msc_engine *msce, apr_pool_t *mp) { + apr_status_t rc; + + /* Serial audit log mutext */ + rc = apr_global_mutex_create(&msce->auditlog_lock, NULL, APR_LOCK_DEFAULT, mp); + if (rc != APR_SUCCESS) { + //ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, "mod_security: Could not create modsec_auditlog_lock"); + //return HTTP_INTERNAL_SERVER_ERROR; + return -1; + } + + #ifdef __SET_MUTEX_PERMS + rc = unixd_set_global_mutex_perms(msce->auditlog_lock); + if (rc != APR_SUCCESS) { + // ap_log_error(APLOG_MARK, APLOG_ERR, rc, s, "mod_security: Could not set permissions on modsec_auditlog_lock; check User and Group directives"); + // return HTTP_INTERNAL_SERVER_ERROR; + return -1; + } + #endif + + return 1; +} + +/** + * Performs per-child (new process) initialisation. + */ +void modsecurity_child_init(msc_engine *msce) { + /* Need to call this once per process before any other XML calls. */ + xmlInitParser(); + + if (msce->auditlog_lock != NULL) { + apr_status_t rc = apr_global_mutex_child_init(&msce->auditlog_lock, NULL, msce->mp); + if (rc != APR_SUCCESS) { + // ap_log_error(APLOG_MARK, APLOG_ERR, rs, s, "Failed to child-init auditlog mutex"); + } + } +} + +/** + * Releases resources held by engine instance. + */ +void modsecurity_shutdown(msc_engine *msce) { + if (msce == NULL) return; +} + +/** + * + */ +static apr_status_t modsecurity_tx_cleanup(void *data) { + modsec_rec *msr = (modsec_rec *)data; + const apr_array_header_t *arr; + apr_table_entry_t *te; + int collect_garbage = 0; + int i; + char *my_error_msg = NULL; + + if (msr == NULL) return APR_SUCCESS; + + if (rand() < RAND_MAX/100) { + collect_garbage = 1; + } + + /* Collections, store & remove stale. */ + arr = apr_table_elts(msr->collections); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + apr_table_t *col = (apr_table_t *)te[i].val; + + /* Only store those collections that changed. */ + if (apr_table_get(msr->collections_dirty, te[i].key)) { + collection_store(msr, col); + } + + if (collect_garbage) { + collections_remove_stale(msr, te[i].key); + } + } + + /* Multipart processor cleanup. */ + if (msr->mpd != NULL) multipart_cleanup(msr); + + /* XML processor cleanup. */ + if (msr->xml != NULL) xml_cleanup(msr); + + // TODO: Why do we ignore return code here? + modsecurity_request_body_clear(msr, &my_error_msg); + if (my_error_msg != NULL) { + msr_log(msr, 1, "%s", my_error_msg); + } + + return APR_SUCCESS; +} + +/** + * + */ +apr_status_t modsecurity_tx_init(modsec_rec *msr) { + const char *s = NULL; + const apr_array_header_t *arr; + apr_table_entry_t *te; + int i; + + /* Register TX cleanup */ + apr_pool_cleanup_register(msr->mp, msr, modsecurity_tx_cleanup, apr_pool_cleanup_null); + + /* Initialise C-L */ + msr->request_content_length = -1; + s = apr_table_get(msr->request_headers, "Content-Length"); + if (s != NULL) { + msr->request_content_length = strtol(s, NULL, 10); + } + + /* Figure out whether this request has a body */ + msr->reqbody_chunked = 0; + msr->reqbody_should_exist = 0; + if (msr->request_content_length == -1) { + /* There's no C-L, but is chunked encoding used? */ + char *transfer_encoding = (char *)apr_table_get(msr->request_headers, "Transfer-Encoding"); + if ((transfer_encoding != NULL)&&(strstr(transfer_encoding, "chunked") != NULL)) { + msr->reqbody_should_exist = 1; + msr->reqbody_chunked = 1; + } + } else { + /* C-L found */ + msr->reqbody_should_exist = 1; + } + + /* Initialise C-T */ + msr->request_content_type = NULL; + s = apr_table_get(msr->request_headers, "Content-Type"); + if (s != NULL) msr->request_content_type = s; + + /* Decide what to do with the request body. */ + if ((msr->request_content_type != NULL) + && (strncasecmp(msr->request_content_type, "application/x-www-form-urlencoded", 33) == 0)) + { + /* Always place POST requests with + * "application/x-www-form-urlencoded" payloads in memory. + */ + msr->msc_reqbody_storage = MSC_REQBODY_MEMORY; + msr->msc_reqbody_spilltodisk = 0; + msr->msc_reqbody_processor = "URLENCODED"; + } else { + /* If the C-L is known and there's more data than + * our limit go to disk straight away. + */ + if ((msr->request_content_length != -1) + && (msr->request_content_length > msr->txcfg->reqbody_inmemory_limit)) + { + msr->msc_reqbody_storage = MSC_REQBODY_DISK; + } + + /* In all other cases, try using the memory first + * but switch over to disk for larger bodies. + */ + msr->msc_reqbody_storage = MSC_REQBODY_MEMORY; + msr->msc_reqbody_spilltodisk = 1; + + if (msr->request_content_type != NULL) { + if (strncasecmp(msr->request_content_type, "multipart/form-data", 19) == 0) { + msr->msc_reqbody_processor = "MULTIPART"; + } + } + } + + /* Check if we are forcing buffering, then use memory only. */ + if (msr->txcfg->reqbody_buffering != REQUEST_BODY_FORCEBUF_OFF) { + msr->msc_reqbody_storage = MSC_REQBODY_MEMORY; + msr->msc_reqbody_spilltodisk = 0; + } + + /* Initialise arguments */ + msr->arguments = apr_table_make(msr->mp, 32); + if (msr->arguments == NULL) return -1; + if (msr->query_string != NULL) { + int invalid_count = 0; + + if (parse_arguments(msr, msr->query_string, strlen(msr->query_string), + msr->txcfg->argument_separator, "QUERY_STRING", msr->arguments, + &invalid_count) < 0) + { + msr_log(msr, 1, "Initialisation: Error occurred while parsing QUERY_STRING arguments."); + return -1; + } + } + + msr->arguments_to_sanitise = apr_table_make(msr->mp, 16); + if (msr->arguments_to_sanitise == NULL) return -1; + msr->request_headers_to_sanitise = apr_table_make(msr->mp, 16); + if (msr->request_headers_to_sanitise == NULL) return -1; + msr->response_headers_to_sanitise = apr_table_make(msr->mp, 16); + if (msr->response_headers_to_sanitise == NULL) return -1; + + /* Initialise cookies */ + msr->request_cookies = apr_table_make(msr->mp, 16); + if (msr->request_cookies == NULL) return -1; + + /* Locate the cookie headers and parse them */ + arr = apr_table_elts(msr->request_headers); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + if (strcasecmp(te[i].key, "Cookie") == 0) { + if (msr->txcfg->cookie_format == COOKIES_V0) { + parse_cookies_v0(msr, te[i].val, msr->request_cookies); + } else { + parse_cookies_v1(msr, te[i].val, msr->request_cookies); + } + } + } + + /* Collections. */ + msr->tx_vars = apr_table_make(msr->mp, 32); + if (msr->tx_vars == NULL) return -1; + + msr->geo_vars = apr_table_make(msr->mp, 8); + if (msr->geo_vars == NULL) return -1; + + msr->collections_original = apr_table_make(msr->mp, 8); + if (msr->collections_original == NULL) return -1; + msr->collections = apr_table_make(msr->mp, 8); + if (msr->collections == NULL) return -1; + msr->collections_dirty = apr_table_make(msr->mp, 8); + if (msr->collections_dirty == NULL) return -1; + + /* Other */ + msr->tcache = NULL; + msr->tcache_items = 0; + + msr->matched_rules = apr_array_make(msr->mp, 16, sizeof(void *)); + if (msr->matched_rules == NULL) return -1; + + msr->matched_var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + if (msr->matched_var == NULL) return -1; + + msr->highest_severity = 255; /* high, invalid value */ + + msr->removed_rules = apr_array_make(msr->mp, 16, sizeof(char *)); + if (msr->removed_rules == NULL) return -1; + + return 1; +} + +/** + * + */ +static int is_response_status_relevant(modsec_rec *msr, int status) { + char *my_error_msg = NULL; + apr_status_t rc; + char buf[32]; + + /* ENH: Setting is_relevant here will cause an audit even if noauditlog + * was set for the last rule that matched. Is this what we want? + */ + + if ((msr->txcfg->auditlog_relevant_regex == NULL) + ||(msr->txcfg->auditlog_relevant_regex == NOT_SET_P)) + { + return 0; + } + + apr_snprintf(buf, sizeof(buf), "%d", status); + + rc = msc_regexec(msr->txcfg->auditlog_relevant_regex, buf, strlen(buf), &my_error_msg); + if (rc >= 0) return 1; + if (rc == PCRE_ERROR_NOMATCH) return 0; + + msr_log(msr, 1, "Regex processing failed (rc %d): %s", rc, my_error_msg); + return 0; +} + +/** + * + */ +static apr_status_t modsecurity_process_phase_request_headers(modsec_rec *msr) { + msr_log(msr, 4, "Starting phase REQUEST_HEADERS."); + + if (msr->txcfg->ruleset != NULL) { + return msre_ruleset_process_phase(msr->txcfg->ruleset, msr); + } + + return 0; +} + +/** + * + */ +static apr_status_t modsecurity_process_phase_request_body(modsec_rec *msr) { + if ((msr->allow_scope == ACTION_ALLOW_REQUEST)||(msr->allow_scope == ACTION_ALLOW)) { + msr_log(msr, 4, "Skipping phase REQUEST_BODY (allow used)."); + return 0; + } else { + msr_log(msr, 4, "Starting phase REQUEST_BODY."); + } + + if (msr->txcfg->ruleset != NULL) { + return msre_ruleset_process_phase(msr->txcfg->ruleset, msr); + } + + return 0; +} + +/** + * + */ +static apr_status_t modsecurity_process_phase_response_headers(modsec_rec *msr) { + if (msr->allow_scope == ACTION_ALLOW) { + msr_log(msr, 4, "Skipping phase RESPONSE_HEADERS (allow used)."); + return 0; + } else { + msr_log(msr, 4, "Starting phase RESPONSE_HEADERS."); + } + + if (msr->txcfg->ruleset != NULL) { + return msre_ruleset_process_phase(msr->txcfg->ruleset, msr); + } + + return 0; +} + +/** + * + */ +static apr_status_t modsecurity_process_phase_response_body(modsec_rec *msr) { + if (msr->allow_scope == ACTION_ALLOW) { + msr_log(msr, 4, "Skipping phase RESPONSE_BODY (allow used)."); + return 0; + } else { + msr_log(msr, 4, "Starting phase RESPONSE_BODY."); + } + + if (msr->txcfg->ruleset != NULL) { + return msre_ruleset_process_phase(msr->txcfg->ruleset, msr); + } + + return 0; +} + +/** + * + */ +static apr_status_t modsecurity_process_phase_logging(modsec_rec *msr) { + msr_log(msr, 4, "Starting phase LOGGING."); + + if (msr->txcfg->ruleset != NULL) { + msre_ruleset_process_phase(msr->txcfg->ruleset, msr); + } + + /* Is this request relevant for logging purposes? */ + if (msr->is_relevant == 0) { + /* Check the status */ + msr->is_relevant += is_response_status_relevant(msr, msr->r->status); + + /* If we processed two requests and statuses are different then + * check the other status too. + */ + if (msr->r_early->status != msr->r->status) { + msr->is_relevant += is_response_status_relevant(msr, msr->r_early->status); + } + } + + /* Figure out if we want to keep the files (if there are any, of course). */ + if ((msr->txcfg->upload_keep_files == KEEP_FILES_ON) + || ((msr->txcfg->upload_keep_files == KEEP_FILES_RELEVANT_ONLY)&&(msr->is_relevant))) + { + msr->upload_remove_files = 0; + } else { + msr->upload_remove_files = 1; + } + + /* Are we configured for audit logging? */ + switch(msr->txcfg->auditlog_flag) { + case AUDITLOG_OFF : + msr_log(msr, 4, "Audit log: Not configured to run for this request."); + return DECLINED; + break; + + case AUDITLOG_RELEVANT : + if (msr->is_relevant == 0) { + msr_log(msr, 4, "Audit log: Ignoring a non-relevant request."); + return DECLINED; + } + break; + + case AUDITLOG_ON : + /* All right, do nothing */ + break; + + default : + msr_log(msr, 1, "Internal error: Could not determine if auditing is needed, so forcing auditing."); + break; + } + + /* Invoke the Audit logger */ + msr_log(msr, 4, "Audit log: Logging this transaction."); + + sec_audit_logger(msr); + + return 0; +} + +/** + * Processes one transaction phase. The phase number does not + * need to be explicitly provided since it's already available + * in the modsec_rec structure. + */ +apr_status_t modsecurity_process_phase(modsec_rec *msr, unsigned int phase) { + /* Check if we should run. */ + if ((msr->was_intercepted)&&(phase != PHASE_LOGGING)) { + msr_log(msr, 4, "Skipping phase %d as request was already intercepted.", phase); + return 0; + } + + /* Do not process the same phase twice. */ + if (msr->phase >= phase) { + msr_log(msr, 4, "Skipping phase %d because it was previously run (at %d now).", + phase, msr->phase); + return 0; + } + + msr->phase = phase; + + /* Clear out the transformation cache at the start of each phase */ + if (msr->txcfg->cache_trans == MODSEC_CACHE_ENABLED) { + if (msr->tcache) { + apr_hash_index_t *hi; + void *dummy; + apr_table_t *tab; + const void *key; + apr_ssize_t klen; + #ifdef CACHE_DEBUG + apr_pool_t *mp = msr->msc_rule_mptmp; + const apr_array_header_t *ctarr; + const apr_table_entry_t *ctelts; + msre_cache_rec *rec; + int cn = 0; + int ri; + #else + apr_pool_t *mp = msr->mp; + #endif + + for (hi = apr_hash_first(mp, msr->tcache); hi; hi = apr_hash_next(hi)) { + apr_hash_this(hi, &key, &klen, &dummy); + tab = (apr_table_t *)dummy; + + if (tab == NULL) continue; + + #ifdef CACHE_DEBUG + /* Dump the cache out as we clear */ + ctarr = apr_table_elts(tab); + ctelts = (const apr_table_entry_t*)ctarr->elts; + for (ri = 0; ri < ctarr->nelts; ri++) { + cn++; + rec = (msre_cache_rec *)ctelts[ri].val; + if (rec->changed) { + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "CACHE: %5d) hits=%d key=%pp %x;%s=\"%s\" (%pp - %pp)", cn, rec->hits, key, rec->num, rec->path, log_escape_nq_ex(mp, rec->val, rec->val_len), rec->val, rec->val + rec->val_len); + } + } + else { + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "CACHE: %5d) hits=%d key=%pp %x;%s=", cn, rec->hits, key, rec->num, rec->path); + } + } + } + #endif + + apr_table_clear(tab); + apr_hash_set(msr->tcache, key, klen, NULL); + } + + msr_log(msr, 9, "Cleared transformation cache for phase %d", msr->phase); + } + + msr->tcache_items = 0; + msr->tcache = apr_hash_make(msr->mp); + if (msr->tcache == NULL) return -1; + } + + switch(phase) { + case 1 : + return modsecurity_process_phase_request_headers(msr); + case 2 : + return modsecurity_process_phase_request_body(msr); + case 3 : + return modsecurity_process_phase_response_headers(msr); + case 4 : + return modsecurity_process_phase_response_body(msr); + case 5 : + return modsecurity_process_phase_logging(msr); + default : + msr_log(msr, 1, "Invalid processing phase: %d", msr->phase); + break; + } + + return -1; +} diff --git a/apache2/modsecurity.h b/apache2/modsecurity.h new file mode 100644 index 0000000..3c3e3ce --- /dev/null +++ b/apache2/modsecurity.h @@ -0,0 +1,563 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ +#ifndef _MODSECURITY_H_ +#define _MODSECURITY_H_ + +#include +#include +#include + +typedef struct rule_exception rule_exception; +typedef struct modsec_rec modsec_rec; +typedef struct directory_config directory_config; +typedef struct error_message error_message; +typedef struct msc_engine msc_engine; +typedef struct msc_data_chunk msc_data_chunk; +typedef struct msc_arg msc_arg; +typedef struct msc_string msc_string; + +#include "msc_release.h" +#include "msc_logging.h" +#include "msc_multipart.h" +#include "msc_pcre.h" +#include "msc_util.h" +#include "msc_xml.h" +#include "msc_geo.h" +#include "re.h" + +#include "ap_config.h" +#include "apr_md5.h" +#include "apr_strings.h" +#include "apr_hash.h" +#include "httpd.h" +#include "http_config.h" +#include "http_log.h" +#include "http_protocol.h" + +#define PHASE_REQUEST_HEADERS 1 +#define PHASE_REQUEST_BODY 2 +#define PHASE_RESPONSE_HEADERS 3 +#define PHASE_RESPONSE_BODY 4 +#define PHASE_LOGGING 5 +#define PHASE_FIRST PHASE_REQUEST_HEADERS +#define PHASE_LAST PHASE_LOGGING + +#define NOT_SET -1l +#define NOT_SET_P ((void *)-1l) + +#define CREATEMODE ( APR_UREAD | APR_UWRITE | APR_GREAD ) +#define CREATEMODE_DIR ( APR_UREAD | APR_UWRITE | APR_UEXECUTE | APR_GREAD | APR_GEXECUTE ) + +#if defined(NETWARE) +#define CREATEMODE_UNISTD ( S_IREAD | S_IWRITE ) +#elif defined(WIN32) +#define CREATEMODE_UNISTD ( _S_IREAD | _S_IWRITE ) +#else +#define CREATEMODE_UNISTD ( S_IRUSR | S_IWUSR | S_IRGRP ) +#endif + +#if !defined(O_BINARY) +#define O_BINARY (0) +#endif + +#ifndef PIPE_BUF +#define PIPE_BUF (512) +#endif + +#define REQUEST_BODY_HARD_LIMIT 1073741824L +#define REQUEST_BODY_DEFAULT_INMEMORY_LIMIT 131072 +#define REQUEST_BODY_DEFAULT_LIMIT 134217728 +#define REQUEST_BODY_NO_FILES_DEFAULT_LIMIT 1048576 +#define RESPONSE_BODY_DEFAULT_LIMIT 524288 +#define RESPONSE_BODY_HARD_LIMIT 1073741824L + +#define RESPONSE_BODY_LIMIT_ACTION_REJECT 0 +#define RESPONSE_BODY_LIMIT_ACTION_PARTIAL 1 + +#define REQUEST_BODY_FORCEBUF_OFF 0 +#define REQUEST_BODY_FORCEBUF_ON 1 + +#define SECACTION_TARGETS "REQUEST_URI" +#define SECACTION_ARGS "@unconditionalMatch" + +#define SECMARKER_TARGETS "REQUEST_URI" +#define SECMARKER_ARGS "@noMatch" +#define SECMARKER_BASE_ACTIONS "t:none,pass,id:" + +#if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE) +#include "unixd.h" +#define __SET_MUTEX_PERMS +#endif + +#define COOKIES_V0 0 +#define COOKIES_V1 1 + +#ifdef WIN32 +#include +#else +#include +#include +#endif + +#define NOTE_MSR "modsecurity-tx-context" + +#define FATAL_ERROR "ModSecurity: Fatal error (memory allocation or unexpected internal error)!" + +extern DSOLOCAL char *new_server_signature; +extern DSOLOCAL char *real_server_signature; +extern DSOLOCAL char *chroot_dir; + +extern module AP_MODULE_DECLARE_DATA security2_module; + +extern DSOLOCAL const command_rec module_directives[]; + +#define RESBODY_STATUS_NOT_READ 0 /* we were not configured to read the body */ +#define RESBODY_STATUS_ERROR 1 /* error occured while we were reading the body */ +#define RESBODY_STATUS_PARTIAL 2 /* partial body content available in the brigade */ +#define RESBODY_STATUS_READ_BRIGADE 3 /* body was read but not flattened */ +#define RESBODY_STATUS_READ 4 /* body was read and flattened */ + +#define IF_STATUS_NONE 0 +#define IF_STATUS_WANTS_TO_RUN 1 +#define IF_STATUS_COMPLETE 2 + +#define OF_STATUS_NOT_STARTED 0 +#define OF_STATUS_IN_PROGRESS 1 +#define OF_STATUS_COMPLETE 2 + +#define MSC_REQBODY_NONE 0 +#define MSC_REQBODY_MEMORY 1 +#define MSC_REQBODY_DISK 2 + +#define ACTION_NONE 0 +#define ACTION_DENY 1 +#define ACTION_REDIRECT 2 +#define ACTION_PROXY 3 +#define ACTION_DROP 4 +#define ACTION_ALLOW 5 +#define ACTION_ALLOW_REQUEST 6 +#define ACTION_ALLOW_PHASE 7 + +#define MODSEC_DISABLED 0 +#define MODSEC_DETECTION_ONLY 1 +#define MODSEC_ENABLED 2 + +#define MODSEC_CACHE_DISABLED 0 +#define MODSEC_CACHE_ENABLED 1 + +#define MODSEC_OFFLINE 0 +#define MODSEC_ONLINE 1 + +#define REGEX_CAPTURE_BUFLEN 1024 + +#define KEEP_FILES_OFF 0 +#define KEEP_FILES_ON 1 +#define KEEP_FILES_RELEVANT_ONLY 2 + +#define RULE_EXCEPTION_IMPORT_ID 1 +#define RULE_EXCEPTION_IMPORT_MSG 2 +#define RULE_EXCEPTION_REMOVE_ID 3 +#define RULE_EXCEPTION_REMOVE_MSG 4 + +#define NBSP 160 + +struct rule_exception { + int type; + const char *param; + void *param_data; +}; + +struct modsec_rec { + apr_pool_t *mp; + msc_engine *modsecurity; + + request_rec *r_early; + request_rec *r; + directory_config *dcfg1; + directory_config *dcfg2; + directory_config *usercfg; + directory_config *txcfg; + + unsigned int reqbody_should_exist; + unsigned int reqbody_chunked; + + unsigned int phase; + unsigned int phase_request_headers_complete; + unsigned int phase_request_body_complete; + + apr_bucket_brigade *if_brigade; + unsigned int if_status; + unsigned int if_started_forwarding; + + apr_size_t reqbody_length; + + apr_bucket_brigade *of_brigade; + unsigned int of_status; + unsigned int of_done_reading; + unsigned int of_skipping; + unsigned int of_partial; + unsigned int of_is_error; + + unsigned int resbody_status; + apr_size_t resbody_length; + char *resbody_data; + unsigned int resbody_contains_html; + + apr_array_header_t *error_messages; + apr_array_header_t *alerts; + + const char *txid; + const char *sessionid; + const char *userid; + + const char *server_software; + const char *local_addr; + unsigned int local_port; + const char *local_user; + + /* client */ + + const char *remote_addr; + unsigned int remote_port; + const char *remote_user; + + /* request */ + + const char *request_line; + const char *request_method; + const char *request_uri; + const char *query_string; + const char *request_protocol; + + const char *hostname; + + apr_table_t *request_headers; + + apr_off_t request_content_length; + const char *request_content_type; + + apr_table_t *arguments; + apr_table_t *arguments_to_sanitise; + apr_table_t *request_headers_to_sanitise; + apr_table_t *response_headers_to_sanitise; + apr_table_t *request_cookies; + + unsigned int is_relevant; + + apr_table_t *tx_vars; + + /* ENH: refactor to allow arbitrary var tables */ + apr_table_t *geo_vars; + + /* response */ + unsigned int response_status; + const char *status_line; + const char *response_protocol; + apr_table_t *response_headers; + unsigned int response_headers_sent; + apr_off_t bytes_sent; + + /* modsecurity request body processing stuff */ + + unsigned int msc_reqbody_storage; /* on disk or in memory */ + unsigned int msc_reqbody_spilltodisk; + unsigned int msc_reqbody_read; + + apr_pool_t *msc_reqbody_mp; /* this is where chunks are allocated from */ + apr_array_header_t *msc_reqbody_chunks; /* data chunks when stored in memory */ + unsigned int msc_reqbody_length; /* the amount of data received */ + int msc_reqbody_chunk_position; /* used when retrieving the body */ + unsigned int msc_reqbody_chunk_offset; /* offset of the chunk currently in use */ + msc_data_chunk *msc_reqbody_chunk_current; /* current chunk */ + char *msc_reqbody_buffer; + + const char *msc_reqbody_filename; /* when stored on disk */ + int msc_reqbody_fd; + msc_data_chunk *msc_reqbody_disk_chunk; + + const char *msc_reqbody_processor; + int msc_reqbody_error; + const char *msc_reqbody_error_msg; + + apr_size_t msc_reqbody_no_files_length; + + multipart_data *mpd; /* MULTIPART processor data structure */ + + xml_data *xml; /* XML processor data structure */ + + /* audit logging */ + char *new_auditlog_boundary; + char *new_auditlog_filename; + apr_file_t *new_auditlog_fd; + unsigned int new_auditlog_size; + apr_md5_ctx_t new_auditlog_md5ctx; + + unsigned int was_intercepted; + unsigned int rule_was_intercepted; + unsigned int intercept_phase; + msre_actionset *intercept_actionset; + const char *intercept_message; + + /* performance measurement */ + apr_time_t request_time; + apr_time_t time_checkpoint_1; + apr_time_t time_checkpoint_2; + apr_time_t time_checkpoint_3; + + apr_array_header_t *matched_rules; + msc_string *matched_var; + int highest_severity; + + /* upload */ + int upload_extract_files; + int upload_remove_files; + + /* other */ + apr_table_t *collections_original; + apr_table_t *collections; + apr_table_t *collections_dirty; + + /* rule processing temp pool */ + apr_pool_t *msc_rule_mptmp; + + /* content injection */ + const char *content_prepend; + apr_off_t content_prepend_len; + const char *content_append; + apr_off_t content_append_len; + + /* data cache */ + apr_hash_t *tcache; + apr_size_t tcache_items; + + /* removed rules */ + apr_array_header_t *removed_rules; + + /* When "allow" is executed the variable below is + * updated to contain the scope of the allow action. Set + * at 0 by default, it will have ACTION_ALLOW if we are + * to allow phases 1-4 and ACTION_ALLOW_REQUEST if we + * are to allow phases 1-2 only. + */ + unsigned int allow_scope; +}; + +struct directory_config { + apr_pool_t *mp; + + msre_ruleset *ruleset; + + int is_enabled; + int reqbody_access; + int reqbody_buffering; + long int reqbody_inmemory_limit; + long int reqbody_limit; + long int reqbody_no_files_limit; + int resbody_access; + + long int of_limit; + apr_table_t *of_mime_types; + int of_mime_types_cleared; + int of_limit_action; + + const char *debuglog_name; + int debuglog_level; + apr_file_t *debuglog_fd; + + int cookie_format; + int argument_separator; + + int rule_inheritance; + apr_array_header_t *rule_exceptions; + + + /* -- Audit log -- */ + + /* Whether audit log should be enabled in the context or not */ + int auditlog_flag; + + /* AUDITLOG_SERIAL (single file) or AUDITLOG_CONCURRENT (multiple files) */ + int auditlog_type; + + /* Mode for audit log directories and files */ + apr_fileperms_t auditlog_dirperms; + apr_fileperms_t auditlog_fileperms; + + /* The name of the audit log file (for the old type), or the + * name of the index file (for the new audit log type) + */ + char *auditlog_name; + /* The name of the secondary index file */ + char *auditlog2_name; + + /* The file descriptors for the files above */ + apr_file_t *auditlog_fd; + apr_file_t *auditlog2_fd; + + /* For the new-style audit log only, the path where + * audit log entries will be stored + */ + char *auditlog_storage_dir; + + /* A list of parts to include in the new-style audit log + * entry. By default, it contains 'ABCFHZ'. Have a look at + * the AUDITLOG_PART_* constants above to decipher the + * meaning. + */ + char *auditlog_parts; + + /* A regular expression that determines if a response + * status is treated as relevant. + */ + msc_regex_t *auditlog_relevant_regex; + + /* Upload */ + const char *tmp_dir; + const char *upload_dir; + int upload_keep_files; + int upload_validates_files; + int upload_filemode; /* int only so NOT_SET works */ + + /* Used only in the configuration phase. */ + msre_rule *tmp_chain_starter; + msre_actionset *tmp_default_actionset; + apr_table_t *tmp_rule_placeholders; + + /* Misc */ + const char *data_dir; + const char *webappid; + + /* Content injection. */ + int content_injection_enabled; + + /* PDF XSS Protection. */ + int pdfp_enabled; + const char *pdfp_secret; + int pdfp_timeout; + const char *pdfp_token_name; + int pdfp_only_get; + int pdfp_method; + + /* Geo Lookup */ + geo_db *geo; + + /* Cache */ + int cache_trans; + int cache_trans_incremental; + apr_size_t cache_trans_min; + apr_size_t cache_trans_max; + apr_size_t cache_trans_maxitems; + + /* Array to hold signatures of components, which will + * appear in the ModSecurity signature in the audit log. + */ + apr_array_header_t *component_signatures; + + /* Request character encoding. */ + const char *request_encoding; +}; + +struct error_message { + const char *file; + int line; + int level; + apr_status_t status; + const char *message; +}; + +struct msc_engine { + apr_pool_t *mp; + apr_global_mutex_t *auditlog_lock; + msre_engine *msre; + unsigned int processing_mode; +}; + +struct msc_data_chunk { + char *data; + apr_size_t length; + unsigned int is_permanent; +}; + +struct msc_arg { + const char *name; + unsigned int name_len; + unsigned int name_origin_offset; + unsigned int name_origin_len; + const char *value; + unsigned int value_len; + unsigned int value_origin_offset; + unsigned int value_origin_len; + const char *origin; +}; + +struct msc_string { + char *name; + unsigned int name_len; + char *value; + unsigned int value_len; +}; + + +/* Engine functions */ + +msc_engine DSOLOCAL *modsecurity_create(apr_pool_t *mp, int processing_mode); + +int DSOLOCAL modsecurity_init(msc_engine *msce, apr_pool_t *mp); + +void DSOLOCAL modsecurity_child_init(msc_engine *msce); + +void DSOLOCAL modsecurity_shutdown(msc_engine *msce); + +apr_status_t DSOLOCAL modsecurity_tx_init(modsec_rec *msr); + +apr_status_t DSOLOCAL modsecurity_process_phase(modsec_rec *msr, unsigned int phase); + + +/* Request body functions */ + +apr_status_t DSOLOCAL modsecurity_request_body_start(modsec_rec *msr, char **error_msg); + +apr_status_t DSOLOCAL modsecurity_request_body_store(modsec_rec *msr, + const char *data, apr_size_t length, char **error_msg); + +apr_status_t DSOLOCAL modsecurity_request_body_end(modsec_rec *msr, char **error_msg); + +apr_status_t DSOLOCAL modsecurity_request_body_retrieve_start(modsec_rec *msr, char **error_msg); + +apr_status_t DSOLOCAL modsecurity_request_body_retrieve_end(modsec_rec *msr); + +/* Retrieves up to nbytes bytes of the request body. Returns 1 on + * success, 0 when there is no more data, or -1 on error. On return + * nbytes will contain the number of bytes stored in the buffer. + */ +apr_status_t DSOLOCAL modsecurity_request_body_retrieve(modsec_rec *msr, msc_data_chunk **chunk, + long int nbytes, char **error_msg); + +void DSOLOCAL msc_add(modsec_rec *msr, int level, msre_actionset *actionset, + const char *action_message, const char *rule_message); + +const char DSOLOCAL *msc_alert_message(modsec_rec *msr, msre_actionset *actionset, const char *action_message, + const char *rule_message); + +void DSOLOCAL msc_alert(modsec_rec *msr, int level, msre_actionset *actionset, const char *action_message, + const char *rule_message); + +apr_status_t DSOLOCAL modsecurity_request_body_clear(modsec_rec *msr, char **error_msg); + +#endif diff --git a/apache2/modules.mk b/apache2/modules.mk new file mode 100644 index 0000000..d201d56 --- /dev/null +++ b/apache2/modules.mk @@ -0,0 +1,19 @@ +MOD_SECURITY2 = mod_security2 apache2_config apache2_io apache2_util \ + re re_operators re_actions re_tfns re_variables \ + msc_logging msc_xml msc_multipart modsecurity msc_parsers msc_util msc_pcre \ + persist_dbm msc_reqbody pdf_protect msc_geo acmp msc_lua + +H = re.h modsecurity.h msc_logging.h msc_multipart.h msc_parsers.h \ + msc_pcre.h msc_util.h msc_xml.h persist_dbm.h apache2.h pdf_protect.h \ + msc_geo.h acmp.h utf8tables.h msc_lua.h + +${MOD_SECURITY2:=.slo}: ${H} +${MOD_SECURITY2:=.lo}: ${H} +${MOD_SECURITY2:=.o}: ${H} + +mod_security2.la: ${MOD_SECURITY2:=.slo} + $(SH_LINK) -rpath $(libexecdir) -module -avoid-version ${MOD_SECURITY2:=.lo} + +DISTCLEAN_TARGETS = modules.mk + +shared = mod_security2.la diff --git a/apache2/msc_geo.c b/apache2/msc_geo.c new file mode 100644 index 0000000..5e72fb9 --- /dev/null +++ b/apache2/msc_geo.c @@ -0,0 +1,491 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ +#include "msc_geo.h" + + +/* -- Lookup Tables -- */ + +static const char *geo_country_code[GEO_COUNTRY_LAST + 1] = { + "--", + "AP","EU","AD","AE","AF","AG","AI","AL","AM","AN", + "AO","AQ","AR","AS","AT","AU","AW","AZ","BA","BB", + "BD","BE","BF","BG","BH","BI","BJ","BM","BN","BO", + "BR","BS","BT","BV","BW","BY","BZ","CA","CC","CD", + "CF","CG","CH","CI","CK","CL","CM","CN","CO","CR", + "CU","CV","CX","CY","CZ","DE","DJ","DK","DM","DO", + "DZ","EC","EE","EG","EH","ER","ES","ET","FI","FJ", + "FK","FM","FO","FR","FX","GA","GB","GD","GE","GF", + "GH","GI","GL","GM","GN","GP","GQ","GR","GS","GT", + "GU","GW","GY","HK","HM","HN","HR","HT","HU","ID", + "IE","IL","IN","IO","IQ","IR","IS","IT","JM","JO", + "JP","KE","KG","KH","KI","KM","KN","KP","KR","KW", + "KY","KZ","LA","LB","LC","LI","LK","LR","LS","LT", + "LU","LV","LY","MA","MC","MD","MG","MH","MK","ML", + "MM","MN","MO","MP","MQ","MR","MS","MT","MU","MV", + "MW","MX","MY","MZ","NA","NC","NE","NF","NG","NI", + "NL","NO","NP","NR","NU","NZ","OM","PA","PE","PF", + "PG","PH","PK","PL","PM","PN","PR","PS","PT","PW", + "PY","QA","RE","RO","RU","RW","SA","SB","SC","SD", + "SE","SG","SH","SI","SJ","SK","SL","SM","SN","SO", + "SR","ST","SV","SY","SZ","TC","TD","TF","TG","TH", + "TJ","TK","TM","TN","TO","TL","TR","TT","TV","TW", + "TZ","UA","UG","UM","US","UY","UZ","VA","VC","VE", + "VG","VI","VN","VU","WF","WS","YE","YT","RS","ZA", + "ZM","ME","ZW","A1","A2","O1","AX","GG","IM","JE" +}; + +static const char *geo_country_code3[GEO_COUNTRY_LAST + 1] = { + "--", + "AP","EU","AND","ARE","AFG","ATG","AIA","ALB","ARM","ANT", + "AGO","AQ","ARG","ASM","AUT","AUS","ABW","AZE","BIH","BRB", + "BGD","BEL","BFA","BGR","BHR","BDI","BEN","BMU","BRN","BOL", + "BRA","BHS","BTN","BV","BWA","BLR","BLZ","CAN","CC","COD", + "CAF","COG","CHE","CIV","COK","CHL","CMR","CHN","COL","CRI", + "CUB","CPV","CX","CYP","CZE","DEU","DJI","DNK","DMA","DOM", + "DZA","ECU","EST","EGY","ESH","ERI","ESP","ETH","FIN","FJI", + "FLK","FSM","FRO","FRA","FX","GAB","GBR","GRD","GEO","GUF", + "GHA","GIB","GRL","GMB","GIN","GLP","GNQ","GRC","GS","GTM", + "GUM","GNB","GUY","HKG","HM","HND","HRV","HTI","HUN","IDN", + "IRL","ISR","IND","IO","IRQ","IRN","ISL","ITA","JAM","JOR", + "JPN","KEN","KGZ","KHM","KIR","COM","KNA","PRK","KOR","KWT", + "CYM","KAZ","LAO","LBN","LCA","LIE","LKA","LBR","LSO","LTU", + "LUX","LVA","LBY","MAR","MCO","MDA","MDG","MHL","MKD","MLI", + "MMR","MNG","MAC","MNP","MTQ","MRT","MSR","MLT","MUS","MDV", + "MWI","MEX","MYS","MOZ","NAM","NCL","NER","NFK","NGA","NIC", + "NLD","NOR","NPL","NRU","NIU","NZL","OMN","PAN","PER","PYF", + "PNG","PHL","PAK","POL","SPM","PCN","PRI","PSE","PRT","PLW", + "PRY","QAT","REU","ROU","RUS","RWA","SAU","SLB","SYC","SDN", + "SWE","SGP","SHN","SVN","SJM","SVK","SLE","SMR","SEN","SOM", + "SUR","STP","SLV","SYR","SWZ","TCA","TCD","TF","TGO","THA", + "TJK","TKL","TKM","TUN","TON","TLS","TUR","TTO","TUV","TWN", + "TZA","UKR","UGA","UM","USA","URY","UZB","VAT","VCT","VEN", + "VGB","VIR","VNM","VUT","WLF","WSM","YEM","YT","SRB","ZAF", + "ZMB","MNE","ZWE","A1","A2","O1","ALA","GGY","IMN","JEY" +}; + +static const char *geo_country_name[GEO_COUNTRY_LAST + 1] = { + "N/A", + "Asia/Pacific Region","Europe","Andorra","United Arab Emirates","Afghanistan","Antigua and Barbuda","Anguilla","Albania","Armenia","Netherlands Antilles", + "Angola","Antarctica","Argentina","American Samoa","Austria","Australia","Aruba","Azerbaijan","Bosnia and Herzegovina","Barbados", + "Bangladesh","Belgium","Burkina Faso","Bulgaria","Bahrain","Burundi","Benin","Bermuda","Brunei Darussalam","Bolivia", + "Brazil","Bahamas","Bhutan","Bouvet Island","Botswana","Belarus","Belize","Canada","Cocos (Keeling) Islands","Congo, The Democratic Republic of the", + "Central African Republic","Congo","Switzerland","Cote D'Ivoire","Cook Islands","Chile","Cameroon","China","Colombia","Costa Rica", + "Cuba","Cape Verde","Christmas Island","Cyprus","Czech Republic","Germany","Djibouti","Denmark","Dominica","Dominican Republic", + "Algeria","Ecuador","Estonia","Egypt","Western Sahara","Eritrea","Spain","Ethiopia","Finland","Fiji", + "Falkland Islands (Malvinas)","Micronesia, Federated States of","Faroe Islands","France","France, Metropolitan","Gabon","United Kingdom","Grenada","Georgia","French Guiana", + "Ghana","Gibraltar","Greenland","Gambia","Guinea","Guadeloupe","Equatorial Guinea","Greece","South Georgia and the South Sandwich Islands","Guatemala", + "Guam","Guinea-Bissau","Guyana","Hong Kong","Heard Island and McDonald Islands","Honduras","Croatia","Haiti","Hungary","Indonesia", + "Ireland","Israel","India","British Indian Ocean Territory","Iraq","Iran, Islamic Republic of","Iceland","Italy","Jamaica","Jordan", + "Japan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Comoros","Saint Kitts and Nevis","Korea, Democratic People's Republic of","Korea, Republic of","Kuwait", + "Cayman Islands","Kazakhstan","Lao People's Democratic Republic","Lebanon","Saint Lucia","Liechtenstein","Sri Lanka","Liberia","Lesotho","Lithuania", + "Luxembourg","Latvia","Libyan Arab Jamahiriya","Morocco","Monaco","Moldova, Republic of","Madagascar","Marshall Islands","Macedonia","Mali", + "Myanmar","Mongolia","Macau","Northern Mariana Islands","Martinique","Mauritania","Montserrat","Malta","Mauritius","Maldives", + "Malawi","Mexico","Malaysia","Mozambique","Namibia","New Caledonia","Niger","Norfolk Island","Nigeria","Nicaragua", + "Netherlands","Norway","Nepal","Nauru","Niue","New Zealand","Oman","Panama","Peru","French Polynesia", + "Papua New Guinea","Philippines","Pakistan","Poland","Saint Pierre and Miquelon","Pitcairn Islands","Puerto Rico","Palestinian Territory","Portugal","Palau", + "Paraguay","Qatar","Reunion","Romania","Russian Federation","Rwanda","Saudi Arabia","Solomon Islands","Seychelles","Sudan", + "Sweden","Singapore","Saint Helena","Slovenia","Svalbard and Jan Mayen","Slovakia","Sierra Leone","San Marino","Senegal","Somalia","Suriname", + "Sao Tome and Principe","El Salvador","Syrian Arab Republic","Swaziland","Turks and Caicos Islands","Chad","French Southern Territories","Togo","Thailand", + "Tajikistan","Tokelau","Turkmenistan","Tunisia","Tonga","Timor-Leste","Turkey","Trinidad and Tobago","Tuvalu","Taiwan", + "Tanzania, United Republic of","Ukraine","Uganda","United States Minor Outlying Islands","United States","Uruguay","Uzbekistan","Holy See (Vatican City State)","Saint Vincent and the Grenadines","Venezuela", + "Virgin Islands, British","Virgin Islands, U.S.","Vietnam","Vanuatu","Wallis and Futuna","Samoa","Yemen","Mayotte","Serbia","South Africa", + "Zambia","Montenegro","Zimbabwe","Anonymous Proxy","Satellite Provider","Other","Aland Islands","Guernsey","Isle of Man","Jersey" +}; + +static const char *geo_country_continent[GEO_COUNTRY_LAST + 1] = { + "--", + "AS","EU","EU","AS","AS","SA","SA","EU","AS","SA", + "AF","AN","SA","OC","EU","OC","SA","AS","EU","SA", + "AS","EU","AF","EU","AS","AF","AF","SA","AS","SA", + "SA","SA","AS","AF","AF","EU","SA","NA","AS","AF", + "AF","AF","EU","AF","OC","SA","AF","AS","SA","SA", + "SA","AF","AS","AS","EU","EU","AF","EU","SA","SA", + "AF","SA","EU","AF","AF","AF","EU","AF","EU","OC", + "SA","OC","EU","EU","EU","AF","EU","SA","AS","SA", + "AF","EU","SA","AF","AF","SA","AF","EU","SA","SA", + "OC","AF","SA","AS","AF","SA","EU","SA","EU","AS", + "EU","AS","AS","AS","AS","AS","EU","EU","SA","AS", + "AS","AF","AS","AS","OC","AF","SA","AS","AS","AS", + "SA","AS","AS","AS","SA","EU","AS","AF","AF","EU", + "EU","EU","AF","AF","EU","EU","AF","OC","EU","AF", + "AS","AS","AS","OC","SA","AF","SA","EU","AF","AS", + "AF","NA","AS","AF","AF","OC","AF","OC","AF","SA", + "EU","EU","AS","OC","OC","OC","AS","SA","SA","OC", + "OC","AS","AS","EU","SA","OC","SA","AS","EU","OC", + "SA","AS","AF","EU","AS","AF","AS","OC","AF","AF", + "EU","AS","AF","EU","EU","EU","AF","EU","AF","AF", + "SA","AF","SA","AS","AF","SA","AF","AF","AF","AS", + "AS","OC","AS","AF","OC","AS","AS","SA","OC","AS", + "AF","EU","AF","OC","NA","SA","AS","EU","SA","SA", + "SA","SA","AS","OC","OC","OC","AS","AF","EU","AF", + "AF","EU","AF","--","--","--","EU","EU","EU","EU" +}; + + +static int db_open(directory_config *dcfg, char **error_msg) +{ + char errstr[1024]; + apr_pool_t *mp = dcfg->mp; + geo_db *geo = dcfg->geo; + apr_status_t rc; + apr_size_t nbytes; + apr_off_t offset; + unsigned char buf[3]; + int i, j; + + #ifdef DEBUG_CONF + fprintf(stderr, "GEO: Initializing geo DB \"%s\".\n", geo->dbfn); + #endif + + if ((rc = apr_file_open(&geo->db, geo->dbfn, APR_READ, APR_OS_DEFAULT, mp)) != APR_SUCCESS) { + *error_msg = apr_psprintf(mp, "Could not open geo database \"%s\": %s", geo->dbfn, apr_strerror(rc, errstr, 1024)); + return 0; + } + + offset = -3; + apr_file_seek(geo->db, APR_END, &offset); + /* TODO check offset */ + + /* Defaults */ + geo->dbtype = GEO_COUNTRY_DATABASE; + geo->ctry_offset = GEO_COUNTRY_OFFSET; + + for (i = 0; i < GEO_STRUCT_INFO_MAX_SIZE; i++) { + memset(buf, 0, 3); + rc = apr_file_read_full(geo->db, &buf, 3, &nbytes); + #ifdef DEBUG_CONF + fprintf(stderr, "GEO: read 0x%02x%02x%02x\n", buf[0], buf[1], buf[2]); + #endif + if ((rc != APR_SUCCESS) || (nbytes != 3)) { + *error_msg = apr_psprintf(mp, "Could not read from geo database \"%s\" (%" APR_SIZE_T_FMT "/3 bytes read): %s", geo->dbfn, nbytes, apr_strerror(rc, errstr, 1024)); + return -1; + } + if ((buf[0] == 0xff) && (buf[1] == 0xff) && (buf[2] == 0xff)) { + #ifdef DEBUG_CONF + fprintf(stderr, "GEO: Found DB info marker at offset 0x%08x\n", (unsigned int)offset); + #endif + memset(buf, 0, 3); + rc = apr_file_read_full(geo->db, &buf, 1, &nbytes); + /* TODO: check rc */ + geo->dbtype = (int)buf[0]; + + /* Backwards compat */ + if (geo->dbtype >= 106) { + geo->dbtype -= 105; + } + #ifdef DEBUG_CONF + fprintf(stderr, "GEO: DB type %d\n", geo->dbtype); + #endif + + /* If a cities DB, then get country offset */ + if ((geo->dbtype == GEO_CITY_DATABASE_0) || (geo->dbtype == GEO_CITY_DATABASE_1)) { + memset(buf, 0, 3); + rc = apr_file_read_full(geo->db, &buf, 3, &nbytes); + if ((rc != APR_SUCCESS) || (nbytes != 3)) { + *error_msg = apr_psprintf(mp, "Could not read geo database \"%s\" country offset (%" APR_SIZE_T_FMT "/3 bytes read): %s", geo->dbfn, nbytes, apr_strerror(rc, errstr, 1024)); + return -1; + } + #ifdef DEBUG_CONF + fprintf(stderr, "GEO: read 0x%02x%02x%02x\n", buf[0], buf[1], buf[2]); + #endif + geo->ctry_offset = 0; + for (j = 0; j < 3; j++) { + geo->ctry_offset += (buf[j] << (j * 8)); + } + } + + #ifdef DEBUG_CONF + fprintf(stderr, "GEO: Country offset 0x%08x\n", geo->ctry_offset); + #endif + + return 1; + } + /* Backup a byte from where we started */ + offset = -4; + apr_file_seek(geo->db, APR_CUR, &offset); + #ifdef DEBUG_CONF + fprintf(stderr, "GEO: DB offset 0x%08x\n", (unsigned int)offset); + #endif + } + + if (geo->dbtype != GEO_COUNTRY_DATABASE) { + *error_msg = apr_psprintf(mp, "Unknown database format"); + return 0; + } + + #ifdef DEBUG_CONF + fprintf(stderr, "GEO: DB type %d\n", geo->dbtype); + #endif + + return 1; +} + +static int field_length(const char *field, int maxlen) +{ + int i; + + if (field == NULL) { + return 0; + } + + for (i = 0; i < maxlen; i++) { + if (field[i] == '\0') { + break; + } + } + + return i; +} + +/** + * Initialise Geo data structure + */ +int geo_init(directory_config *dcfg, const char *dbfn, char **error_msg) +{ + *error_msg = NULL; + + if ((dcfg->geo == NULL) || (dcfg->geo == NOT_SET_P)) { + dcfg->geo = apr_pcalloc(dcfg->mp, sizeof(geo_db)); + } + + dcfg->geo->db = NULL; + dcfg->geo->dbfn = apr_pstrdup(dcfg->mp, dbfn); + dcfg->geo->dbtype = 0; + dcfg->geo->ctry_offset = 0; + + return db_open(dcfg, error_msg); +} + +/** + * Perform geographical lookup on target. + */ +int geo_lookup(modsec_rec *msr, geo_rec *georec, const char *target, char **error_msg) +{ + apr_sockaddr_t *addr; + long ipnum = 0; + char *targetip = NULL; + geo_db *geo = msr->txcfg->geo; + char errstr[1024]; + unsigned char buf[2* GEO_MAX_RECORD_LEN]; + const int reclen = 3; /* Algorithm needs changed if this changes */ + apr_size_t nbytes; + unsigned int rec_val = 0; + apr_off_t seekto = 0; + int rc; + int country = 0; + int level; + double dtmp; + int itmp; + + *error_msg = NULL; + + /* init */ + georec->country_code = geo_country_code[0]; + georec->country_code3 = geo_country_code3[0]; + georec->country_name = geo_country_name[0]; + georec->country_continent = geo_country_continent[0]; + georec->region = ""; + georec->city = ""; + georec->postal_code = ""; + georec->latitude = 0; + georec->longitude = 0; + georec->dma_code = 0; + georec->area_code = 0; + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "GEO: Looking up \"%s\".", log_escape(msr->mp, target)); + } + + /* NOTE: This only works with ipv4 */ + if ((rc = apr_sockaddr_info_get(&addr, target, APR_INET, 0, 0, msr->mp)) != APR_SUCCESS) { + + *error_msg = apr_psprintf(msr->mp, "Geo lookup for \"%s\" failed: %s", log_escape(msr->mp, target), apr_strerror(rc, errstr, 1024)); + msr_log(msr, 4, "%s", *error_msg); + return 0; + } + if ((rc = apr_sockaddr_ip_get(&targetip, addr)) != APR_SUCCESS) { + *error_msg = apr_psprintf(msr->mp, "Geo lookup for \"%s\" failed: %s", log_escape(msr->mp, target), apr_strerror(rc, errstr, 1024)); + msr_log(msr, 4, "%s", *error_msg); + return 0; + }; + + /* Why is this in host byte order? */ + ipnum = ntohl(addr->sa.sin.sin_addr.s_addr); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "GEO: Using address \"%s\" (0x%08lx).", targetip, ipnum); + } + + for (level = 31; level >= 0; level--) { + /* Read the record */ + seekto = 2 * reclen * rec_val; + apr_file_seek(geo->db, APR_SET, &seekto); + /* TODO: check rc */ + rc = apr_file_read_full(geo->db, &buf, (2 * reclen), &nbytes); + + /* NOTE: This is hard-coded for size 3 records */ + /* Left */ + if ((ipnum & (1 << level)) == 0) { + rec_val = buf[0] + + (buf[1] << 8) + + (buf[2] << 16); + } + /* Right */ + else { + rec_val = buf[3] + + (buf[4] << 8) + + (buf[5] << 16); + } + + /* If we are past the country offset, then we are done */ + if (rec_val >= geo->ctry_offset) { + break; + } + } + + if (geo->dbtype == GEO_COUNTRY_DATABASE) { + country = rec_val; + country -= geo->ctry_offset; + if ((country <= 0) || (country > GEO_COUNTRY_LAST)) { + *error_msg = apr_psprintf(msr->mp, "No geo data for \"%s\" (country %d).", log_escape(msr->mp, target), country); + msr_log(msr, 4, "%s", *error_msg); + return 0; + } + + /* Country */ + georec->country_code = geo_country_code[country]; + georec->country_code3 = geo_country_code3[country]; + georec->country_name = geo_country_name[country]; + georec->country_continent = geo_country_continent[country]; + } + else { + int field_len = 0; + int rec_offset = 0; + int remaining = GEO_CITY_RECORD_LEN; + unsigned char cbuf[GEO_CITY_RECORD_LEN]; + + seekto = rec_val + (2 * reclen - 1) * geo->ctry_offset; + apr_file_seek(geo->db, APR_SET, &seekto); + /* TODO: check rc */ + rc = apr_file_read_full(geo->db, &cbuf, sizeof(cbuf), &nbytes); + + country = cbuf[0]; + if ((country <= 0) || (country > GEO_COUNTRY_LAST)) { + *error_msg = apr_psprintf(msr->mp, "No geo data for \"%s\" (country %d).", log_escape(msr->mp, target), country); + msr_log(msr, 4, "%s", *error_msg); + return 0; + } + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "GEO: rec=\"%s\"", log_escape_raw(msr->mp, cbuf, sizeof(cbuf))); + } + + /* Country */ + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "GEO: country=\"%.*s\"", (1*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))); + } + georec->country_code = geo_country_code[country]; + georec->country_code3 = geo_country_code3[country]; + georec->country_name = geo_country_name[country]; + georec->country_continent = geo_country_continent[country]; + rec_offset++; + remaining -= rec_offset; + + /* Region */ + field_len = field_length((const char *)cbuf+rec_offset, remaining); + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "GEO: region=\"%.*s\"", ((field_len+1)*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4)); + } + georec->region = apr_pstrmemdup(msr->mp, (const char *)cbuf+rec_offset, (remaining)); + rec_offset += field_len + 1; + remaining -= field_len + 1; + + /* City */ + field_len = field_length((const char *)cbuf+rec_offset, remaining); + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "GEO: city=\"%.*s\"", ((field_len+1)*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4)); + } + georec->city = apr_pstrmemdup(msr->mp, (const char *)cbuf+rec_offset, (remaining)); + rec_offset += field_len + 1; + remaining -= field_len + 1; + + /* Postal Code */ + field_len = field_length((const char *)cbuf+rec_offset, remaining); + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "GEO: postal_code=\"%.*s\"", ((field_len+1)*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4)); + } + georec->postal_code = apr_pstrmemdup(msr->mp, (const char *)cbuf+rec_offset, (remaining)); + rec_offset += field_len + 1; + remaining -= field_len + 1; + + /* Latitude */ + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "GEO: latitude=\"%.*s\"", (3*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4)); + } + dtmp = cbuf[rec_offset] + + (cbuf[rec_offset+1] << 8) + + (cbuf[rec_offset+2] << 16); + georec->latitude = dtmp/10000 - 180; + rec_offset += 3; + remaining -= 3; + + + /* Longitude */ + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "GEO: longitude=\"%.*s\"", (3*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4)); + } + dtmp = cbuf[rec_offset] + + (cbuf[rec_offset+1] << 8) + + (cbuf[rec_offset+2] << 16); + georec->longitude = dtmp/10000 - 180; + rec_offset += 3; + remaining -= 3; + + /* dma/area codes are in city rev1 and US only */ + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "GEO: dma/area=\"%.*s\"", (3*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4)); + } + if (geo->dbtype == GEO_CITY_DATABASE_1 + && georec->country_code[0] == 'U' + && georec->country_code[1] == 'S') + { + /* DMA Code */ + itmp = cbuf[rec_offset] + + (cbuf[rec_offset+1] << 8) + + (cbuf[rec_offset+2] << 16); + georec->dma_code = itmp / 1000; + georec->area_code = itmp % 1000; + rec_offset += 6; + remaining -= 6; + } + + } + + *error_msg = apr_psprintf(msr->mp, "Geo lookup for \"%s\" succeeded.", log_escape(msr->mp, target)); + return 1; +} + +/** + * Frees the resources used for Geo lookups + */ +apr_status_t geo_cleanup(modsec_rec *msr) +{ + return APR_SUCCESS; +} + + diff --git a/apache2/msc_geo.h b/apache2/msc_geo.h new file mode 100644 index 0000000..0df47af --- /dev/null +++ b/apache2/msc_geo.h @@ -0,0 +1,72 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ +#ifndef _MSC_GEO_H_ +#define _MSC_GEO_H_ + +#define GEO_STRUCT_INFO_MAX_SIZE 20 +#define GEO_DB_INFO_MAX_SIZE 100 +#define GEO_COUNTRY_OFFSET 0xffff00 +#define GEO_MAX_RECORD_LEN 4 +#define GEO_COUNTRY_UNKNOWN "Unknown" +#define GEO_CITY_UNKNOWN "Unknown" +#define GEO_CITY_RECORD_LEN 50 +#define GEO_COUNTRY_DATABASE 1 +#define GEO_CITY_DATABASE_0 6 +#define GEO_CITY_DATABASE_1 2 +#define GEO_COUNTRY_LAST 250 + + +typedef struct geo_rec geo_rec; +typedef struct geo_db geo_db; + +#include +#include "modsecurity.h" + +/* Structures */ + +struct geo_rec { + const char *country_code; + const char *country_code3; + const char *country_name; + const char *country_continent; + const char *region; + const char *city; + const char *postal_code; + float latitude; + float longitude; + int dma_code; + int area_code; +}; + +struct geo_db { + apr_file_t *db; + const char *dbfn; + int dbtype; + unsigned int ctry_offset; +}; + +/* Functions */ + +int DSOLOCAL geo_init(directory_config *dcfg, const char *dbfn, char **error_msg); + +int DSOLOCAL geo_lookup(modsec_rec *msr, geo_rec *rec, const char *target, char **error_msg); + +apr_status_t DSOLOCAL geo_cleanup(modsec_rec *msr); + +#endif diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c new file mode 100644 index 0000000..956f31b --- /dev/null +++ b/apache2/msc_logging.c @@ -0,0 +1,983 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ +#include + +#include "mod_security2_config.h" +#include "re.h" +#include "msc_logging.h" +#include "httpd.h" +#include "apr_strings.h" +#include "apr_global_mutex.h" +#include "msc_util.h" + + +/** + * Write the supplied data to the audit log (if the FD is ready), update + * the size counters, update the hash context. + */ +static int sec_auditlog_write(modsec_rec *msr, const char *data, unsigned int len) { + apr_size_t nbytes_written, nbytes = len; + apr_status_t rc; + + /* Do nothing if there's no data. */ + if (data == NULL) return -1; + + /* Update size counters and the hash calculation. We always do this, + * even in cases where write fails. That will make it easier to detect + * problems with partial writes. + */ + msr->new_auditlog_size += len; + apr_md5_update(&msr->new_auditlog_md5ctx, data, len); + + /* Do not write if we do not have a file descriptor. */ + if (msr->new_auditlog_fd == NULL) return -1; + + /* Write data to file. */ + rc = apr_file_write_full(msr->new_auditlog_fd, data, nbytes, &nbytes_written); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "Audit log: Failed writing (requested %" APR_SIZE_T_FMT + " bytes, written %" APR_SIZE_T_FMT ")", nbytes, nbytes_written); + + /* Set to NULL to prevent more than one error message on + * out-of-disk-space events and to prevent further attempts + * to write to the same file in this request. + * + * Note that, as we opened the file through the pool mechanism of + * the APR, we do not need to close the file here. It will be closed + * automatically at the end of the request. + */ + msr->new_auditlog_fd = NULL; + + return -1; + } + + return 1; +} + +/** + * Construct a log line in the vcombinedus format (see below). + */ +char *construct_log_vcombinedus(modsec_rec *msr) { + const char *local_user, *remote_user; + const char *referer, *user_agent, *uniqueid; + const char *sessionid; + + /* remote log name */ + if (msr->remote_user == NULL) remote_user = "-"; + else remote_user = msr->remote_user; + + /* authenticated user */ + if (msr->local_user == NULL) local_user = "-"; + else local_user = msr->local_user; + + /* unique id */ + uniqueid = msr->txid; + if (uniqueid == NULL) uniqueid = "-"; + + /* referer */ + referer = "-"; + /* Logging Referer is a waste of space. + referer = (char *)apr_table_get(msr->request_headers, "Referer"); + if (referer == NULL) referer = "-"; + */ + + /* user agent */ + user_agent = "-"; + /* Logging User-Agent is a waste of space too. + user_agent = (char *)apr_table_get(msr->request_headers, "User-Agent"); + if (user_agent == NULL) user_agent = "-"; + */ + + /* sessionid */ + sessionid = (msr->sessionid == NULL ? "-" : msr->sessionid); + + return apr_psprintf(msr->mp, "%s %s %s %s [%s] \"%s\" %u %" APR_OFF_T_FMT " \"%s\" \"%s\" %s \"%s\"", + log_escape_nq(msr->mp, msr->hostname), msr->remote_addr, log_escape_nq(msr->mp, remote_user), + log_escape_nq(msr->mp, local_user), current_logtime(msr->mp), + ((msr->request_line == NULL) ? "" : log_escape(msr->mp, msr->request_line)), + msr->response_status, msr->bytes_sent, log_escape(msr->mp, referer), + log_escape(msr->mp, user_agent), log_escape(msr->mp, uniqueid), sessionid); +} + +/** + * Constructs a log line in vcombined log format trying to truncate + * some of the fields to make the log line shorter than _limit bytes. + */ +char *construct_log_vcombinedus_limited(modsec_rec *msr, int _limit, int *was_limited) { + char *hostname; + char *local_user, *remote_user; + char *referer, *user_agent, *uniqueid; + const char *sessionid; + char *the_request, *bytes_sent; + int limit = _limit; + + /* hostname */ + hostname = (msr->hostname == NULL ? "-" : log_escape_nq(msr->mp, msr->hostname)); + + /* remote log name */ + if (msr->remote_user == NULL) remote_user = "-"; + else remote_user = log_escape_nq(msr->mp, msr->remote_user); + + /* authenticated user */ + if (msr->local_user == NULL) local_user = "-"; + else local_user = log_escape_nq(msr->mp, msr->local_user); + + /* unique id */ + if (msr->txid == NULL) uniqueid = "-"; + else uniqueid = log_escape(msr->mp, msr->txid); + + /* referer */ + referer = "-"; + /* + referer = (char *)apr_table_get(msr->request_headers, "Referer"); + if (referer == NULL) referer = "-"; + else referer = log_escape(msr->mp, referer); + */ + + /* user agent */ + user_agent = "-"; + /* + user_agent = (char *)apr_table_get(msr->request_headers, "User-Agent"); + if (user_agent == NULL) user_agent = "-"; + else user_agent = log_escape(msr->mp, user_agent); + */ + + /* sessionid */ + sessionid = (msr->sessionid == NULL) ? "-" : log_escape(msr->mp, msr->sessionid); + + the_request = (msr->request_line == NULL) ? "" : log_escape(msr->mp, msr->request_line); + + bytes_sent = apr_psprintf(msr->mp, "%" APR_OFF_T_FMT, msr->bytes_sent); + + /* first take away the size of the + * information we must log + */ + limit -= 22; /* spaces and double quotes */ + limit -= strlen(hostname); /* server name or IP */ + limit -= strlen(msr->remote_addr); /* remote IP */ + limit -= 28; /* current_logtime */ + limit -= 3; /* status */ + limit -= strlen(bytes_sent); /* bytes sent */ + limit -= strlen(uniqueid); /* unique id */ + limit -= strlen(sessionid); /* session id */ + + if (limit <= 0) { + msr_log(msr, 1, "GuardianLog: Atomic pipe write size too small: %d", PIPE_BUF); + return NULL; + } + + /* we hope to be able to squeeze everything in */ + if (limit < (int)(strlen(remote_user) + strlen(local_user) + strlen(referer) + + strlen(user_agent) + strlen(the_request))) + { + /* Boo hoo hoo, there's not enough space available. */ + *was_limited = 1; + + /* Let's see if we can reduce the size of something. This + * is a very crude approach but it seems to work for our + * needs. + */ + if (strlen(remote_user) > 32) { + msr_log(msr, 9, "GuardianLog: Reduced remote_user to 32."); + remote_user[32] = '\0'; + } + limit -= strlen(remote_user); + + if (strlen(local_user) > 32) { + msr_log(msr, 9, "GuardianLog: Reduced local_user to 32."); + local_user[32] = '\0'; + } + limit -= strlen(local_user); + + if (strlen(referer) > 64) { + msr_log(msr, 9, "GuardianLog: Reduced referer to 64."); + referer[64] = '\0'; + } + limit -= strlen(referer); + + if (strlen(user_agent) > 64) { + msr_log(msr, 9, "GuardianLog: Reduced user_agent to 64."); + user_agent[64] = '\0'; + } + limit -= strlen(user_agent); + + if (limit <= 0) { + msr_log(msr, 1, "GuardianLog: Atomic pipe write size too small: %d.", PIPE_BUF); + return NULL; + } + + /* use what's left for the request line */ + if ((int)strlen(the_request) > limit) { + the_request[limit] = '\0'; + msr_log(msr, 9, "GuardianLog: Reduced the_request to %d bytes.", limit); + } + } else { + /* Yay! We have enough space! */ + *was_limited = 0; + } + + return apr_psprintf(msr->mp, "%s %s %s %s [%s] \"%s\" %u %s \"%s\" \"%s\" %s \"%s\"", + hostname, msr->remote_addr, remote_user, + local_user, current_logtime(msr->mp), the_request, + msr->response_status, bytes_sent, referer, user_agent, + uniqueid, sessionid + ); +} + +/** + * Checks if the provided string is a valid audit log parts specification. + */ +int is_valid_parts_specification(char *p) { + char c, *t = p; + + while((c = *(t++)) != '\0') { + if ((c != AUDITLOG_PART_ENDMARKER)&&((c < AUDITLOG_PART_FIRST)||(c > AUDITLOG_PART_LAST))) { + return 0; + } + } + + return 1; +} + +/** + * Constructs a filename that will be used to store an + * audit log entry. + */ +static char *construct_auditlog_filename(apr_pool_t *mp, const char *uniqueid) { + apr_time_exp_t t; + char tstr[300]; + apr_size_t len; + + apr_time_exp_lt(&t, apr_time_now()); + + apr_strftime(tstr, &len, 299, "/%Y%m%d/%Y%m%d-%H%M/%Y%m%d-%H%M%S", &t); + return apr_psprintf(mp, "%s-%s", tstr, uniqueid); +} + +/** + * Creates a random 8-character string that + * consists of hexadecimal numbers, to be used + * as an audit log boundary. + */ +static char *create_auditlog_boundary(request_rec *r) { + unsigned long data = rand(); + /* Do note that I tried using apr_generate_random_bytes but it turned + * out to be terribly slow for some reason. Needs further investigation. + */ + return bytes2hex(r->pool, (void *)&data, 4); +} + +/** + * Sanitises the request line by removing the parameters + * that have been marked as sensitive. + */ +static void sanitise_request_line(modsec_rec *msr) { + const apr_array_header_t *tarr; + const apr_table_entry_t *telts; + int i; + char *qspos; + + /* Locate the query string. */ + qspos = strstr(msr->request_line, "?"); + if (qspos == NULL) return; + qspos++; + + /* Loop through the list of sensitive parameters. */ + tarr = apr_table_elts(msr->arguments_to_sanitise); + telts = (const apr_table_entry_t*)tarr->elts; + for (i = 0; i < tarr->nelts; i++) { + msc_arg *arg = (msc_arg *)telts[i].val; + /* Only look at the parameters that appeared in the query string. */ + if (strcmp(arg->origin, "QUERY_STRING") == 0) { + char *p; + int j; + + /* Go to the beginning of the parameter. */ + p = qspos; + j = arg->value_origin_offset; + while((*p != '\0')&&(j--)) p++; + if (*p == '\0') { + msr_log(msr, 1, "Unable to sanitise variable \"%s\" at offset %u of QUERY_STRING" + "because the request line is too short.", + log_escape_ex(msr->mp, arg->name, arg->name_len), + arg->value_origin_offset); + continue; + } + + /* Write over the value. */ + j = arg->value_origin_len; + while((*p != '\0')&&(j--)) { + *p++ = '*'; + } + if (*p == '\0') { + msr_log(msr, 1, "Unable to sanitise variable \"%s\" at offset %u (size %d) " + "of QUERY_STRING because the request line is too short.", + log_escape_ex(msr->mp, arg->name, arg->name_len), + arg->value_origin_offset, arg->value_origin_len); + continue; + } + } + } +} + +/** + * Output the Producer header. + */ +static void sec_auditlog_write_producer_header(modsec_rec *msr) { + char **signatures = NULL; + char *text = NULL; + int i; + + /* Try to write everything in one go. */ + if (msr->txcfg->component_signatures->nelts == 0) { + text = apr_psprintf(msr->mp, "Producer: %s.\n", MODSEC_MODULE_NAME_FULL); + sec_auditlog_write(msr, text, strlen(text)); + + return; + } + + /* Start with the ModSecurity signature. */ + text = apr_psprintf(msr->mp, "Producer: %s", MODSEC_MODULE_NAME_FULL); + sec_auditlog_write(msr, text, strlen(text)); + + + /* Then loop through the components and output individual signatures. */ + signatures = (char **)msr->txcfg->component_signatures->elts; + for(i = 0; i < msr->txcfg->component_signatures->nelts; i++) { + text = apr_psprintf(msr->mp, "; %s", (char *)signatures[i]); + sec_auditlog_write(msr, text, strlen(text)); + } + + sec_auditlog_write(msr, ".\n", 2); +} + +/** + * Produce an audit log entry. + */ +void sec_audit_logger(modsec_rec *msr) { + const apr_array_header_t *arr = NULL; + apr_table_entry_t *te = NULL; + char *str1 = NULL, *str2 = NULL, *text = NULL; + const msre_rule *rule = NULL; + apr_size_t nbytes, nbytes_written; + unsigned char md5hash[APR_MD5_DIGESTSIZE]; + int was_limited = 0; + int wrote_response_body = 0; + char *entry_filename, *entry_basename; + apr_status_t rc; + int i, limit; + + /* the boundary is used by both audit log types */ + msr->new_auditlog_boundary = create_auditlog_boundary(msr->r); + + /* Return silently if we don't have a request line. This + * means we will not be logging request timeouts. + */ + if (msr->request_line == NULL) { + msr_log(msr, 4, "Audit log: Skipping request whose request_line is null."); + return; + } + + /* Also return silently if we don't have a file descriptor. */ + if (msr->txcfg->auditlog_fd == NULL) { + msr_log(msr, 4, "Audit log: Skipping request since there is nowhere to write to."); + return; + } + + if (msr->txcfg->auditlog_type != AUDITLOG_CONCURRENT) { + /* Serial logging - we already have an open file + * descriptor to write to. + */ + msr->new_auditlog_fd = msr->txcfg->auditlog_fd; + } else { + /* Concurrent logging - we need to create a brand + * new file for this request. + */ + apr_md5_init(&msr->new_auditlog_md5ctx); + + msr->new_auditlog_filename = construct_auditlog_filename(msr->mp, msr->txid); + if (msr->new_auditlog_filename == NULL) return; + + /* The audit log storage directory should be explicitly + * defined. But if it isn't try to write to the same + * directory where the index file is placed. Of course, + * it is *very* bad practice to allow the Apache user + * to write to the same directory where a root user is + * writing to but it's not us that's causing the problem + * and there isn't anything we can do about that. + * + * ENH Actually there is something we can do! We will make + * SecAuditStorageDir mandatory, ask the user to explicitly + * define the storage location *and* refuse to work if the + * index and the storage location are in the same folder. + */ + if (msr->txcfg->auditlog_storage_dir == NULL) { + entry_filename = file_dirname(msr->mp, msr->txcfg->auditlog_name); + } + else { + entry_filename = msr->txcfg->auditlog_storage_dir; + } + if (entry_filename == NULL) return; + + entry_filename = apr_psprintf(msr->mp, "%s%s", entry_filename, msr->new_auditlog_filename); + if (entry_filename == NULL) return; + entry_basename = file_dirname(msr->mp, entry_filename); + if (entry_basename == NULL) return; + + /* IMP1 Surely it would be more efficient to check the folders for + * the audit log repository base path in the configuration phase, to reduce + * the work we do on every request. Also, since our path depends on time, + * we could cache the time we last checked and don't check if we know + * the folder is there. + */ + rc = apr_dir_make_recursive(entry_basename, msr->txcfg->auditlog_dirperms, msr->mp); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "Audit log: Failed to create subdirectories: %s (%s)", + entry_basename, get_apr_error(msr->mp, rc)); + return; + } + + rc = apr_file_open(&msr->new_auditlog_fd, entry_filename, + APR_WRITE | APR_TRUNCATE | APR_CREATE | APR_BINARY | APR_FILE_NOCLEANUP, + msr->txcfg->auditlog_fileperms, msr->mp); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "Audit log: Failed to create file: %s (%s)", + entry_filename, get_apr_error(msr->mp, rc)); + return; + } + } + + /* Lock the mutex, but only if we are using serial format. */ + if (msr->txcfg->auditlog_type != AUDITLOG_CONCURRENT) { + rc = apr_global_mutex_lock(msr->modsecurity->auditlog_lock); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "Audit log: Failed to lock global mutex: %s", + get_apr_error(msr->mp, rc)); + } + } + + /* AUDITLOG_PART_HEADER */ + + text = apr_psprintf(msr->mp, "--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_HEADER); + sec_auditlog_write(msr, text, strlen(text)); + + /* Format: time transaction_id remote_addr remote_port local_addr local_port */ + + text = apr_psprintf(msr->mp, "[%s] %s %s %u %s %u", + current_logtime(msr->mp), msr->txid, msr->remote_addr, msr->remote_port, + msr->local_addr, msr->local_port); + sec_auditlog_write(msr, text, strlen(text)); + + + /* AUDITLOG_PART_REQUEST_HEADERS */ + + if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_REQUEST_HEADERS) != NULL) { + text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_REQUEST_HEADERS); + sec_auditlog_write(msr, text, strlen(text)); + + sanitise_request_line(msr); + + sec_auditlog_write(msr, msr->request_line, strlen(msr->request_line)); + sec_auditlog_write(msr, "\n", 1); + + arr = apr_table_elts(msr->request_headers); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + text = apr_psprintf(msr->mp, "%s: %s\n", te[i].key, te[i].val); + /* Do we need to sanitise this request header? */ + if (apr_table_get(msr->request_headers_to_sanitise, te[i].key) != NULL) { + /* Yes, sanitise it. */ + memset(text + strlen(te[i].key) + 2, '*', strlen(te[i].val)); + } + sec_auditlog_write(msr, text, strlen(text)); + } + } + + /* AUDITLOG_PART_REQUEST_BODY */ + + /* Output this part of it was explicitly requested (C) or if it was the faked + * request body that was requested (I) but we have no reason to fake it (it's + * already in the correct format). + */ + if ( (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_REQUEST_BODY) != NULL) + || ( (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_FAKE_REQUEST_BODY) != NULL) + && (msr->mpd == NULL) ) ) + { + if (msr->msc_reqbody_read) { + const apr_array_header_t *tarr; + const apr_table_entry_t *telts; + apr_array_header_t *sorted_args; + unsigned int offset = 0, last_offset = 0; + msc_arg *nextarg = NULL; + int sanitise = 0; /* IMP1 Use constants for "sanitise" values. */ + char *my_error_msg = NULL; + + sorted_args = apr_array_make(msr->mp, 25, sizeof(const msc_arg *)); + + /* First we need to sort the arguments that need to be + * sanitised in descending order (we are using a stack structure + * to store then so the order will be ascending when we start + * popping them out). This is because we will + * be reading the request body sequentially and must + * sanitise it as we go. + */ + + for(;;) { + nextarg = NULL; + + /* Find the next largest offset (excluding + * the ones we've used up already). + */ + tarr = apr_table_elts(msr->arguments_to_sanitise); + telts = (const apr_table_entry_t*)tarr->elts; + for(i = 0; i < tarr->nelts; i++) { + msc_arg *arg = (msc_arg *)telts[i].val; + if (strcmp(arg->origin, "BODY") != 0) continue; + + if (last_offset == 0) { /* The first time we're here. */ + if (arg->value_origin_offset > offset) { + offset = arg->value_origin_offset; + nextarg = arg; + } + } else { /* Not the first time. */ + if ((arg->value_origin_offset > offset) + &&(arg->value_origin_offset < last_offset)) + { + offset = arg->value_origin_offset; + nextarg = arg; + } + } + } + + /* If we don't have the next argument that means + * we're done here. + */ + if (nextarg == NULL) break; + + sanitise = 2; /* Means time to pop the next argument out. */ + last_offset = offset; + offset = 0; + { /* IMP1 Fix this ugly bit here. */ + msc_arg **x = apr_array_push(sorted_args); + *x = nextarg; + } + } + + /* Now start retrieving the body chunk by chunk and + * sanitise data in pieces. + */ + + rc = modsecurity_request_body_retrieve_start(msr, &my_error_msg); + if (rc < 0) { + msr_log(msr, 1, "Audit log: %s", my_error_msg); + } else { + msc_data_chunk *chunk = NULL; + unsigned int chunk_offset = 0; + unsigned int sanitise_offset = 0; + unsigned int sanitise_length = 0; + + text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_REQUEST_BODY); + sec_auditlog_write(msr, text, strlen(text)); + + for(;;) { + rc = modsecurity_request_body_retrieve(msr, &chunk, -1, &my_error_msg); + if (chunk != NULL) { + /* Anything greater than 1 means we have more data to sanitise. */ + while (sanitise > 1) { + msc_arg **arg = NULL; + + if (sanitise == 2) { + /* Get the next argument from the stack. */ + arg = (msc_arg **)apr_array_pop(sorted_args); + if (arg == NULL) sanitise = 0; /* We're done sanitising. */ + else { + /* Continue with sanitation to process the + * retrieved argument. + */ + sanitise = 1; + sanitise_offset = (*arg)->value_origin_offset; + sanitise_length = (*arg)->value_origin_len; + } + } + + if (sanitise) { + /* Check if the data we want to sanitise is + * stored in the current chunk. + */ + if (chunk_offset + chunk->length > sanitise_offset) { + unsigned int soff; /* data offset within chunk */ + unsigned int len; /* amount in this chunk to sanitise */ + + soff = sanitise_offset - chunk_offset; + + if (soff + sanitise_length <= chunk->length) { + /* The entire argument resides in the current chunk. */ + len = sanitise_length; + sanitise = 2; /* Get another parameter to sanitise. */ + } else { + /* Some work to do here but we'll need to seek + * another chunk. + */ + len = chunk->length - soff; + sanitise_offset += len; + sanitise_length -= len; + sanitise = 1; /* It's OK to go to the next chunk. */ + } + + /* Yes, we actually write over the original data. + * We shouldn't be needing it any more. + */ + if (soff + len <= chunk->length) { /* double check */ + memset((char *)chunk->data + soff, '*', len); + } + } + } + } + + /* Write the sanitised chunk to the log + * and advance to the next chunk. */ + sec_auditlog_write(msr, chunk->data, chunk->length); + chunk_offset += chunk->length; + } + + if (rc <= 0) { + break; + } + } + + if (rc < 0) { + msr_log(msr, 1, "Audit log: %s", my_error_msg); + } + + modsecurity_request_body_retrieve_end(msr); + } + } + } + + /* AUDITLOG_PART_FAKE_REQUEST_BODY */ + + if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_FAKE_REQUEST_BODY) != NULL) { + if ((msr->msc_reqbody_read)&&(msr->mpd != NULL)) { + char *buffer = NULL; + + buffer = multipart_reconstruct_urlencoded_body_sanitise(msr); + if (buffer == NULL) { + msr_log(msr, 1, "Audit log: Failed to reconstruct request body."); + } else { + text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_FAKE_REQUEST_BODY); + sec_auditlog_write(msr, text, strlen(text)); + sec_auditlog_write(msr, buffer, strlen(buffer)); + } + } + } + + /* AUDITLOG_PART_A_RESPONSE_HEADERS */ + + if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_A_RESPONSE_HEADERS) != NULL) { + text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_A_RESPONSE_HEADERS); + sec_auditlog_write(msr, text, strlen(text)); + + /* There are no response headers (or the status line) in HTTP 0.9 */ + if (msr->response_headers_sent) { + if (msr->status_line != NULL) { + text = apr_psprintf(msr->mp, "%s %s\n", msr->response_protocol, + msr->status_line); + } else { + text = apr_psprintf(msr->mp, "%s %u\n", msr->response_protocol, + msr->response_status); + } + sec_auditlog_write(msr, text, strlen(text)); + + /* Output headers */ + + arr = apr_table_elts(msr->response_headers); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + text = apr_psprintf(msr->mp, "%s: %s\n", te[i].key, te[i].val); + /* Do we need to sanitise this response header? */ + if (apr_table_get(msr->response_headers_to_sanitise, te[i].key) != NULL) { + /* Yes, sanitise it. */ + memset(text + strlen(te[i].key) + 2, '*', strlen(te[i].val)); + } + sec_auditlog_write(msr, text, strlen(text)); + } + } + } + + /* AUDITLOG_PART_RESPONSE_BODY */ + + if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_RESPONSE_BODY) != NULL) { + if (msr->resbody_data != NULL) { + text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_RESPONSE_BODY); + sec_auditlog_write(msr, text, strlen(text)); + sec_auditlog_write(msr, msr->resbody_data, msr->resbody_length); + wrote_response_body = 1; + } + } + + /* AUDITLOG_PART_TRAILER */ + + if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_TRAILER) != NULL) { + apr_time_t now = apr_time_now(); + + text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_TRAILER); + sec_auditlog_write(msr, text, strlen(text)); + + /* Messages */ + for(i = 0; i < msr->alerts->nelts; i++) { + text = apr_psprintf(msr->mp, "Message: %s\n", ((char **)msr->alerts->elts)[i]); + sec_auditlog_write(msr, text, strlen(text)); + } + + /* Apache error messages */ + for(i = 0; i < msr->error_messages->nelts; i++) { + error_message *em = (((error_message**)msr->error_messages->elts)[i]); + text = apr_psprintf(msr->mp, "Apache-Error: %s\n", + format_error_log_message(msr->mp, em)); + sec_auditlog_write(msr, text, strlen(text)); + } + + /* Action */ + if (msr->was_intercepted) { + text = apr_psprintf(msr->mp, "Action: Intercepted (phase %d)\n", msr->intercept_phase); + sec_auditlog_write(msr, text, strlen(text)); + } + + /* Apache-Handler */ + if (msr->r->handler != NULL) { + text = apr_psprintf(msr->mp, "Apache-Handler: %s\n", msr->r->handler); + sec_auditlog_write(msr, text, strlen(text)); + } + + /* Processing times */ + if (msr->time_checkpoint_1 == 0) { + text = apr_psprintf(msr->mp, "Stopwatch: %" APR_TIME_T_FMT " %" APR_TIME_T_FMT + " (- - -)\n", (msr->request_time), (now - msr->request_time)); + } else { + char sw_str2[101] = "-"; + char sw_str3[101] = "-"; + + if (msr->time_checkpoint_2 != 0) { + apr_snprintf(sw_str2, sizeof(sw_str2), "%" APR_TIME_T_FMT, + (msr->time_checkpoint_2 - msr->request_time)); + } + + if (msr->time_checkpoint_3 != 0) { + apr_snprintf(sw_str3, sizeof(sw_str3), "%" APR_TIME_T_FMT, + (msr->time_checkpoint_3 - msr->request_time)); + } + + text = apr_psprintf(msr->mp, "Stopwatch: %" APR_TIME_T_FMT + " %" APR_TIME_T_FMT " (%" APR_TIME_T_FMT + "%s %s %s)\n", + (msr->request_time), (now - msr->request_time), + (msr->time_checkpoint_1 - msr->request_time), + ((msr->msc_reqbody_read == 0) ? "" : "*"), + sw_str2, sw_str3 + ); + } + + sec_auditlog_write(msr, text, strlen(text)); + + /* Our response body does not contain chunks */ + /* ENH Only write this when the output was chunked. */ + /* ENH Add info when request body was decompressed, dechunked too. */ + if (wrote_response_body) { + text = apr_psprintf(msr->mp, "Response-Body-Transformed: Dechunked\n"); + sec_auditlog_write(msr, text, strlen(text)); + } + + sec_auditlog_write_producer_header(msr); + + /* Server */ + if (msr->server_software != NULL) { + text = apr_psprintf(msr->mp, "Server: %s\n", msr->server_software); + sec_auditlog_write(msr, text, strlen(text)); + } + + /* Sanitised arguments */ + { + const apr_array_header_t *tarr; + const apr_table_entry_t *telts; + + tarr = apr_table_elts(msr->arguments_to_sanitise); + telts = (const apr_table_entry_t*)tarr->elts; + + if (tarr->nelts > 0) { + text = apr_psprintf(msr->mp, "Sanitised-Args: "); + sec_auditlog_write(msr, text, strlen(text)); + } + + for(i = 0; i < tarr->nelts; i++) { + msc_arg *arg = (msc_arg *)telts[i].val; + text = apr_psprintf(msr->mp, "%s\"%s\"%s", ((i == 0) ? "" : ", "), + log_escape(msr->mp, arg->name), ((i == (tarr->nelts - 1)) ? ".\n" : "")); + sec_auditlog_write(msr, text, strlen(text)); + } + } + + /* Sanitised request headers */ + { + const apr_array_header_t *tarr; + const apr_table_entry_t *telts; + + tarr = apr_table_elts(msr->request_headers_to_sanitise); + telts = (const apr_table_entry_t*)tarr->elts; + + if (tarr->nelts > 0) { + text = apr_psprintf(msr->mp, "Sanitised-Request-Headers: "); + sec_auditlog_write(msr, text, strlen(text)); + } + + for(i = 0; i < tarr->nelts; i++) { + text = apr_psprintf(msr->mp, "%s\"%s\"%s", ((i == 0) ? "" : ", "), + log_escape(msr->mp, telts[i].key), ((i == (tarr->nelts - 1)) ? ".\n" : "")); + sec_auditlog_write(msr, text, strlen(text)); + } + } + + /* Sanitised response headers */ + { + const apr_array_header_t *tarr; + const apr_table_entry_t *telts; + + tarr = apr_table_elts(msr->response_headers_to_sanitise); + telts = (const apr_table_entry_t*)tarr->elts; + + if (tarr->nelts > 0) { + text = apr_psprintf(msr->mp, "Sanitised-Response-Headers: "); + sec_auditlog_write(msr, text, strlen(text)); + } + + for(i = 0; i < tarr->nelts; i++) { + text = apr_psprintf(msr->mp, "%s\"%s\"%s", ((i == 0) ? "" : ", "), + log_escape(msr->mp, telts[i].key), ((i == (tarr->nelts - 1)) ? ".\n" : "")); + sec_auditlog_write(msr, text, strlen(text)); + } + } + + /* Web application info. */ + if ( ((msr->txcfg->webappid != NULL)&&(strcmp(msr->txcfg->webappid, "default") != 0)) + || (msr->sessionid != NULL) || (msr->userid != NULL)) + { + text = apr_psprintf(msr->mp, "WebApp-Info: \"%s\" \"%s\" \"%s\"\n", + msr->txcfg->webappid == NULL ? "-" : log_escape(msr->mp, msr->txcfg->webappid), + msr->sessionid == NULL ? "-" : log_escape(msr->mp, msr->sessionid), + msr->userid == NULL ? "-" : log_escape(msr->mp, msr->userid)); + sec_auditlog_write(msr, text, strlen(text)); + } + } + + /* AUDITLOG_PART_UPLOADS */ + /* ENH: Implement */ + + + /* AUDITLOG_PART_MATCHEDRULES */ + + if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_MATCHEDRULES) != NULL) { + text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_MATCHEDRULES); + sec_auditlog_write(msr, text, strlen(text)); + + /* Matched Rules */ + for(i = 0; i < msr->matched_rules->nelts; i++) { + rule = ((msre_rule **)msr->matched_rules->elts)[i]; + text = apr_psprintf(msr->mp, "%s\n", rule->unparsed); + sec_auditlog_write(msr, text, strlen(text)); + } + } + + + /* AUDITLOG_PART_ENDMARKER */ + + text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_ENDMARKER); + sec_auditlog_write(msr, text, strlen(text)); + + /* Return here if we were writing to a serial log + * as it does not need an index file. + */ + if (msr->txcfg->auditlog_type != AUDITLOG_CONCURRENT) { + sec_auditlog_write(msr, "\n", 1); + + /* Unlock the mutex we used to serialise access to the audit log file. */ + rc = apr_global_mutex_unlock(msr->modsecurity->auditlog_lock); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "Audit log: Failed to unlock global mutex: %s", + get_apr_error(msr->mp, rc)); + } + + return; + } + + /* From here on only concurrent-style processing. */ + + apr_file_close(msr->new_auditlog_fd); + + /* Write an entry to the index file */ + + /* Calculate hash of the entry. */ + apr_md5_final(md5hash, &msr->new_auditlog_md5ctx); + + str2 = apr_psprintf(msr->mp, "%s %d %d md5:%s", msr->new_auditlog_filename, 0, + msr->new_auditlog_size, bytes2hex(msr->mp, md5hash, 16)); + if (str2 == NULL) return; + + /* We do not want the index line to be longer than 3980 bytes. */ + limit = 3980; + was_limited = 0; + + /* If we are logging to a pipe we need to observe and + * obey the pipe atomic write limit - PIPE_BUF. For + * more details see the discussion in sec_guardian_logger code. + */ + if (msr->txcfg->auditlog_name[0] == '|') { + if (PIPE_BUF < limit) { + limit = PIPE_BUF; + } + } + + limit = limit - strlen(str2) - 5; + if (limit <= 0) { + msr_log(msr, 1, "Audit Log: Atomic PIPE write buffer too small: %d", PIPE_BUF); + return; + } + + str1 = construct_log_vcombinedus_limited(msr, limit, &was_limited); + if (str1 == NULL) return; + + if (was_limited == 0) { + text = apr_psprintf(msr->mp, "%s %s \n", str1, str2); + } else { + text = apr_psprintf(msr->mp, "%s %s L\n", str1, str2); + } + if (text == NULL) return; + + nbytes = strlen(text); + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Audit Log: Writing %" APR_SIZE_T_FMT " bytes to primary concurrent index", nbytes); + } + apr_file_write_full(msr->txcfg->auditlog_fd, text, nbytes, &nbytes_written); + + /* Write to the secondary audit log if we have one */ + if (msr->txcfg->auditlog2_fd != NULL) { + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Audit Log: Writing %" APR_SIZE_T_FMT " bytes to secondary concurrent index", nbytes); + } + apr_file_write_full(msr->txcfg->auditlog2_fd, text, nbytes, &nbytes_written); + } +} diff --git a/apache2/msc_logging.h b/apache2/msc_logging.h new file mode 100644 index 0000000..ea25898 --- /dev/null +++ b/apache2/msc_logging.h @@ -0,0 +1,54 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ +#ifndef _MSC_LOGGING_H_ +#define _MSC_LOGGING_H_ + +#define AUDITLOG_OFF 0 +#define AUDITLOG_ON 1 +#define AUDITLOG_RELEVANT 2 + +#define AUDITLOG_SERIAL 0 +#define AUDITLOG_CONCURRENT 1 + +#define AUDITLOG_PART_FIRST 'A' +#define AUDITLOG_PART_HEADER 'A' +#define AUDITLOG_PART_REQUEST_HEADERS 'B' +#define AUDITLOG_PART_REQUEST_BODY 'C' +#define AUDITLOG_PART_RESPONSE_HEADERS 'D' +#define AUDITLOG_PART_RESPONSE_BODY 'E' +#define AUDITLOG_PART_A_RESPONSE_HEADERS 'F' +#define AUDITLOG_PART_A_RESPONSE_BODY 'G' +#define AUDITLOG_PART_TRAILER 'H' +#define AUDITLOG_PART_FAKE_REQUEST_BODY 'I' +#define AUDITLOG_PART_UPLOADS 'J' +#define AUDITLOG_PART_MATCHEDRULES 'K' +#define AUDITLOG_PART_LAST 'K' +#define AUDITLOG_PART_ENDMARKER 'Z' + +#include "modsecurity.h" + +int DSOLOCAL is_valid_parts_specification(char *p); + +char DSOLOCAL *construct_log_vcombinedus(modsec_rec *msr); + +char DSOLOCAL *construct_log_vcombinedus_limited(modsec_rec *msr, int _limit, int *was_limited); + +void DSOLOCAL sec_audit_logger(modsec_rec *msr); + +#endif diff --git a/apache2/msc_lua.c b/apache2/msc_lua.c new file mode 100644 index 0000000..f248a6d --- /dev/null +++ b/apache2/msc_lua.c @@ -0,0 +1,423 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ +#if defined(WITH_LUA) + +#include "msc_lua.h" + +#include "apr_strings.h" + +typedef struct { + apr_array_header_t *parts; + apr_pool_t *pool; +} msc_lua_dumpw_t; + +typedef struct { + msc_script *script; + int index; +} msc_lua_dumpr_t; + +/** + * + */ +static const char* dump_reader(lua_State* L, void* user_data, size_t* size) { + msc_lua_dumpr_t *dumpr = (msc_lua_dumpr_t *)user_data; + msc_script_part *part; + + /* Do we have more chunks to return? */ + if (dumpr->index == dumpr->script->parts->nelts) { + return NULL; + } + + /* Get one chunk. */ + part = ((msc_script_part **)dumpr->script->parts->elts)[dumpr->index]; + *size = part->len; + + dumpr->index++; + + return part->data; +} + +/** + * + */ +static int dump_writer(lua_State *L, const void* data, size_t len, void* user_data) { + msc_lua_dumpw_t *dump = (msc_lua_dumpw_t *)user_data; + msc_script_part *part; + void *part_data; + + /* Allocate new part, copy the data into it. */ + part_data = apr_palloc(dump->pool, len); + memcpy(part_data, data, len); + part = apr_palloc(dump->pool, sizeof(msc_script_part)); + part->data = part_data; + part->len = len; + + /* Then add it to the list of parsts. */ + *(const msc_script_part **)apr_array_push(dump->parts) = part; + + return 0; +} + +/** + * + */ +static int lua_restore(lua_State *L, msc_script *script) { + msc_lua_dumpr_t dumpr; + + dumpr.script = script; + dumpr.index = 0; + + return lua_load(L, dump_reader, &dumpr, script->name); +} + +/** + * + */ +char *lua_compile(msc_script **script, const char *filename, apr_pool_t *pool) { + lua_State *L = NULL; + msc_lua_dumpw_t dump; + + /* Initialise state. */ + L = lua_open(); + luaL_openlibs(L); + + /* Find script. */ + if (luaL_loadfile(L, filename)) { + return apr_psprintf(pool, "ModSecurity: Failed to compile script %s: %s", + filename, lua_tostring(L, -1)); + } + + /* Dump the script into binary form. */ + dump.pool = pool; + dump.parts = apr_array_make(pool, 128, sizeof(msc_script_part *)); + + lua_dump(L, dump_writer, &dump); + + (*script) = apr_pcalloc(pool, sizeof(msc_script)); + (*script)->name = filename; + (*script)->parts = dump.parts; + + /* Destroy state. */ + lua_close(L); + + return NULL; +} + +/** + * + */ +static int l_log(lua_State *L) { + modsec_rec *msr = NULL; + const char *text; + int level; + + /* Retrieve parameters. */ + level = luaL_checknumber(L, 1); + text = luaL_checkstring(L, 2); + + /* Retrieve msr. */ + lua_getglobal(L, "__msr"); + msr = (modsec_rec *)lua_topointer(L, -1); + + /* Log message. */ + if (msr != NULL) { + msr_log(msr, level, "%s", text); + } + + return 0; +} + +/** + * + */ +static apr_array_header_t *resolve_tfns(lua_State *L, int idx, modsec_rec *msr, apr_pool_t *mp) { + apr_array_header_t *tfn_arr = NULL; + msre_tfn_metadata *tfn = NULL; + char *name = NULL; + + tfn_arr = apr_array_make(mp, 25, sizeof(msre_tfn_metadata *)); + if (tfn_arr == NULL) return NULL; + + /* ENH: Why is this userdata and not none/nil when parameter not given? */ + if (lua_isuserdata(L, idx) || lua_isnoneornil(L, idx)) { /* No second parameter */ + return tfn_arr; + } else if (lua_istable(L, idx)) { /* Is the second parameter an array? */ + int i, n = lua_objlen(L, idx); + + for(i = 1; i <= n; i++) { + lua_rawgeti(L, idx, i); + name = (char *)luaL_checkstring(L, -1); + + /* A "none" means start over */ + if (strcmp("none", name) == 0) { + tfn_arr->nelts = 0; + continue; + } + + tfn = msre_engine_tfn_resolve(msr->modsecurity->msre, name); + if (tfn == NULL) { + msr_log(msr, 1, "SecRuleScript: Invalid transformation function: %s", name); + } else { + *(msre_tfn_metadata **)apr_array_push(tfn_arr) = tfn; + } + } + } else if (lua_isstring(L, idx)) { /* The second parameter may be a simple string? */ + name = (char *)luaL_checkstring(L, idx); + + /* A "none" means start over */ + if (strcmp("none", name) == 0) { + tfn_arr->nelts = 0; + } + else { + tfn = msre_engine_tfn_resolve(msr->modsecurity->msre, name); + if (tfn == NULL) { + msr_log(msr, 1, "SecRuleScript: Invalid transformation function: %s", name); + } else { + *(msre_tfn_metadata **)apr_array_push(tfn_arr) = tfn; + } + } + } else { + msr_log(msr, 1, "SecRuleScript: Transformation parameter must be a transformation name or array of transformation names, but found \"%s\" (type %d).", lua_typename(L, idx), lua_type(L, idx)); + return NULL; + } + + return tfn_arr; +} + +/** + * + */ +static int l_getvar(lua_State *L) { + char *varname = NULL, *param = NULL; + modsec_rec *msr = NULL; + msre_rule *rule = NULL; + char *my_error_msg = NULL; + char *p1 = NULL; + apr_array_header_t *tfn_arr = NULL; + msre_var *vx = NULL; + msre_var *var; + + /* Retrieve parameters. */ + p1 = (char *)luaL_checkstring(L, 1); + + /* Retrieve msr. */ + lua_getglobal(L, "__msr"); + msr = (modsec_rec *)lua_topointer(L, -1); + + /* Retrieve rule. */ + lua_getglobal(L, "__rule"); + rule = (msre_rule *)lua_topointer(L, -1); + + /* Extract the variable name and its parameter from the script. */ + varname = apr_pstrdup(msr->msc_rule_mptmp, p1); + param = strchr(varname, '.'); + if (param != NULL) { + *param = '\0'; + param++; + } + + /* Resolve variable. */ + var = msre_create_var_ex(msr->msc_rule_mptmp, msr->modsecurity->msre, + varname, param, msr, &my_error_msg); + + if (var == NULL) { + msr_log(msr, 1, "%s", my_error_msg); + + lua_pushnil(L); + + return 0; + } + + /* Resolve transformation functions. */ + tfn_arr = resolve_tfns(L, 2, msr, msr->msc_rule_mptmp); + + /* Generate variable. */ + vx = generate_single_var(msr, var, tfn_arr, rule, msr->msc_rule_mptmp); + if (vx == NULL) { + lua_pushnil(L); + + return 0; + } + + /* Return variable value. */ + lua_pushlstring(L, vx->value, vx->value_len); + + return 1; +} + +/** + * + */ +static int l_getvars(lua_State *L) { + const apr_array_header_t *tarr; + const apr_table_entry_t *telts; + apr_table_t *vartable = NULL; + apr_array_header_t *tfn_arr = NULL; + char *varname = NULL, *param = NULL; + modsec_rec *msr = NULL; + msre_rule *rule = NULL; + msre_var *vartemplate = NULL; + char *my_error_msg = NULL; + char *p1 = NULL; + int i; + + /* Retrieve parameters. */ + p1 = (char *)luaL_checkstring(L, 1); + + /* Retrieve msr. */ + lua_getglobal(L, "__msr"); + msr = (modsec_rec *)lua_topointer(L, -1); + + /* Retrieve rule. */ + lua_getglobal(L, "__rule"); + rule = (msre_rule *)lua_topointer(L, -1); + + /* Extract the variable name and its parameter from the script. */ + varname = apr_pstrdup(msr->msc_rule_mptmp, p1); + param = strchr(varname, '.'); + if (param != NULL) { + *param = '\0'; + param++; + } + + /* Resolve transformation functions. */ + tfn_arr = resolve_tfns(L, 2, msr, msr->msc_rule_mptmp); + + lua_newtable(L); + + /* Resolve variable. */ + vartemplate = msre_create_var_ex(msr->msc_rule_mptmp, msr->modsecurity->msre, + varname, param, msr, &my_error_msg); + + if (vartemplate == NULL) { + msr_log(msr, 1, "%s", my_error_msg); + + /* Returning empty table. */ + return 1; + } + + vartable = generate_multi_var(msr, vartemplate, tfn_arr, rule, msr->msc_rule_mptmp); + + tarr = apr_table_elts(vartable); + telts = (const apr_table_entry_t*)tarr->elts; + for (i = 0; i < tarr->nelts; i++) { + msre_var *var = (msre_var *)telts[i].val; + + lua_pushnumber(L, i + 1); /* Index is not zero-based. */ + + lua_newtable(L); /* Per-parameter table. */ + + lua_pushstring(L, "name"); + lua_pushlstring(L, var->name, strlen(var->name)); + lua_settable(L, -3); + + lua_pushstring(L, "value"); + lua_pushlstring(L, var->value, var->value_len); + lua_settable(L, -3); + + lua_settable(L, -3); /* Push one parameter into the results table. */ + } + + return 1; +} + +static const struct luaL_Reg mylib[] = { + { "log", l_log }, + { "getvar", l_getvar }, + { "getvars", l_getvars }, + { NULL, NULL } +}; + +/** + * + */ +int lua_execute(msc_script *script, char *param, modsec_rec *msr, msre_rule *rule, char **error_msg) { + apr_time_t time_before; + lua_State *L = NULL; + int rc; + + if (error_msg == NULL) return -1; + *error_msg = NULL; + + if (msr->txcfg->debuglog_level >= 8) { + msr_log(msr, 8, "Lua: Executing script: %s", script->name); + } + + time_before = apr_time_now(); + + /* Create new state. */ + L = lua_open(); + + luaL_openlibs(L); + + /* Associate msr with the state. */ + lua_pushlightuserdata(L, (void *)msr); + lua_setglobal(L, "__msr"); + + /* Associate rule with the state. */ + if (rule != NULL) { + lua_pushlightuserdata(L, (void *)rule); + lua_setglobal(L, "__rule"); + } + + /* Register functions. */ + luaL_register(L, "m", mylib); + + rc = lua_restore(L, script); + if (rc) { + *error_msg = apr_psprintf(msr->mp, "Lua: Failed to restore script with %i.", rc); + return -1; + } + + /* Execute the chunk so that the functions are defined. */ + lua_pcall(L, 0, 0, 0); + + /* Execute main() */ + lua_getglobal(L, "main"); + + /* Put the parameter on the stack. */ + if (param != NULL) { + lua_pushlstring(L, param, strlen(param)); + } + + if (lua_pcall(L, ((param != NULL) ? 1 : 0), 1, 0)) { + *error_msg = apr_psprintf(msr->mp, "Lua: Script execution failed: %s", lua_tostring(L, -1)); + return -1; + } + + /* Get the response from the script. */ + *error_msg = (char *)lua_tostring(L, -1); + if (*error_msg != NULL) { + *error_msg = apr_pstrdup(msr->mp, *error_msg); + } + + /* Destroy state. */ + lua_pop(L, 1); + lua_close(L); + + /* Returns status code to caller. */ + if (msr->txcfg->debuglog_level >= 8) { + msr_log(msr, 8, "Lua: Script completed in %" APR_TIME_T_FMT " usec, returning: %s.", + (apr_time_now() - time_before), *error_msg); + } + + return ((*error_msg != NULL) ? RULE_MATCH : RULE_NO_MATCH); +} + +#endif /* WITH_LUA */ diff --git a/apache2/msc_lua.h b/apache2/msc_lua.h new file mode 100644 index 0000000..80c2bcf --- /dev/null +++ b/apache2/msc_lua.h @@ -0,0 +1,51 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ +#if defined(WITH_LUA) + +#ifndef _MSC_LUA_H_ +#define _MSC_LUA_H_ + +typedef struct msc_script msc_script; +typedef struct msc_script_part msc_script_part; + +#include +#include +#include + +#include "apr_general.h" +#include "apr_tables.h" +#include "modsecurity.h" + +struct msc_script { + const char *name; + apr_array_header_t *parts; +}; + +struct msc_script_part { + const void *data; + size_t len; +}; + +char DSOLOCAL *lua_compile(msc_script **script, const char *filename, apr_pool_t *pool); + +int DSOLOCAL lua_execute(msc_script *script, char *param, modsec_rec *msr, msre_rule *rule, char **error_msg); + +#endif + +#endif /* WITH_LUA */ diff --git a/apache2/msc_multipart.c b/apache2/msc_multipart.c new file mode 100644 index 0000000..d5268eb --- /dev/null +++ b/apache2/msc_multipart.c @@ -0,0 +1,1350 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ +#include +#include + +#include "mod_security2_config.h" +#include "msc_multipart.h" +#include "msc_util.h" +#include "msc_parsers.h" + + +#if 0 +static char *multipart_construct_filename(modsec_rec *msr) { + char c, *p, *q = msr->mpd->mpp->filename; + char *filename; + + /* find the last backward slash and consider the + * filename to be only what's right from it + */ + p = strrchr(q, '\\'); + if (p != NULL) q = p + 1; + + /* do the same for the forward slash */ + p = strrchr(q, '/'); + if (p != NULL) q = p + 1; + + /* allow letters, digits and dots, replace + * everything else with underscores + */ + p = filename = apr_pstrdup(msr->mp, q); + while((c = *p) != 0) { + if (!( isalnum(c) || (c == '.') )) *p = '_'; + p++; + } + + return filename; +} +#endif + +/** + * + */ +static int multipart_parse_content_disposition(modsec_rec *msr, char *c_d_value) { + char *p = NULL, *t = NULL; + + /* accept only what we understand */ + if (strncmp(c_d_value, "form-data", 9) != 0) { + return -1; + } + + /* see if there are any other parts to parse */ + + p = c_d_value + 9; + while((*p == '\t') || (*p == ' ')) p++; + if (*p == '\0') return 1; /* this is OK */ + + if (*p != ';') return -2; + p++; + + /* parse the appended parts */ + + while(*p != '\0') { + char *name = NULL, *value = NULL, *start = NULL; + + /* go over the whitespace */ + while((*p == '\t') || (*p == ' ')) p++; + if (*p == '\0') return -3; + + start = p; + while((*p != '\0') && (*p != '=') && (*p != '\t') && (*p != ' ')) p++; + if (*p == '\0') return -4; + + name = apr_pstrmemdup(msr->mp, start, (p - start)); + + while((*p == '\t') || (*p == ' ')) p++; + if (*p == '\0') return -5; + + if (*p != '=') return -13; + p++; + + while((*p == '\t') || (*p == ' ')) p++; + if (*p == '\0') return -6; + + /* Accept both quotes as some backends will accept them, but + * technically "'" is invalid and so flag_invalid_quoting is + * set so the user can deal with it in the rules if they so wish. + */ + if ((*p == '"') || (*p == '\'')) { + /* quoted */ + char quote = *p; + + if (quote == '\'') { + msr->mpd->flag_invalid_quoting = 1; + } + + p++; + if (*p == '\0') return -7; + + start = p; + value = apr_pstrdup(msr->mp, p); + t = value; + + while(*p != '\0') { + if (*p == '\\') { + if (*(p + 1) == '\0') { + /* improper escaping */ + return -8; + } + /* only quote and \ can be escaped */ + if ((*(p + 1) == quote) || (*(p + 1) == '\\')) { + p++; + } + else { + /* improper escaping */ + + /* We allow for now because IE sends + * improperly escaped content and there's + * nothing we can do about it. + * + * return -9; + */ + } + } + else if (*p == quote) { + *t = '\0'; + break; + } + + *(t++) = *(p++); + } + if (*p == '\0') return -10; + + p++; /* go over the quote at the end */ + + } else { + /* not quoted */ + + start = p; + while((*p != '\0') && (is_token_char(*p))) p++; + value = apr_pstrmemdup(msr->mp, start, (p - start)); + } + + /* evaluate part */ + + if (strcmp(name, "name") == 0) { + if (msr->mpd->mpp->name != NULL) { + msr_log(msr, 4, "Multipart: Warning: Duplicate Content-Disposition name: %s", + log_escape_nq(msr->mp, value)); + return -14; + } + msr->mpd->mpp->name = value; + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Multipart: Content-Disposition name: %s", + log_escape_nq(msr->mp, value)); + } + } + else + if (strcmp(name, "filename") == 0) { + if (msr->mpd->mpp->filename != NULL) { + msr_log(msr, 4, "Multipart: Warning: Duplicate Content-Disposition filename: %s", + log_escape_nq(msr->mp, value)); + return -15; + } + msr->mpd->mpp->filename = value; + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Multipart: Content-Disposition filename: %s", + log_escape_nq(msr->mp, value)); + } + } + else return -11; + + if (*p != '\0') { + while((*p == '\t') || (*p == ' ')) p++; + /* the next character must be a zero or a semi-colon */ + if (*p == '\0') return 1; /* this is OK */ + if (*p != ';') return -12; + p++; /* move over the semi-colon */ + } + + /* loop will stop when (*p == '\0') */ + } + + return 1; +} + +/** + * + */ +static int multipart_process_part_header(modsec_rec *msr, char **error_msg) { + int i, len, rc; + + if (error_msg == NULL) return -1; + *error_msg = NULL; + + /* Check for nul bytes. */ + len = MULTIPART_BUF_SIZE - msr->mpd->bufleft; + for(i = 0; i < len; i++) { + if (msr->mpd->buf[i] == '\0') { + *error_msg = apr_psprintf(msr->mp, "Multipart: Nul byte in part headers."); + return -1; + } + } + + /* The buffer is data so increase the data length counter. */ + msr->msc_reqbody_no_files_length += (MULTIPART_BUF_SIZE - msr->mpd->bufleft); + + if (len > 1) { + if (msr->mpd->buf[len - 2] == '\r') { + msr->mpd->flag_crlf_line = 1; + } else { + msr->mpd->flag_lf_line = 1; + } + } else { + msr->mpd->flag_lf_line = 1; + } + + /* Is this an empty line? */ + if ( ((msr->mpd->buf[0] == '\r') + &&(msr->mpd->buf[1] == '\n') + &&(msr->mpd->buf[2] == '\0') ) + || ((msr->mpd->buf[0] == '\n') + &&(msr->mpd->buf[1] == '\0') ) ) + { /* Empty line. */ + char *header_value = NULL; + + header_value = (char *)apr_table_get(msr->mpd->mpp->headers, "Content-Disposition"); + if (header_value == NULL) { + *error_msg = apr_psprintf(msr->mp, "Multipart: Part missing Content-Disposition header."); + return -1; + } + + rc = multipart_parse_content_disposition(msr, header_value); + if (rc < 0) { + *error_msg = apr_psprintf(msr->mp, "Multipart: Invalid Content-Disposition header (%d): %s.", + rc, log_escape_nq(msr->mp, header_value)); + return -1; + } + + if (msr->mpd->mpp->name == NULL) { + *error_msg = apr_psprintf(msr->mp, "Multipart: Content-Disposition header missing name field."); + return -1; + } + + if (msr->mpd->mpp->filename != NULL) { + /* Some parsers use crude methods to extract the name and filename + * values from the C-D header. We need to check for the case where they + * didn't understand C-D but we did. + */ + if (strstr(header_value, "filename=") == NULL) { + *error_msg = apr_psprintf(msr->mp, "Multipart: Invalid Content-Disposition header (filename)."); + return -1; + } + + msr->mpd->mpp->type = MULTIPART_FILE; + } else { + msr->mpd->mpp->type = MULTIPART_FORMDATA; + } + + msr->mpd->mpp_state = 1; + msr->mpd->mpp->last_header_name = NULL; + } else { + /* Header line. */ + + if ((msr->mpd->buf[0] == '\t') || (msr->mpd->buf[0] == ' ')) { + char *header_value, *new_value, *data; + + /* header folding, add data to the header we are building */ + msr->mpd->flag_header_folding = 1; + + if (msr->mpd->mpp->last_header_name == NULL) { + /* we are not building a header at this moment */ + *error_msg = apr_psprintf(msr->mp, "Multipart: Invalid part header (folding error)."); + return -1; + } + + /* locate the beginning of data */ + data = msr->mpd->buf; + while((*data == '\t') || (*data == ' ')) data++; + + new_value = apr_pstrdup(msr->mp, data); + remove_lf_crlf_inplace(new_value); + + /* update the header value in the table */ + header_value = (char *)apr_table_get(msr->mpd->mpp->headers, msr->mpd->mpp->last_header_name); + new_value = apr_pstrcat(msr->mp, header_value, " ", new_value, NULL); + apr_table_set(msr->mpd->mpp->headers, msr->mpd->mpp->last_header_name, new_value); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Multipart: Continued folder header \"%s\" with \"%s\"", + log_escape(msr->mp, msr->mpd->mpp->last_header_name), + log_escape(msr->mp, data)); + } + + if (strlen(new_value) > MULTIPART_BUF_SIZE) { + *error_msg = apr_psprintf(msr->mp, "Multipart: Part header too long."); + return -1; + } + } else { + char *header_name, *header_value, *data; + + /* new header */ + + data = msr->mpd->buf; + while((*data != ':') && (*data != '\0')) data++; + if (*data == '\0') { + *error_msg = apr_psprintf(msr->mp, "Multipart: Invalid part header (colon missing): %s.", + log_escape_nq(msr->mp, msr->mpd->buf)); + return -1; + } + + /* extract header name */ + header_name = apr_pstrmemdup(msr->mp, msr->mpd->buf, (data - msr->mpd->buf)); + if (data == msr->mpd->buf) { + *error_msg = apr_psprintf(msr->mp, "Multipart: Invalid part header (header name missing)."); + + return -1; + } + + /* extract the value value */ + data++; + while((*data == '\t') || (*data == ' ')) data++; + header_value = apr_pstrdup(msr->mp, data); + remove_lf_crlf_inplace(header_value); + + /* error if the name already exists */ + if (apr_table_get(msr->mpd->mpp->headers, header_name) != NULL) { + *error_msg = apr_psprintf(msr->mp, "Multipart: Duplicate part header: %s.", + log_escape_nq(msr->mp, header_name)); + return -1; + } + + apr_table_setn(msr->mpd->mpp->headers, header_name, header_value); + msr->mpd->mpp->last_header_name = header_name; + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Multipart: Added part header \"%s\" \"%s\"", + log_escape(msr->mp, header_name), + log_escape(msr->mp, header_value)); + } + } + } + + return 1; +} + +/** + * + */ +static int multipart_process_part_data(modsec_rec *msr, char **error_msg) { + char *p = msr->mpd->buf + (MULTIPART_BUF_SIZE - msr->mpd->bufleft); + char localreserve[2] = { '\0', '\0' }; /* initialized to quiet warning */ + int bytes_reserved = 0; + + if (error_msg == NULL) return -1; + *error_msg = NULL; + + /* Preserve some bytes for later. */ + if ( ((MULTIPART_BUF_SIZE - msr->mpd->bufleft) >= 1) + && (*(p - 1) == '\n') ) + { + if ( ((MULTIPART_BUF_SIZE - msr->mpd->bufleft) >= 2) + && (*(p - 2) == '\r') ) + { + /* Two bytes. */ + bytes_reserved = 2; + localreserve[0] = *(p - 2); + localreserve[1] = *(p - 1); + msr->mpd->bufleft += 2; + *(p - 2) = 0; + } else { + /* Only one byte. */ + bytes_reserved = 1; + localreserve[0] = *(p - 1); + localreserve[1] = 0; + msr->mpd->bufleft += 1; + *(p - 1) = 0; + } + } + + /* add data to the part we are building */ + if (msr->mpd->mpp->type == MULTIPART_FILE) { + + /* remember where we started */ + if (msr->mpd->mpp->length == 0) { + msr->mpd->mpp->offset = msr->mpd->buf_offset; + } + + /* only store individual files on disk if we are going + * to keep them or if we need to have them approved later + */ + if (msr->upload_extract_files) { + /* first create a temporary file if we don't have it already */ + if (msr->mpd->mpp->tmp_file_fd == 0) { + /* construct temporary file name */ + msr->mpd->mpp->tmp_file_name = apr_psprintf(msr->mp, "%s/%s-%s-file-XXXXXX", + msr->txcfg->tmp_dir, current_filetime(msr->mp), msr->txid); + msr->mpd->mpp->tmp_file_fd = msc_mkstemp_ex(msr->mpd->mpp->tmp_file_name, msr->txcfg->upload_filemode); + + /* do we have an opened file? */ + if (msr->mpd->mpp->tmp_file_fd < 0) { + *error_msg = apr_psprintf(msr->mp, "Multipart: Failed to create file: %s", + log_escape_nq(msr->mp, msr->mpd->mpp->tmp_file_name)); + return -1; + } + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Multipart: Created temporary file: %s", + log_escape_nq(msr->mp, msr->mpd->mpp->tmp_file_name)); + } + } + + /* write the reserve first */ + if (msr->mpd->reserve[0] != 0) { + if (write(msr->mpd->mpp->tmp_file_fd, &msr->mpd->reserve[1], msr->mpd->reserve[0]) != msr->mpd->reserve[0]) { + *error_msg = apr_psprintf(msr->mp, "Multipart: writing to \"%s\" failed", + log_escape(msr->mp, msr->mpd->mpp->tmp_file_name)); + return -1; + } + + msr->mpd->mpp->tmp_file_size += msr->mpd->reserve[0]; + msr->mpd->mpp->length += msr->mpd->reserve[0]; + } + + /* write data to the file */ + if (write(msr->mpd->mpp->tmp_file_fd, msr->mpd->buf, MULTIPART_BUF_SIZE - msr->mpd->bufleft) + != (MULTIPART_BUF_SIZE - msr->mpd->bufleft)) + { + *error_msg = apr_psprintf(msr->mp, "Multipart: writing to \"%s\" failed", + log_escape(msr->mp, msr->mpd->mpp->tmp_file_name)); + return -1; + } + + msr->mpd->mpp->tmp_file_size += (MULTIPART_BUF_SIZE - msr->mpd->bufleft); + msr->mpd->mpp->length += (MULTIPART_BUF_SIZE - msr->mpd->bufleft); + } else { + /* just keep track of the file size */ + msr->mpd->mpp->tmp_file_size += (MULTIPART_BUF_SIZE - msr->mpd->bufleft) + msr->mpd->reserve[0]; + msr->mpd->mpp->length += (MULTIPART_BUF_SIZE - msr->mpd->bufleft) + msr->mpd->reserve[0]; + } + } + else if (msr->mpd->mpp->type == MULTIPART_FORMDATA) { + value_part_t *value_part = apr_pcalloc(msr->mp, sizeof(value_part_t)); + + /* The buffer contains data so increase the data length counter. */ + msr->msc_reqbody_no_files_length += (MULTIPART_BUF_SIZE - msr->mpd->bufleft) + msr->mpd->reserve[0]; + + /* add this part to the list of parts */ + + /* remember where we started */ + if (msr->mpd->mpp->length == 0) { + msr->mpd->mpp->offset = msr->mpd->buf_offset; + } + + if (msr->mpd->reserve[0] != 0) { + value_part->data = apr_palloc(msr->mp, (MULTIPART_BUF_SIZE - msr->mpd->bufleft) + msr->mpd->reserve[0]); + memcpy(value_part->data, &(msr->mpd->reserve[1]), msr->mpd->reserve[0]); + memcpy(value_part->data + msr->mpd->reserve[0], msr->mpd->buf, (MULTIPART_BUF_SIZE - msr->mpd->bufleft)); + + value_part->length = (MULTIPART_BUF_SIZE - msr->mpd->bufleft) + msr->mpd->reserve[0]; + msr->mpd->mpp->length += value_part->length; + } else { + value_part->length = (MULTIPART_BUF_SIZE - msr->mpd->bufleft); + value_part->data = apr_pstrmemdup(msr->mp, msr->mpd->buf, value_part->length); + msr->mpd->mpp->length += value_part->length; + } + + *(value_part_t **)apr_array_push(msr->mpd->mpp->value_parts) = value_part; + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Multipart: Added data to variable: %s", + log_escape_nq_ex(msr->mp, value_part->data, value_part->length)); + } + } + else { + *error_msg = apr_psprintf(msr->mp, "Multipart: unknown part type %d", msr->mpd->mpp->type); + return -1; + } + + /* store the reserved bytes to the multipart + * context so that they don't get lost + */ + if (bytes_reserved) { + msr->mpd->reserve[0] = bytes_reserved; + msr->mpd->reserve[1] = localreserve[0]; + msr->mpd->reserve[2] = localreserve[1]; + msr->mpd->buf_offset += bytes_reserved; + } + else { + msr->mpd->buf_offset -= msr->mpd->reserve[0]; + msr->mpd->reserve[0] = 0; + } + + return 1; +} + +/** + * + */ +static char *multipart_combine_value_parts(modsec_rec *msr, apr_array_header_t *value_parts) { + value_part_t **parts = NULL; + char *rval = apr_palloc(msr->mp, msr->mpd->mpp->length + 1); + unsigned long int offset; + int i; + + if (rval == NULL) return NULL; + + offset = 0; + parts = (value_part_t **)value_parts->elts; + for(i = 0; i < value_parts->nelts; i++) { + if (offset + parts[i]->length <= msr->mpd->mpp->length) { + memcpy(rval + offset, parts[i]->data, parts[i]->length); + offset += parts[i]->length; + } + } + rval[offset] = '\0'; + + return rval; +} + +/** + * + */ +static int multipart_process_boundary(modsec_rec *msr, int last_part, char **error_log) { + /* if there was a part being built finish it */ + if (msr->mpd->mpp != NULL) { + /* close the temp file */ + if ((msr->mpd->mpp->type == MULTIPART_FILE) + &&(msr->mpd->mpp->tmp_file_name != NULL) + &&(msr->mpd->mpp->tmp_file_fd != 0)) + { + close(msr->mpd->mpp->tmp_file_fd); + } + + if (msr->mpd->mpp->type != MULTIPART_FILE) { + /* now construct a single string out of the parts */ + msr->mpd->mpp->value = multipart_combine_value_parts(msr, msr->mpd->mpp->value_parts); + if (msr->mpd->mpp->value == NULL) return -1; + } + + if (msr->mpd->mpp->name) { + /* add the part to the list of parts */ + *(multipart_part **)apr_array_push(msr->mpd->parts) = msr->mpd->mpp; + if (msr->mpd->mpp->type == MULTIPART_FILE) { + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Multipart: Added file part %pp to the list: name \"%s\" " + "file name \"%s\" (offset %u, length %u)", + msr->mpd->mpp, log_escape(msr->mp, msr->mpd->mpp->name), + log_escape(msr->mp, msr->mpd->mpp->filename), + msr->mpd->mpp->offset, msr->mpd->mpp->length); + } + } + else { + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Multipart: Added part %pp to the list: name \"%s\" " + "(offset %u, length %u)", msr->mpd->mpp, log_escape(msr->mp, msr->mpd->mpp->name), + msr->mpd->mpp->offset, msr->mpd->mpp->length); + } + } + } + else { + msr_log(msr, 3, "Multipart: Skipping invalid part %pp (part name missing): " + "(offset %u, length %u)", msr->mpd->mpp, + msr->mpd->mpp->offset, msr->mpd->mpp->length); + } + + msr->mpd->mpp = NULL; + } + + if (last_part == 0) { + /* start building a new part */ + msr->mpd->mpp = (multipart_part *)apr_pcalloc(msr->mp, sizeof(multipart_part)); + if (msr->mpd->mpp == NULL) return -1; + msr->mpd->mpp->type = MULTIPART_FORMDATA; + msr->mpd->mpp_state = 0; + + msr->mpd->mpp->headers = apr_table_make(msr->mp, 10); + if (msr->mpd->mpp->headers == NULL) return -1; + msr->mpd->mpp->last_header_name = NULL; + + msr->mpd->reserve[0] = 0; + msr->mpd->reserve[1] = 0; + msr->mpd->reserve[2] = 0; + msr->mpd->reserve[3] = 0; + + msr->mpd->mpp->value_parts = apr_array_make(msr->mp, 10, sizeof(value_part_t *)); + } + + return 1; +} + +static int multipart_boundary_characters_valid(char *boundary) { + unsigned char *p = (unsigned char *)boundary; + unsigned char c; + + if (p == NULL) return -1; + + while((c = *p) != '\0') { + /* Control characters and space not allowed. */ + if (c < 32) { + return 0; + } + + /* Non-ASCII characters not allowed. */ + if (c > 126) { + return 0; + } + + switch(c) { + /* Special characters not allowed. */ + case '(' : + case ')' : + case '<' : + case '>' : + case '@' : + case ',' : + case ';' : + case ':' : + case '\\' : + case '"' : + case '/' : + case '[' : + case ']' : + case '?' : + case '=' : + return 0; + break; + + default : + /* Do nothing. */ + break; + } + + p++; + } + + return 1; +} + +static int multipart_count_boundary_params(apr_pool_t *mp, const char *header_value) { + char *duplicate = NULL; + char *s = NULL; + int count = 0; + + if (header_value == NULL) return -1; + duplicate = apr_pstrdup(mp, header_value); + if (duplicate == NULL) return -1; + + /* Performing a case-insensitive search. */ + strtolower_inplace((unsigned char *)duplicate); + + s = duplicate; + while((s = strstr(s, "boundary")) != NULL) { + s += 8; + + if (strchr(s, '=') != NULL) { + count++; + } + } + + return count; +} + +/** + * + */ +int multipart_init(modsec_rec *msr, char **error_msg) { + if (error_msg == NULL) return -1; + *error_msg = NULL; + + msr->mpd = (multipart_data *)apr_pcalloc(msr->mp, sizeof(multipart_data)); + if (msr->mpd == NULL) return -1; + + msr->mpd->parts = apr_array_make(msr->mp, 10, sizeof(multipart_part *)); + msr->mpd->bufleft = MULTIPART_BUF_SIZE; + msr->mpd->bufptr = msr->mpd->buf; + msr->mpd->buf_contains_line = 1; + msr->mpd->mpp = NULL; + + if (msr->request_content_type == NULL) { + msr->mpd->flag_error = 1; + *error_msg = apr_psprintf(msr->mp, "Multipart: Content-Type header not available."); + return -1; + } + + if (strlen(msr->request_content_type) > 1024) { + msr->mpd->flag_error = 1; + *error_msg = apr_psprintf(msr->mp, "Multipart: Invalid boundary in C-T (length)."); + return -1; + } + + if (strncasecmp(msr->request_content_type, "multipart/form-data", 19) != 0) { + msr->mpd->flag_error = 1; + *error_msg = apr_psprintf(msr->mp, "Multipart: Invalid MIME type."); + return -1; + } + + /* Count how many times the word "boundary" appears in the C-T header. */ + if (multipart_count_boundary_params(msr->mp, msr->request_content_type) > 1) { + msr->mpd->flag_error = 1; + *error_msg = apr_psprintf(msr->mp, "Multipart: Multiple boundary parameters in C-T."); + return -1; + } + + msr->mpd->boundary = strstr(msr->request_content_type, "boundary"); + if (msr->mpd->boundary != NULL) { + char *p = NULL; + char *b = NULL; + int seen_semicolon = 0; + int len = 0; + + /* Check for extra characters before the boundary. */ + for (p = (char *)(msr->request_content_type + 19); p < msr->mpd->boundary; p++) { + if (!isspace(*p)) { + if ((seen_semicolon == 0) && (*p == ';')) { + seen_semicolon = 1; /* It is OK to have one semicolon. */ + } else { + msr->mpd->flag_error = 1; + *error_msg = apr_psprintf(msr->mp, "Multipart: Invalid boundary in C-T (malformed)."); + return -1; + } + } + } + + /* Have we seen the semicolon in the header? */ + if (seen_semicolon == 0) { + msr->mpd->flag_missing_semicolon = 1; + } + + b = strchr(msr->mpd->boundary + 8, '='); + if (b == NULL) { + msr->mpd->flag_error = 1; + *error_msg = apr_psprintf(msr->mp, "Multipart: Invalid boundary in C-T (malformed)."); + return -1; + } + + /* Check parameter name ends well. */ + if (b != (msr->mpd->boundary + 8)) { + /* Check all characters between the end of the boundary + * and the = character. + */ + for (p = msr->mpd->boundary + 8; p < b; p++) { + if (isspace(*p)) { + /* Flag for whitespace after parameter name. */ + msr->mpd->flag_boundary_whitespace = 1; + } else { + msr->mpd->flag_error = 1; + *error_msg = apr_psprintf(msr->mp, "Multipart: Invalid boundary in C-T (parameter name)."); + return -1; + } + } + } + + b++; /* Go over the = character. */ + len = strlen(b); + + /* Flag for whitespace before parameter value. */ + if (isspace(*b)) { + msr->mpd->flag_boundary_whitespace = 1; + } + + /* Is the boundary quoted? */ + if ((len >= 2) && (*b == '"') && (*(b + len - 1) == '"')) { + /* Quoted. */ + msr->mpd->boundary = apr_pstrndup(msr->mp, b + 1, len - 2); + if (msr->mpd->boundary == NULL) return -1; + msr->mpd->flag_boundary_quoted = 1; + } else { + /* Not quoted. */ + + /* Test for partial quoting. */ + if ( (*b == '"') + || ((len >= 2) && (*(b + len - 1) == '"')) ) + { + msr->mpd->flag_error = 1; + *error_msg = apr_psprintf(msr->mp, "Multipart: Invalid boundary in C-T (quote)."); + return -1; + } + + msr->mpd->boundary = apr_pstrdup(msr->mp, b); + if (msr->mpd->boundary == NULL) return -1; + msr->mpd->flag_boundary_quoted = 0; + } + + /* Case-insensitive test for the string "boundary" in the boundary. */ + if (multipart_count_boundary_params(msr->mp, msr->mpd->boundary) != 0) { + msr->mpd->flag_error = 1; + *error_msg = apr_psprintf(msr->mp, "Multipart: Invalid boundary in C-T (content)."); + return -1; + } + + /* Validate the characters used in the boundary. */ + if (multipart_boundary_characters_valid(msr->mpd->boundary) != 1) { + msr->mpd->flag_error = 1; + *error_msg = apr_psprintf(msr->mp, "Multipart: Invalid boundary in C-T (characters)."); + return -1; + } + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Multipart: Boundary%s: %s", + (msr->mpd->flag_boundary_quoted ? " (quoted)" : ""), + log_escape_nq(msr->mp, msr->mpd->boundary)); + } + + if (strlen(msr->mpd->boundary) == 0) { + msr->mpd->flag_error = 1; + *error_msg = apr_psprintf(msr->mp, "Multipart: Invalid boundary in C-T (empty)."); + return -1; + } + } + else { /* Could not find boundary in the C-T header. */ + msr->mpd->flag_error = 1; + + /* Test for case-insensitive boundary. Allowed by the RFC but highly unusual. */ + if (multipart_count_boundary_params(msr->mp, msr->request_content_type) > 0) { + *error_msg = apr_psprintf(msr->mp, "Multipart: Invalid boundary in C-T (case sensitivity)."); + return -1; + } + + *error_msg = apr_psprintf(msr->mp, "Multipart: Boundary not found in C-T."); + return -1; + } + + return 1; +} + +/** + * Finalise multipart processing. This method is invoked at the end, when it + * is clear that there is no more data to be processed. + */ +int multipart_complete(modsec_rec *msr, char **error_msg) { + if (msr->mpd == NULL) return 1; + + if (msr->txcfg->debuglog_level >= 4) { + if (msr->mpd->flag_data_before) { + msr_log(msr, 4, "Multipart: Warning: seen data before first boundary."); + } + + if (msr->mpd->flag_data_after) { + msr_log(msr, 4, "Multipart: Warning: seen data after last boundary."); + } + + if (msr->mpd->flag_boundary_quoted) { + msr_log(msr, 4, "Multipart: Warning: boundary was quoted."); + } + + if (msr->mpd->flag_boundary_whitespace) { + msr_log(msr, 4, "Multipart: Warning: boundary whitespace in C-T header."); + } + + if (msr->mpd->flag_header_folding) { + msr_log(msr, 4, "Multipart: Warning: header folding used."); + } + + if (msr->mpd->flag_crlf_line && msr->mpd->flag_lf_line) { + msr_log(msr, 4, "Multipart: Warning: mixed line endings used (CRLF/LF)."); + } + else if (msr->mpd->flag_lf_line) { + msr_log(msr, 4, "Multipart: Warning: incorrect line endings used (LF)."); + } + + if (msr->mpd->flag_missing_semicolon) { + msr_log(msr, 4, "Multipart: Warning: missing semicolon in C-T header."); + } + } + + if ((msr->mpd->seen_data != 0) && (msr->mpd->is_complete == 0)) { + if (msr->mpd->boundary_count > 0) { + /* Check if we have the final boundary (that we haven't + * processed yet) in the buffer. + */ + if (msr->mpd->buf_contains_line) { + if ( ((unsigned int)(MULTIPART_BUF_SIZE - msr->mpd->bufleft) == (4 + strlen(msr->mpd->boundary))) + && (*(msr->mpd->buf) == '-') + && (*(msr->mpd->buf + 1) == '-') + && (strncmp(msr->mpd->buf + 2, msr->mpd->boundary, strlen(msr->mpd->boundary)) == 0) + && (*(msr->mpd->buf + 2 + strlen(msr->mpd->boundary)) == '-') + && (*(msr->mpd->buf + 2 + strlen(msr->mpd->boundary) + 1) == '-') ) + { + /* Looks like the final boundary - process it. */ + if (multipart_process_boundary(msr, 1 /* final */, error_msg) < 0) { + msr->mpd->flag_error = 1; + return -1; + } + + /* The payload is complete after all. */ + msr->mpd->is_complete = 1; + } + } + + if (msr->mpd->is_complete == 0) { + *error_msg = apr_psprintf(msr->mp, "Multipart: Final boundary missing."); + return -1; + } + } else { + *error_msg = apr_psprintf(msr->mp, "Multipart: No boundaries found in payload."); + return -1; + } + } + + return 1; +} + +/** + * + */ +int multipart_process_chunk(modsec_rec *msr, const char *buf, + unsigned int size, char **error_msg) +{ + char *inptr = (char *)buf; + unsigned int inleft = size; + + if (error_msg == NULL) return -1; + *error_msg = NULL; + + if (size == 0) return 1; + + msr->mpd->seen_data = 1; + + if (msr->mpd->is_complete) { + msr->mpd->flag_data_before = 1; + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Multipart: Ignoring data after last boundary (received %u bytes)", size); + } + + return 1; + } + + if (msr->mpd->bufleft == 0) { + msr->mpd->flag_error = 1; + *error_msg = apr_psprintf(msr->mp, + "Multipart: Internal error in process_chunk: no space left in the buffer"); + return -1; + } + + /* here we loop through the available data, one byte at a time */ + while(inleft > 0) { + char c = *inptr; + int process_buffer = 0; + + if ((c == '\r') && (msr->mpd->bufleft == 1)) { + /* we don't want to take \r as the last byte in the buffer */ + process_buffer = 1; + } else { + inptr++; + inleft = inleft - 1; + + *(msr->mpd->bufptr) = c; + msr->mpd->bufptr++; + msr->mpd->bufleft--; + } + + /* until we either reach the end of the line + * or the end of our internal buffer + */ + if ((c == '\n') || (msr->mpd->bufleft == 0) || (process_buffer)) { + int processed_as_boundary = 0; + + *(msr->mpd->bufptr) = 0; + + /* Do we have something that looks like a boundary? */ + if ( msr->mpd->buf_contains_line + && (strlen(msr->mpd->buf) > 3) + && (*(msr->mpd->buf) == '-') + && (*(msr->mpd->buf + 1) == '-') ) + { + /* Does it match our boundary? */ + if ( (strlen(msr->mpd->buf) >= strlen(msr->mpd->boundary) + 2) + && (strncmp(msr->mpd->buf + 2, msr->mpd->boundary, strlen(msr->mpd->boundary)) == 0) ) + { + char *boundary_end = msr->mpd->buf + 2 + strlen(msr->mpd->boundary); + int is_final = 0; + + /* Is this the final boundary? */ + if ((*boundary_end == '-') && (*(boundary_end + 1)== '-')) { + is_final = 1; + boundary_end += 2; + + if (msr->mpd->is_complete != 0) { + msr->mpd->flag_error = 1; + *error_msg = apr_psprintf(msr->mp, + "Multipart: Invalid boundary (final duplicate)."); + return -1; + } + } + + /* Allow for CRLF and LF line endings. */ + if ( ( (*boundary_end == '\r') + && (*(boundary_end + 1) == '\n') + && (*(boundary_end + 2) == '\0') ) + || ( (*boundary_end == '\n') + && (*(boundary_end + 1) == '\0') ) ) + { + if (*boundary_end == '\n') { + msr->mpd->flag_lf_line = 1; + } else { + msr->mpd->flag_crlf_line = 1; + } + + if (multipart_process_boundary(msr, (is_final ? 1 : 0), error_msg) < 0) { + msr->mpd->flag_error = 1; + return -1; + } + + if (is_final) { + msr->mpd->is_complete = 1; + } + + processed_as_boundary = 1; + msr->mpd->boundary_count++; + } + else { + /* error */ + msr->mpd->flag_error = 1; + *error_msg = apr_psprintf(msr->mp, + "Multipart: Invalid boundary: %s", + log_escape_nq(msr->mp, msr->mpd->buf)); + return -1; + } + } else { /* It looks like a boundary but we couldn't match it. */ + char *p = NULL; + + /* Check if an attempt to use quotes around the boundary was made. */ + if ( (msr->mpd->flag_boundary_quoted) + && (strlen(msr->mpd->buf) >= strlen(msr->mpd->boundary) + 3) + && (*(msr->mpd->buf + 2) == '"') + && (strncmp(msr->mpd->buf + 3, msr->mpd->boundary, strlen(msr->mpd->boundary)) == 0) + ) { + msr->mpd->flag_error = 1; + *error_msg = apr_psprintf(msr->mp, "Multipart: Invalid boundary (quotes)."); + return -1; + } + + /* Check the beginning of the boundary for whitespace. */ + p = msr->mpd->buf + 2; + while(isspace(*p)) { + p++; + } + + if ( (p != msr->mpd->buf + 2) + && (strncmp(p, msr->mpd->boundary, strlen(msr->mpd->boundary)) == 0) + ) { + /* Found whitespace in front of a boundary. */ + msr->mpd->flag_error = 1; + *error_msg = apr_psprintf(msr->mp, "Multipart: Invalid boundary (whitespace)."); + return -1; + } + + msr->mpd->flag_unmatched_boundary = 1; + } + } else { /* We do not think the buffer contains a boundary. */ + /* Look into the buffer to see if there's anything + * there that resembles a boundary. + */ + if (msr->mpd->buf_contains_line) { + int i, len = (MULTIPART_BUF_SIZE - msr->mpd->bufleft); + char *p = msr->mpd->buf; + + for(i = 0; i < len; i++) { + if ((p[i] == '-') && (i + 1 < len) && (p[i + 1] == '-')) + { + if (strncmp(p + i + 2, msr->mpd->boundary, strlen(msr->mpd->boundary)) == 0) { + msr->mpd->flag_unmatched_boundary = 1; + break; + } + } + } + } + } + + /* Process as data if it was not a boundary. */ + if (processed_as_boundary == 0) { + if (msr->mpd->mpp == NULL) { + msr->mpd->flag_data_before = 1; + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Multipart: Ignoring data before first boundary."); + } + } else { + if (msr->mpd->mpp_state == 0) { + if ((msr->mpd->bufleft == 0) || (process_buffer)) { + /* part header lines must be shorter than + * MULTIPART_BUF_SIZE bytes + */ + msr->mpd->flag_error = 1; + *error_msg = apr_psprintf(msr->mp, + "Multipart: Part header line over %d bytes long", + MULTIPART_BUF_SIZE); + return -1; + } + + if (multipart_process_part_header(msr, error_msg) < 0) { + msr->mpd->flag_error = 1; + return -1; + } + } else { + if (multipart_process_part_data(msr, error_msg) < 0) { + msr->mpd->flag_error = 1; + return -1; + } + } + } + } + + /* Update the offset of the data we are about + * to process. This is to allow us to know the + * offsets of individual files and variables. + */ + msr->mpd->buf_offset += (MULTIPART_BUF_SIZE - msr->mpd->bufleft); + + /* reset the pointer to the beginning of the buffer + * and continue to accept input data + */ + msr->mpd->bufptr = msr->mpd->buf; + msr->mpd->bufleft = MULTIPART_BUF_SIZE; + msr->mpd->buf_contains_line = (c == 0x0a) ? 1 : 0; + } + + if ((msr->mpd->is_complete) && (inleft != 0)) { + msr->mpd->flag_data_after = 1; + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Multipart: Ignoring data after last boundary (%u bytes left)", inleft); + } + + return 1; + } + } + + return 1; +} + +/** + * + */ +apr_status_t multipart_cleanup(modsec_rec *msr) { + int keep_files = 0; + + if (msr->mpd == NULL) return -1; + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Multipart: Cleanup started (remove files %d).", msr->upload_remove_files); + } + + if (msr->upload_remove_files == 0) { + if (msr->txcfg->upload_dir == NULL) { + msr_log(msr, 1, "Input filter: SecUploadDir is undefined, unable to store " + "multipart files."); + } else { + keep_files = 1; + } + } + + /* Loop through the list of parts + * and delete the temporary files, but only if + * file storage was not requested, or if storage + * of relevant files was requested and this isn't + * such a request. + */ + if (keep_files == 0) { + multipart_part **parts; + int i; + + parts = (multipart_part **)msr->mpd->parts->elts; + for(i = 0; i < msr->mpd->parts->nelts; i++) { + if (parts[i]->type == MULTIPART_FILE) { + if (parts[i]->tmp_file_name != NULL) { + /* make sure it is closed first */ + if (parts[i]->tmp_file_fd > 0) { + close(parts[i]->tmp_file_fd); + parts[i]->tmp_file_fd = -1; + } + + if (unlink(parts[i]->tmp_file_name) < 0) { + msr_log(msr, 1, "Multipart: Failed to delete file (part) \"%s\" because %d(%s)", + log_escape(msr->mp, parts[i]->tmp_file_name), errno, strerror(errno)); + } else { + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Multipart: Deleted file (part) \"%s\"", + log_escape(msr->mp, parts[i]->tmp_file_name)); + } + } + } + } + } + } else { + /* delete empty files, move the others to the upload dir */ + multipart_part **parts; + int i; + + parts = (multipart_part **)msr->mpd->parts->elts; + for(i = 0; i < msr->mpd->parts->nelts; i++) { + if ( (parts[i]->type == MULTIPART_FILE) + && (parts[i]->tmp_file_size == 0)) + { + /* Delete empty file. */ + if (parts[i]->tmp_file_name != NULL) { + /* make sure it is closed first */ + if (parts[i]->tmp_file_fd > 0) { + close(parts[i]->tmp_file_fd); + parts[i]->tmp_file_fd = -1; + } + + if (unlink(parts[i]->tmp_file_name) < 0) { + msr_log(msr, 1, "Multipart: Failed to delete empty file (part) \"%s\" because %d(%s)", + log_escape(msr->mp, parts[i]->tmp_file_name), errno, strerror(errno)); + } else { + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Multipart: Deleted empty file (part) \"%s\"", + log_escape(msr->mp, parts[i]->tmp_file_name)); + } + } + } + } else { + /* Move file to the upload dir. */ + if (parts[i]->tmp_file_name != NULL) { + const char *new_filename = NULL; + const char *new_basename = NULL; + + /* make sure it is closed first */ + if (parts[i]->tmp_file_fd > 0) { + close(parts[i]->tmp_file_fd); + parts[i]->tmp_file_fd = -1; + } + + new_basename = file_basename(msr->mp, parts[i]->tmp_file_name); + if (new_basename == NULL) return -1; + new_filename = apr_psprintf(msr->mp, "%s/%s", msr->txcfg->upload_dir, + new_basename); + if (new_filename == NULL) return -1; + + if (apr_file_rename(parts[i]->tmp_file_name, new_filename, + msr->msc_reqbody_mp) != APR_SUCCESS) + { + msr_log(msr, 1, "Input filter: Failed to rename file from \"%s\" to \"%s\".", + log_escape(msr->mp, parts[i]->tmp_file_name), + log_escape(msr->mp, new_filename)); + return -1; + } else { + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Input filter: Moved file from \"%s\" to \"%s\".", + log_escape(msr->mp, parts[i]->tmp_file_name), + log_escape(msr->mp, new_filename)); + } + } + } + } + } + } + + return 1; +} + +/** + * + */ +int multipart_get_arguments(modsec_rec *msr, char *origin, apr_table_t *arguments) { + multipart_part **parts; + int i; + + parts = (multipart_part **)msr->mpd->parts->elts; + for(i = 0; i < msr->mpd->parts->nelts; i++) { + if (parts[i]->type == MULTIPART_FORMDATA) { + msc_arg *arg = (msc_arg *)apr_pcalloc(msr->mp, sizeof(msc_arg)); + if (arg == NULL) return -1; + + arg->name = parts[i]->name; + arg->name_len = strlen(parts[i]->name); + arg->value = parts[i]->value; + arg->value_len = parts[i]->length; + arg->value_origin_offset = parts[i]->offset; + arg->value_origin_len = parts[i]->length; + arg->origin = origin; + + add_argument(msr, arguments, arg); + } + } + + return 1; +} + +/** + * + */ +char *multipart_reconstruct_urlencoded_body_sanitise(modsec_rec *msr) { + multipart_part **parts; + char *body; + unsigned int body_len; + int i; + + if (msr->mpd == NULL) return NULL; + + /* calculate the size of the buffer */ + body_len = 1; + parts = (multipart_part **)msr->mpd->parts->elts; + for(i = 0; i < msr->mpd->parts->nelts; i++) { + if (parts[i]->type == MULTIPART_FORMDATA) { + body_len += 4; + body_len += strlen(parts[i]->name) * 3; + body_len += strlen(parts[i]->value) * 3; + } + } + + /* allocate the buffer */ + body = apr_palloc(msr->mp, body_len + 1); + if ((body == NULL) || (body_len + 1 == 0)) return NULL; + *body = 0; + + parts = (multipart_part **)msr->mpd->parts->elts; + for(i = 0; i < msr->mpd->parts->nelts; i++) { + if (parts[i]->type == MULTIPART_FORMDATA) { + if (*body != 0) { + strncat(body, "&", body_len - strlen(body)); + } + strnurlencat(body, parts[i]->name, body_len - strlen(body)); + strncat(body, "=", body_len - strlen(body)); + + /* Sanitise the variable. Since we are only doing this for + * the logging we will actually write over the data we keep + * in the memory. + */ + if (msr->phase >= PHASE_LOGGING) { + if (apr_table_get(msr->arguments_to_sanitise, parts[i]->name) != NULL) { + memset(parts[i]->value, '*', strlen(parts[i]->value)); + } + } + strnurlencat(body, parts[i]->value, body_len - strlen(body)); + } + } + + return body; +} diff --git a/apache2/msc_multipart.h b/apache2/msc_multipart.h new file mode 100644 index 0000000..1cd4888 --- /dev/null +++ b/apache2/msc_multipart.h @@ -0,0 +1,139 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ +#ifndef _MSC_MULTIPART_H_ +#define _MSC_MULTIPART_H_ + +#define MULTIPART_BUF_SIZE 4096 + +#define MULTIPART_FORMDATA 1 +#define MULTIPART_FILE 2 + +typedef struct multipart_part multipart_part; +typedef struct multipart_data multipart_data; + +#include "apr_general.h" +#include "apr_tables.h" +#include "modsecurity.h" + +typedef struct value_part_t value_part_t; +struct value_part_t { + char *data; + long int length; +}; + +struct multipart_part { + /* part type, can be MULTIPART_FORMDATA or MULTIPART_FILE */ + int type; + /* the name */ + char *name; + + /* variables only, variable value */ + char *value; + apr_array_header_t *value_parts; + + /* files only, the content type (where available) */ + char *content_type; + + /* files only, the name of the temporary file holding data */ + char *tmp_file_name; + int tmp_file_fd; + unsigned int tmp_file_size; + /* files only, filename as supplied by the browser */ + char *filename; + + char *last_header_name; + apr_table_t *headers; + + unsigned int offset; + unsigned int length; +}; + +struct multipart_data { + /* this array keeps parts */ + apr_array_header_t *parts; + + /* mime boundary used to detect when + * parts end and begin + */ + char *boundary; + int boundary_count; + + /* internal buffer and other variables + * used while parsing + */ + char buf[MULTIPART_BUF_SIZE + 2]; + int buf_contains_line; + char *bufptr; + int bufleft; + + unsigned int buf_offset; + + /* pointer that keeps track of a part while + * it is being built + */ + multipart_part *mpp; + + + /* part parsing state; 0 means we are reading + * headers, 1 means we are collecting data + */ + int mpp_state; + + /* because of the way this parsing algorithm + * works we hold back the last two bytes of + * each data chunk so that we can discard it + * later if the next data chunk proves to be + * a boundary; the first byte is an indicator + * 0 - no content, 1 - two data bytes available + */ + char reserve[4]; + + int seen_data; + int is_complete; + + int flag_error; + int flag_data_before; + int flag_data_after; + int flag_header_folding; + int flag_boundary_quoted; + int flag_lf_line; + int flag_crlf_line; + int flag_unmatched_boundary; + int flag_boundary_whitespace; + int flag_missing_semicolon; + int flag_invalid_quoting; +}; + + +/* Functions */ + +int DSOLOCAL multipart_init(modsec_rec *msr, char **error_msg); + +int DSOLOCAL multipart_complete(modsec_rec *msr, char **error_msg); + +int DSOLOCAL multipart_process_chunk(modsec_rec *msr, const char *buf, + unsigned int size, char **error_msg); + +apr_status_t DSOLOCAL multipart_cleanup(modsec_rec *msr); + +int DSOLOCAL multipart_get_arguments(modsec_rec *msr, char *origin, apr_table_t *arguments); + +char DSOLOCAL *multipart_reconstruct_urlencoded_body_sanitise(modsec_rec *msr); + +#endif diff --git a/apache2/msc_parsers.c b/apache2/msc_parsers.c new file mode 100644 index 0000000..3b8e90f --- /dev/null +++ b/apache2/msc_parsers.c @@ -0,0 +1,334 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ +#include "msc_parsers.h" +#include + +/** + * + */ +int parse_cookies_v0(modsec_rec *msr, char *_cookie_header, apr_table_t *cookies) { + char *attr_name = NULL, *attr_value = NULL; + char *cookie_header; + char *saveptr = NULL; + int cookie_count = 0; + char *p = NULL; + + if (_cookie_header == NULL) { + msr_log(msr, 1, "Cookie parser: Received null for argument."); + return -1; + } + + cookie_header = strdup(_cookie_header); + if (cookie_header == NULL) return -1; + + p = apr_strtok(cookie_header, ";", &saveptr); + while(p != NULL) { + attr_name = NULL; + attr_value = NULL; + + /* ignore whitespace at the beginning of cookie name */ + while(isspace(*p)) p++; + attr_name = p; + + attr_value = strstr(p, "="); + if (attr_value != NULL) { + /* terminate cookie name */ + *attr_value = 0; + /* move over to the beginning of the value */ + attr_value++; + } + + /* we ignore cookies with empty names */ + if ((attr_name != NULL)&&(strlen(attr_name) != 0)) { + if (attr_value != NULL) { + if (msr->txcfg->debuglog_level >= 5) { + msr_log(msr, 5, "Adding request cookie: name \"%s\", value \"%s\"", + log_escape(msr->mp, attr_name), log_escape(msr->mp, attr_value)); + } + + apr_table_add(cookies, attr_name, attr_value); + } else { + if (msr->txcfg->debuglog_level >= 5) { + msr_log(msr, 5, "Adding request cookie: name \"%s\", value empty", + log_escape(msr->mp, attr_name)); + } + + apr_table_add(cookies, attr_name, ""); + } + + cookie_count++; + } + + p = apr_strtok(NULL, ";", &saveptr); + } + + free(cookie_header); + return cookie_count; +} + +/** + * + */ +int parse_cookies_v1(modsec_rec *msr, char *_cookie_header, apr_table_t *cookies) { + char *attr_name = NULL, *attr_value = NULL, *p = NULL; + char *prev_attr_name = NULL; + char *cookie_header = NULL; + int cookie_count = 0; + + if (_cookie_header == NULL) return -1; + cookie_header = strdup(_cookie_header); + if (cookie_header == NULL) return -1; + + p = cookie_header; + while(*p != 0) { + attr_name = NULL; + attr_value = NULL; + + /* attribute name */ + + /* remove space from the beginning */ + while((isspace(*p))&&(*p != 0)) p++; + attr_name = p; + while((*p != 0)&&(*p != '=')&&(*p != ';')&&(*p != ',')) p++; + + /* if we've reached the end of string */ + if (*p == 0) goto add_cookie; + + /* if there is no cookie value supplied */ + if ((*p == ';')||(*p == ',')) { + *p++ = 0; /* terminate the name */ + goto add_cookie; + } + + /* terminate the attribute name, + * writing over the = character + */ + *p++ = 0; + + /* attribute value */ + + /* skip over the whitespace at the beginning */ + while((isspace(*p))&&(*p != 0)) p++; + + /* no value supplied */ + if (*p == 0) goto add_cookie; + + if (*p == '"') { + if (*++p == 0) goto add_cookie; + attr_value = p; + while((*p != 0)&&(*p != '"')) p++; + if (*p != 0) *p++ = 0; + else { + /* Do nothing about this. */ + } + } else { + attr_value = p; + while((*p != 0)&&(*p != ',')&&(*p != ';')) p++; + if (*p != 0) *p++ = 0; + + /* remove the whitespace from the end of cookie value */ + if (attr_value != NULL) { + char *t = attr_value; + int i = 0; + + while(*t != 0) { + t++; + i++; + } + + while((i-- > 0)&&(isspace(*(--t)))) *t = 0; + } + } + + add_cookie: + + /* remove the whitespace from the end of cookie name */ + if (attr_name != NULL) { + char *t = attr_name; + int i = 0; + + while(*t != 0) { + t++; + i++; + } + + while((i-- > 0)&&(isspace(*(--t)))) *t = 0; + } + + /* add the cookie to the list now */ + if ((attr_name != NULL)&&(strlen(attr_name) != 0)) { + + /* handle special attribute names */ + if (attr_name[0] == '$') { + if (prev_attr_name != NULL) { + /* cookie keyword, we change the name we use + * so they can have a unique name in the cookie table + */ + attr_name = apr_psprintf(msr->mp, "$%s_%s", prev_attr_name, attr_name + 1); + } + } + + if (attr_value != NULL) { + if (msr->txcfg->debuglog_level >= 5) { + msr_log(msr, 5, "Adding request cookie: name \"%s\", value \"%s\"", + log_escape(msr->mp, attr_name), log_escape(msr->mp, attr_value)); + } + + apr_table_add(cookies, attr_name, attr_value); + } else { + if (msr->txcfg->debuglog_level >= 5) { + msr_log(msr, 5, "Adding request cookie: name \"%s\", value empty", + log_escape(msr->mp, attr_name)); + } + + apr_table_add(cookies, attr_name, ""); + } + + cookie_count++; + + /* only keep the cookie names for later */ + if (attr_name[0] != '$') prev_attr_name = attr_name; + } + + /* at this point the *p is either 0 (in which case we exit), or + * right after the current cookie ended - we need to look for + * the next cookie + */ + while( (*p != 0)&&( (*p == ',')||(*p == ';')||(isspace(*p)) ) ) p++; + } + + return cookie_count; +} + +/** + * + */ +int parse_arguments(modsec_rec *msr, const char *s, apr_size_t inputlength, + int argument_separator, const char *origin, + apr_table_t *arguments, int *invalid_count) +{ + msc_arg *arg; + apr_size_t i, j; + char *value = NULL; + char *buf; + int status; + int changed; + + if (s == NULL) return -1; + if (inputlength == 0) return 1; + + /* Check that adding one will not overflow */ + if (inputlength + 1 <= 0) return -1; + + buf = (char *)malloc(inputlength + 1); + if (buf == NULL) return -1; + + arg = (msc_arg *)apr_pcalloc(msr->mp, sizeof(msc_arg)); + arg->origin = origin; + + i = 0; + j = 0; + status = 0; + *invalid_count = 0; + while (i < inputlength) { + if (status == 0) { + /* parameter name */ + arg->name_origin_offset = i; + while ((s[i] != '=') && (s[i] != argument_separator) && (i < inputlength)) { + buf[j] = s[i]; + j++; + i++; + } + buf[j++] = '\0'; + arg->name_origin_len = i - arg->name_origin_offset; + } else { + /* parameter value */ + arg->value_origin_offset = i; + while ((s[i] != argument_separator) && (i < inputlength)) { + buf[j] = s[i]; + j++; + i++; + } + buf[j++] = '\0'; + arg->value_origin_len = i - arg->value_origin_offset; + } + + if (status == 0) { + arg->name_len = urldecode_nonstrict_inplace_ex((unsigned char *)buf, arg->name_origin_len, invalid_count, &changed); + arg->name = apr_pstrmemdup(msr->mp, buf, arg->name_len); + + if (s[i] == argument_separator) { + /* Empty parameter */ + arg->value_len = 0; + arg->value = ""; + + add_argument(msr, arguments, arg); + + arg = (msc_arg *)apr_pcalloc(msr->mp, sizeof(msc_arg)); + arg->origin = origin; + + status = 0; /* unchanged */ + j = 0; + } else { + status = 1; + value = &buf[j]; + } + } + else { + arg->value_len = urldecode_nonstrict_inplace_ex((unsigned char *)value, arg->value_origin_len, invalid_count, &changed); + arg->value = apr_pstrmemdup(msr->mp, value, arg->value_len); + + add_argument(msr, arguments, arg); + + arg = (msc_arg *)apr_pcalloc(msr->mp, sizeof(msc_arg)); + arg->origin = origin; + + status = 0; + j = 0; + } + + i++; /* skip over the separator */ + } + + /* the last parameter was empty */ + if (status == 1) { + arg->value_len = 0; + arg->value = ""; + + add_argument(msr, arguments, arg); + } + + free(buf); + + return 1; +} + +/** + * + */ +void add_argument(modsec_rec *msr, apr_table_t *arguments, msc_arg *arg) { + if (msr->txcfg->debuglog_level >= 5) { + msr_log(msr, 5, "Adding request argument (%s): name \"%s\", value \"%s\"", + arg->origin, log_escape_ex(msr->mp, arg->name, arg->name_len), + log_escape_ex(msr->mp, arg->value, arg->value_len)); + } + + apr_table_addn(arguments, log_escape_nq_ex(msr->mp, arg->name, arg->name_len), (void *)arg); +} + diff --git a/apache2/msc_parsers.h b/apache2/msc_parsers.h new file mode 100644 index 0000000..9a55dd7 --- /dev/null +++ b/apache2/msc_parsers.h @@ -0,0 +1,33 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ +#ifndef _MSC_PARSERS_H_ +#define _MSC_PARSERS_H_ + +#include "modsecurity.h" + +int DSOLOCAL parse_cookies_v0(modsec_rec *msr, char *_cookie_header, apr_table_t *cookies); + +int DSOLOCAL parse_cookies_v1(modsec_rec *msr, char *_cookie_header, apr_table_t *cookies); + +int DSOLOCAL parse_arguments(modsec_rec *msr, const char *s, apr_size_t inputlength, + int argument_separator, const char *origin, apr_table_t *arguments, int *invalid_count); + +void DSOLOCAL add_argument(modsec_rec *msr, apr_table_t *arguments, msc_arg *arg); + +#endif diff --git a/apache2/msc_pcre.c b/apache2/msc_pcre.c new file mode 100644 index 0000000..2281dbd --- /dev/null +++ b/apache2/msc_pcre.c @@ -0,0 +1,121 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ +#include "msc_pcre.h" +#include "apr_strings.h" + +/** + * Releases the resources used by a single regular expression pattern. + */ +apr_status_t msc_pcre_cleanup(msc_regex_t *regex) { + if (regex != NULL) { + if (regex->pe != NULL) { + free(regex->pe); + regex->pe = NULL; + } + if (regex->re != NULL) { + free(regex->re); + regex->re = NULL; + } + } + + return APR_SUCCESS; +} + +/** + * Compiles the provided regular expression pattern. The last two + * parameters are optional, but if they are provided and an error + * occurs they will contain the error message and the offset in + * the pattern where the offending part of the pattern begins. + */ +void *msc_pregcomp(apr_pool_t *pool, const char *pattern, int options, + const char **_errptr, int *_erroffset) +{ + const char *errptr = NULL; + int erroffset; + msc_regex_t *regex; + + regex = apr_pcalloc(pool, sizeof(msc_regex_t)); + if (regex == NULL) return NULL; + regex->pattern = pattern; + + if ((_errptr == NULL)||(_erroffset == NULL)) { + regex->re = pcre_compile(pattern, options, &errptr, &erroffset, NULL); + } else { + regex->re = pcre_compile(pattern, options, _errptr, _erroffset, NULL); + } + if (regex->re == NULL) return NULL; + + #ifdef WITH_PCRE_STUDY + regex->pe = pcre_study(regex->re, 0, &errptr); + #endif + + apr_pool_cleanup_register(pool, (void *)regex, + (apr_status_t (*)(void *))msc_pcre_cleanup, apr_pool_cleanup_null); + + return regex; +} + +/** + * Executes regular expression with extended options. + * Returns PCRE_ERROR_NOMATCH when there is no match, error code < -1 + * on errors, and a value > 0 when there is a match. + */ +int msc_regexec_ex(msc_regex_t *regex, const char *s, unsigned int slen, + int startoffset, int options, int *ovector, int ovecsize, char **error_msg) +{ + if (error_msg == NULL) return -1000; /* To differentiate from PCRE as it already uses -1. */ + *error_msg = NULL; + + return pcre_exec(regex->re, regex->pe, s, slen, startoffset, options, ovector, ovecsize); +} + +/** + * Executes regular expression, capturing subexpressions in the given + * vector. Returns PCRE_ERROR_NOMATCH when there is no match, error code < -1 + * on errors, and a value > 0 when there is a match. + */ +int msc_regexec_capture(msc_regex_t *regex, const char *s, unsigned int slen, + int *ovector, int ovecsize, char **error_msg) +{ + if (error_msg == NULL) return -1000; /* To differentiate from PCRE as it already uses -1. */ + *error_msg = NULL; + + return msc_regexec_ex(regex, s, slen, 0, 0, ovector, ovecsize, error_msg); +} + +/** + * Executes regular expression but ignores any of the subexpression + * captures. See above for the return codes. + */ +int msc_regexec(msc_regex_t *regex, const char *s, unsigned int slen, + char **error_msg) +{ + if (error_msg == NULL) return -1000; /* To differentiate from PCRE as it already uses -1. */ + *error_msg = NULL; + + return msc_regexec_ex(regex, s, slen, 0, 0, NULL, 0, error_msg); +} + +/** + * Gets info on a compiled regex. + */ +int msc_fullinfo(msc_regex_t *regex, int what, void *where) +{ + return pcre_fullinfo(regex->re, regex->pe, what, where); +} diff --git a/apache2/msc_pcre.h b/apache2/msc_pcre.h new file mode 100644 index 0000000..7c0a01c --- /dev/null +++ b/apache2/msc_pcre.h @@ -0,0 +1,50 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ +#ifndef _MSC_PCRE_H_ +#define _MSC_PCRE_H_ + +typedef struct msc_regex_t msc_regex_t; + +#include "pcre.h" +#include "apr_general.h" +#include "modsecurity.h" + +struct msc_regex_t { + void *re; + void *pe; + const char *pattern; +}; + +apr_status_t DSOLOCAL msc_pcre_cleanup(msc_regex_t *regex); + +void DSOLOCAL *msc_pregcomp(apr_pool_t *pool, const char *pattern, int options, + const char **_errptr, int *_erroffset); + +int DSOLOCAL msc_regexec_ex(msc_regex_t *regex, const char *s, unsigned int slen, + int startoffset, int options, int *ovector, int ovecsize, char **error_msg); + +int DSOLOCAL msc_regexec_capture(msc_regex_t *regex, const char *s, + unsigned int slen, int *ovector, int ovecsize, char **error_msg); + +int DSOLOCAL msc_regexec(msc_regex_t *regex, const char *s, unsigned int slen, + char **error_msg); + +int DSOLOCAL msc_fullinfo(msc_regex_t *regex, int what, void *where); + +#endif diff --git a/apache2/msc_release.c b/apache2/msc_release.c new file mode 100644 index 0000000..9513f59 --- /dev/null +++ b/apache2/msc_release.c @@ -0,0 +1,42 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ + +#include "msc_release.h" + +modsec_build_type_rec modsec_build_type[] = { + { "-dev", 1 }, /* Development build */ + { "-rc", 3 }, /* Release Candidate build */ + { "", 9 }, /* Production build */ + { "-breach", 9 }, /* Breach build */ + { "-trunk", 9 }, /* Trunk build */ + { NULL, -1 } /* terminator */ +}; + +int get_modsec_build_type(const char *name) +{ + int i; + + for (i = 0; modsec_build_type[i].name != NULL; i++) { + if (strcmp(((name == NULL) ? MODSEC_VERSION_TYPE : name), modsec_build_type[i].name) == 0) { + return modsec_build_type[i].val; + } + } + + return 9; /* so no warning */ +} diff --git a/apache2/msc_release.h b/apache2/msc_release.h new file mode 100644 index 0000000..efd32ba --- /dev/null +++ b/apache2/msc_release.h @@ -0,0 +1,68 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ +#ifndef _MSC_RELEASE_H_ +#define _MSC_RELEASE_H_ + +#include +#include + +/* ENH: Clean this mess up by detecting this is possible */ +#if !(defined(_AIX) || defined(WIN32) || defined(CYGWIN) || defined(NETWARE) || defined(SOLARIS2) || defined(OSF1)) +#define DSOLOCAL __attribute__((visibility("hidden"))) +#else +#define DSOLOCAL +#endif + +#if defined(DEBUG_MEM) +/* Nothing Yet */ +#endif + +/* For GNU C, tell the compiler to check printf like formatters */ +#if (defined(__GNUC__) && !defined(SOLARIS2)) +#define PRINTF_ATTRIBUTE(a,b) __attribute__((format (printf, a, b))) +#else +#define PRINTF_ATTRIBUTE(a,b) +#endif + +typedef struct modsec_build_type_rec { + const char * name; + int val; +} modsec_build_type_rec; +extern DSOLOCAL modsec_build_type_rec modsec_build_type[]; + +#define MODSEC_VERSION_MAJOR "2" +#define MODSEC_VERSION_MINOR "5" +#define MODSEC_VERSION_MAINT "11" +#define MODSEC_VERSION_TYPE "" +#define MODSEC_VERSION_RELEASE "" + +#define MODSEC_VERSION_SUFFIX MODSEC_VERSION_TYPE MODSEC_VERSION_RELEASE + +#define MODSEC_VERSION \ + MODSEC_VERSION_MAJOR "." MODSEC_VERSION_MINOR "." MODSEC_VERSION_MAINT \ + MODSEC_VERSION_SUFFIX + +/* Apache Module Defines */ +#define MODSEC_MODULE_NAME "ModSecurity for Apache" +#define MODSEC_MODULE_VERSION MODSEC_VERSION +#define MODSEC_MODULE_NAME_FULL MODSEC_MODULE_NAME "/" MODSEC_MODULE_VERSION " (http://www.modsecurity.org/)" + +int DSOLOCAL get_modsec_build_type(const char *name); + +#endif /* _MSC_RELEASE_H_ */ diff --git a/apache2/msc_reqbody.c b/apache2/msc_reqbody.c new file mode 100644 index 0000000..9fc629e --- /dev/null +++ b/apache2/msc_reqbody.c @@ -0,0 +1,760 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ +#include "modsecurity.h" +#include "msc_parsers.h" + +#define CHUNK_CAPACITY 8192 + +/** + * Prepare to accept the request body (part 2). + */ +static apr_status_t modsecurity_request_body_start_init(modsec_rec *msr, char **error_msg) { + *error_msg = NULL; + + if(msr->msc_reqbody_storage == MSC_REQBODY_MEMORY) { + /* Prepare to store request body in memory. */ + + msr->msc_reqbody_chunks = apr_array_make(msr->msc_reqbody_mp, + 32, sizeof(msc_data_chunk *)); + if (msr->msc_reqbody_chunks == NULL) { + *error_msg = apr_pstrdup(msr->mp, "Input filter: Failed to prepare in-memory storage."); + return -1; + } + } else { + /* Prepare to store request body on disk. */ + + msr->msc_reqbody_filename = apr_psprintf(msr->mp, "%s/%s-%s-request_body-XXXXXX", + msr->txcfg->tmp_dir, current_filetime(msr->mp), msr->txid); + if (msr->msc_reqbody_filename == NULL) { + *error_msg = apr_pstrdup(msr->mp, "Input filter: Failed to generate an on-disk filename."); + return -1; + } + + msr->msc_reqbody_fd = msc_mkstemp((char *)msr->msc_reqbody_filename); + if (msr->msc_reqbody_fd < 0) { + *error_msg = apr_psprintf(msr->mp, "Input filter: Failed to create temporary file: %s", + msr->msc_reqbody_filename); + return -1; + } + + msr_log(msr, 4, "Input filter: Created temporary file to store request body: %s", + msr->msc_reqbody_filename); + } + + return 1; +} + +/** + * Prepare to accept the request body (part 1). + */ +apr_status_t modsecurity_request_body_start(modsec_rec *msr, char **error_msg) { + *error_msg = NULL; + msr->msc_reqbody_length = 0; + + /* Create a separate memory pool that will be used + * to allocate structures from (not data, which is allocated + * via malloc). + */ + apr_pool_create(&msr->msc_reqbody_mp, NULL); + + /* Initialise request body processors, if any. */ + + if (msr->msc_reqbody_processor != NULL) { + char *my_error_msg = NULL; + + if (strcmp(msr->msc_reqbody_processor, "MULTIPART") == 0) { + if (multipart_init(msr, &my_error_msg) < 0) { + *error_msg = apr_psprintf(msr->mp, "Multipart parsing error (init): %s", my_error_msg); + msr->msc_reqbody_error = 1; + msr->msc_reqbody_error_msg = my_error_msg; + msr_log(msr, 2, "%s", *error_msg); + } + } + else + if (strcmp(msr->msc_reqbody_processor, "XML") == 0) { + if (xml_init(msr, &my_error_msg) < 0) { + *error_msg = apr_psprintf(msr->mp, "XML parsing error (init): %s", my_error_msg); + msr->msc_reqbody_error = 1; + msr->msc_reqbody_error_msg = my_error_msg; + msr_log(msr, 2, "%s", *error_msg); + } + } + else + if (strcmp(msr->msc_reqbody_processor, "URLENCODED") == 0) { + /* Do nothing, URLENCODED processor does not support streaming yet. */ + } + else { + *error_msg = apr_psprintf(msr->mp, "Unknown request body processor: %s", + msr->msc_reqbody_processor); + return -1; + } + } + + return modsecurity_request_body_start_init(msr, error_msg); +} + +/** + * Stores a chunk of request body data to disk. + */ +static apr_status_t modsecurity_request_body_store_disk(modsec_rec *msr, + const char *data, apr_size_t length, char **error_msg) +{ + apr_size_t i; + + *error_msg = NULL; + + i = write(msr->msc_reqbody_fd, data, length); + if (i != length) { + *error_msg = apr_psprintf(msr->mp, "Input filter: Failed writing %" APR_SIZE_T_FMT + " bytes to temporary file (rc %" APR_SIZE_T_FMT ").", length, i); + return -1; + } + + return 1; +} + +/** + * Stores one chunk of request body data in memory. + */ +static apr_status_t modsecurity_request_body_store_memory(modsec_rec *msr, + const char *data, apr_size_t length, char **error_msg) +{ + *error_msg = NULL; + + /* Would storing this chunk mean going over the limit? */ + if ((msr->msc_reqbody_spilltodisk) + && (msr->msc_reqbody_length + length > (apr_size_t)msr->txcfg->reqbody_inmemory_limit)) + { + msc_data_chunk **chunks; + unsigned int disklen = 0; + int i; + + msr_log(msr, 4, "Input filter: Request too large to store in memory, switching to disk."); + + /* NOTE Must use modsecurity_request_body_store_disk() here + * to prevent data to be sent to the streaming + * processors again. + */ + + /* Initialise disk storage */ + msr->msc_reqbody_storage = MSC_REQBODY_DISK; + if (modsecurity_request_body_start_init(msr, error_msg) < 0) return -1; + + /* Write the data we keep in memory */ + chunks = (msc_data_chunk **)msr->msc_reqbody_chunks->elts; + for(i = 0; i < msr->msc_reqbody_chunks->nelts; i++) { + disklen += chunks[i]->length; + + if (modsecurity_request_body_store_disk(msr, chunks[i]->data, chunks[i]->length, error_msg) < 0) { + return -1; + } + + free(chunks[i]->data); + chunks[i]->data = NULL; + } + + /* Clear the memory pool as we no longer need the bits. */ + + /* IMP1 But since we only used apr_pool_clear memory might + * not be released back to the OS straight away? + */ + msr->msc_reqbody_chunks = NULL; + apr_pool_clear(msr->msc_reqbody_mp); + + msr_log(msr, 4, "Input filter: Wrote %u bytes from memory to disk.", disklen); + + /* Continue with disk storage from now on */ + return modsecurity_request_body_store_disk(msr, data, length, error_msg); + } + + /* If we're here that means we are not over the + * request body in-memory limit yet. + */ + { + unsigned long int bucket_offset, bucket_left; + + bucket_offset = 0; + bucket_left = length; + + /* Although we store the request body in chunks we don't + * want to use the same chunk sizes as the incoming memory + * buffers. They are often of very small sizes and that + * would make us waste a lot of memory. That's why we + * use our own chunks of CHUNK_CAPACITY sizes. + */ + + /* Loop until we empty this bucket into our chunks. */ + while(bucket_left > 0) { + /* Allocate a new chunk if we have to. */ + if (msr->msc_reqbody_chunk_current == NULL) { + msr->msc_reqbody_chunk_current = (msc_data_chunk *) + apr_pcalloc(msr->msc_reqbody_mp, sizeof(msc_data_chunk)); + if (msr->msc_reqbody_chunk_current == NULL) { + *error_msg = apr_psprintf(msr->mp, "Input filter: Failed to allocate %lu bytes " + "for request body chunk.", (unsigned long)sizeof(msc_data_chunk)); + return -1; + } + + msr->msc_reqbody_chunk_current->data = malloc(CHUNK_CAPACITY); + if (msr->msc_reqbody_chunk_current->data == NULL) { + *error_msg = apr_psprintf(msr->mp, "Input filter: Failed to allocate %d bytes " + "for request body chunk data.", CHUNK_CAPACITY); + return -1; + } + + msr->msc_reqbody_chunk_current->length = 0; + msr->msc_reqbody_chunk_current->is_permanent = 1; + + *(const msc_data_chunk **)apr_array_push(msr->msc_reqbody_chunks) + = msr->msc_reqbody_chunk_current; + } + + if (bucket_left < (CHUNK_CAPACITY - msr->msc_reqbody_chunk_current->length)) { + /* There's enough space in the current chunk. */ + memcpy(msr->msc_reqbody_chunk_current->data + + msr->msc_reqbody_chunk_current->length, data + bucket_offset, bucket_left); + msr->msc_reqbody_chunk_current->length += bucket_left; + bucket_left = 0; + } else { + /* Fill the existing chunk. */ + unsigned long int copy_length = CHUNK_CAPACITY - + msr->msc_reqbody_chunk_current->length; + + memcpy(msr->msc_reqbody_chunk_current->data + + msr->msc_reqbody_chunk_current->length, data + bucket_offset, copy_length); + bucket_offset += copy_length; + bucket_left -= copy_length; + msr->msc_reqbody_chunk_current->length += copy_length; + + /* We're done with this chunk. Setting the pointer + * to NULL is going to force a new chunk to be allocated + * on the next go. + */ + msr->msc_reqbody_chunk_current = NULL; + } + } + + msr->msc_reqbody_length += length; + } + + return 1; +} + +/** + * Stores one chunk of request body data. Returns -1 on error. + */ +apr_status_t modsecurity_request_body_store(modsec_rec *msr, + const char *data, apr_size_t length, char **error_msg) +{ + *error_msg = NULL; + + /* If we have a processor for this request body send + * data to it first (but only if it did not report an + * error on previous invocations). + */ + if ((msr->msc_reqbody_processor != NULL)&&(msr->msc_reqbody_error == 0)) { + char *my_error_msg = NULL; + + if (strcmp(msr->msc_reqbody_processor, "MULTIPART") == 0) { + /* The per-request data length counter will + * be updated by the multipart parser. + */ + + /* Process data as multipart/form-data. */ + if (multipart_process_chunk(msr, data, length, &my_error_msg) < 0) { + *error_msg = apr_psprintf(msr->mp, "Multipart parsing error: %s", my_error_msg); + msr->msc_reqbody_error = 1; + msr->msc_reqbody_error_msg = *error_msg; + msr_log(msr, 2, "%s", *error_msg); + } + } + else + if (strcmp(msr->msc_reqbody_processor, "XML") == 0) { + /* Increase per-request data length counter. */ + msr->msc_reqbody_no_files_length += length; + + /* Process data as XML. */ + if (xml_process_chunk(msr, data, length, &my_error_msg) < 0) { + *error_msg = apr_psprintf(msr->mp, "XML parsing error: %s", my_error_msg); + msr->msc_reqbody_error = 1; + msr->msc_reqbody_error_msg = *error_msg; + msr_log(msr, 2, "%s", *error_msg); + } + } + else + if (strcmp(msr->msc_reqbody_processor, "URLENCODED") == 0) { + /* Increase per-request data length counter. */ + msr->msc_reqbody_no_files_length += length; + + /* Do nothing else, URLENCODED processor does not support streaming. */ + } + else { + *error_msg = apr_psprintf(msr->mp, "Unknown request body processor: %s", + msr->msc_reqbody_processor); + return -1; + } + } else if (msr->txcfg->reqbody_buffering != REQUEST_BODY_FORCEBUF_OFF) { + /* Increase per-request data length counter if forcing buffering. */ + msr->msc_reqbody_no_files_length += length; + } + + /* Check that we are not over the request body no files limit. */ + if (msr->msc_reqbody_no_files_length >= (unsigned long) msr->txcfg->reqbody_no_files_limit) { + return -5; + } + + /* Store data. */ + if (msr->msc_reqbody_storage == MSC_REQBODY_MEMORY) { + return modsecurity_request_body_store_memory(msr, data, length, error_msg); + } + else + if (msr->msc_reqbody_storage == MSC_REQBODY_DISK) { + return modsecurity_request_body_store_disk(msr, data, length, error_msg); + } + + /* Should never happen. */ + *error_msg = apr_psprintf(msr->mp, "Internal error, unknown value for msc_reqbody_storage: %u", + msr->msc_reqbody_storage); + return -1; +} + +/** + * Replace a bunch of chunks holding a request body with a single large chunk. + */ +static apr_status_t modsecurity_request_body_end_raw(modsec_rec *msr, char **error_msg) { + msc_data_chunk **chunks, *one_chunk; + char *d; + int i, sofar; + + *error_msg = NULL; + + /* Allocate a buffer large enough to hold the request body. */ + + if (msr->msc_reqbody_length + 1 == 0) { + *error_msg = apr_psprintf(msr->mp, "Internal error, request body length will overflow: %u", + msr->msc_reqbody_length); + return -1; + } + + msr->msc_reqbody_buffer = malloc(msr->msc_reqbody_length + 1); + if (msr->msc_reqbody_buffer == NULL) { + *error_msg = apr_psprintf(msr->mp, "Unable to allocate memory to hold request body. Asked for %u bytes.", + msr->msc_reqbody_length + 1); + return -1; + } + + msr->msc_reqbody_buffer[msr->msc_reqbody_length] = '\0'; + + /* Copy the data we keep in chunks into the new buffer. */ + + sofar = 0; + d = msr->msc_reqbody_buffer; + chunks = (msc_data_chunk **)msr->msc_reqbody_chunks->elts; + for(i = 0; i < msr->msc_reqbody_chunks->nelts; i++) { + if (sofar + chunks[i]->length <= msr->msc_reqbody_length) { + memcpy(d, chunks[i]->data, chunks[i]->length); + d += chunks[i]->length; + sofar += chunks[i]->length; + } else { + *error_msg = apr_psprintf(msr->mp, "Internal error, request body buffer overflow."); + return -1; + } + } + + /* Now free the memory used by the chunks. */ + + chunks = (msc_data_chunk **)msr->msc_reqbody_chunks->elts; + for(i = 0; i < msr->msc_reqbody_chunks->nelts; i++) { + free(chunks[i]->data); + chunks[i]->data = NULL; + } + + /* Create a new array with only one chunk in it. */ + + msr->msc_reqbody_chunks = apr_array_make(msr->msc_reqbody_mp, 2, sizeof(msc_data_chunk *)); + if (msr->msc_reqbody_chunks == NULL) { + *error_msg = apr_pstrdup(msr->mp, "Failed to create structure to hold request body."); + return -1; + } + + one_chunk = (msc_data_chunk *)apr_pcalloc(msr->msc_reqbody_mp, sizeof(msc_data_chunk)); + one_chunk->data = msr->msc_reqbody_buffer; + one_chunk->length = msr->msc_reqbody_length; + one_chunk->is_permanent = 1; + *(const msc_data_chunk **)apr_array_push(msr->msc_reqbody_chunks) = one_chunk; + + return 1; +} + +/** + * + */ +static apr_status_t modsecurity_request_body_end_urlencoded(modsec_rec *msr, char **error_msg) { + int invalid_count = 0; + + *error_msg = NULL; + + /* Create the raw buffer */ + if (modsecurity_request_body_end_raw(msr, error_msg) != 1) { + return -1; + } + + /* Parse URL-encoded arguments in the request body. */ + + if (parse_arguments(msr, msr->msc_reqbody_buffer, msr->msc_reqbody_length, + msr->txcfg->argument_separator, "BODY", msr->arguments, &invalid_count) < 0) + { + *error_msg = apr_pstrdup(msr->mp, "Initialisation: Error occurred while parsing BODY arguments."); + return -1; + } + + return 1; +} + +/** + * Stops receiving the request body. + */ +apr_status_t modsecurity_request_body_end(modsec_rec *msr, char **error_msg) { + *error_msg = NULL; + + /* Close open file descriptors, if any. */ + if (msr->msc_reqbody_storage == MSC_REQBODY_DISK) { + if (msr->msc_reqbody_fd > 0) { + close(msr->msc_reqbody_fd); + msr->msc_reqbody_fd = -1; + } + } + + /* Note that we've read the body. */ + msr->msc_reqbody_read = 1; + + /* Finalise body processing. */ + if ((msr->msc_reqbody_processor != NULL)&&(msr->msc_reqbody_error == 0)) { + char *my_error_msg = NULL; + + if (strcmp(msr->msc_reqbody_processor, "MULTIPART") == 0) { + if (multipart_complete(msr, &my_error_msg) < 0) { + *error_msg = apr_psprintf(msr->mp, "Multipart parsing error: %s", my_error_msg); + msr->msc_reqbody_error = 1; + msr->msc_reqbody_error_msg = *error_msg; + msr_log(msr, 2, "%s", *error_msg); + return -1; + } + + if (multipart_get_arguments(msr, "BODY", msr->arguments) < 0) { + *error_msg = "Multipart parsing error: Failed to retrieve arguments."; + msr->msc_reqbody_error = 1; + msr->msc_reqbody_error_msg = *error_msg; + msr_log(msr, 2, "%s", *error_msg); + return -1; + } + } + else + if (strcmp(msr->msc_reqbody_processor, "URLENCODED") == 0) { + return modsecurity_request_body_end_urlencoded(msr, error_msg); + } + else + if (strcmp(msr->msc_reqbody_processor, "XML") == 0) { + if (xml_complete(msr, &my_error_msg) < 0) { + *error_msg = apr_psprintf(msr->mp, "XML parser error: %s", my_error_msg); + msr->msc_reqbody_error = 1; + msr->msc_reqbody_error_msg = *error_msg; + msr_log(msr, 2, "%s", *error_msg); + return -1; + } + } + } else if (msr->txcfg->reqbody_buffering != REQUEST_BODY_FORCEBUF_OFF) { + /* Convert to a single continous buffer, but don't do anything else. */ + return modsecurity_request_body_end_raw(msr, error_msg); + } + + /* Note the request body no files length. */ + msr_log(msr, 4, "Reqest body no files length: %" APR_SIZE_T_FMT, msr->msc_reqbody_no_files_length); + + return 1; +} + +/** + * Prepares to forward the request body. + */ +apr_status_t modsecurity_request_body_retrieve_start(modsec_rec *msr, char **error_msg) { + *error_msg = NULL; + + if (msr->msc_reqbody_storage == MSC_REQBODY_MEMORY) { + msr->msc_reqbody_chunk_position = 0; + msr->msc_reqbody_chunk_offset = 0; + + msr->msc_reqbody_disk_chunk = apr_pcalloc(msr->msc_reqbody_mp, sizeof(msc_data_chunk)); + if (msr->msc_reqbody_disk_chunk == NULL) { + *error_msg = apr_psprintf(msr->mp, "Failed to allocate %lu bytes for request body disk chunk.", + (unsigned long)sizeof(msc_data_chunk)); + return -1; + } + msr->msc_reqbody_disk_chunk->is_permanent = 1; + } + else + if (msr->msc_reqbody_storage == MSC_REQBODY_DISK) { + msr->msc_reqbody_disk_chunk = apr_pcalloc(msr->msc_reqbody_mp, sizeof(msc_data_chunk)); + if (msr->msc_reqbody_disk_chunk == NULL) { + *error_msg = apr_psprintf(msr->mp, "Failed to allocate %lu bytes for request body disk chunk.", + (unsigned long)sizeof(msc_data_chunk)); + return -1; + } + + msr->msc_reqbody_disk_chunk->is_permanent = 0; + msr->msc_reqbody_disk_chunk->data = apr_palloc(msr->msc_reqbody_mp, CHUNK_CAPACITY); + if (msr->msc_reqbody_disk_chunk->data == NULL) { + *error_msg = apr_psprintf(msr->mp, "Failed to allocate %d bytes for request body disk chunk data.", + CHUNK_CAPACITY); + return -1; + } + + msr->msc_reqbody_fd = open(msr->msc_reqbody_filename, O_RDONLY | O_BINARY); + if (msr->msc_reqbody_fd < 0) { + *error_msg = apr_psprintf(msr->mp, "Failed to open temporary file for reading: %s", + msr->msc_reqbody_filename); + return -1; + } + } + + return 1; +} + +/** + * + */ +apr_status_t modsecurity_request_body_retrieve_end(modsec_rec *msr) { + if (msr->msc_reqbody_storage == MSC_REQBODY_DISK) { + if (msr->msc_reqbody_fd > 0) { + close(msr->msc_reqbody_fd); + msr->msc_reqbody_fd = -1; + } + } + + return 1; +} + +/** + * Returns one chunk of request body data. It stores a NULL + * in the chunk pointer when there is no data to return. The + * return code is 1 if more calls can be made to retrieve more + * data, 0 if there is no more data to retrieve, or -1 on error. + * + * The caller can limit the amount of data returned by providing + * a non-negative value in nbytes. + */ +apr_status_t modsecurity_request_body_retrieve(modsec_rec *msr, + msc_data_chunk **chunk, long int nbytes, char **error_msg) +{ + msc_data_chunk **chunks; + + *error_msg = NULL; + + if (chunk == NULL) { + *error_msg = apr_pstrdup(msr->mp, "Internal error, retrieving request body chunk."); + return -1; + } + *chunk = NULL; + + if (msr->msc_reqbody_storage == MSC_REQBODY_MEMORY) { + /* Are there any chunks left? */ + if (msr->msc_reqbody_chunk_position >= msr->msc_reqbody_chunks->nelts) { + /* No more chunks. */ + return 0; + } + + /* We always respond with the same chunk, just different information in it. */ + *chunk = msr->msc_reqbody_disk_chunk; + + /* Advance to the current chunk and position on the + * next byte we need to send. + */ + chunks = (msc_data_chunk **)msr->msc_reqbody_chunks->elts; + msr->msc_reqbody_disk_chunk->data = chunks[msr->msc_reqbody_chunk_position]->data + + msr->msc_reqbody_chunk_offset; + + if (nbytes < 0) { + /* Send what's left in this chunk as there is no limit on the size. */ + msr->msc_reqbody_disk_chunk->length = chunks[msr->msc_reqbody_chunk_position]->length; + msr->msc_reqbody_chunk_position++; + msr->msc_reqbody_chunk_offset = 0; + } else { + /* We have a limit we must obey. */ + + if (chunks[msr->msc_reqbody_chunk_position]->length - + msr->msc_reqbody_chunk_offset <= (unsigned int)nbytes) + { + /* If what's left in our chunk is less than the limit + * then send it all back. + */ + msr->msc_reqbody_disk_chunk->length = + chunks[msr->msc_reqbody_chunk_position]->length - + msr->msc_reqbody_chunk_offset; + msr->msc_reqbody_chunk_position++; + msr->msc_reqbody_chunk_offset = 0; + } else { + /* If we have more data in our chunk, send the + * maximum bytes we can (nbytes). + */ + msr->msc_reqbody_disk_chunk->length = nbytes; + msr->msc_reqbody_chunk_offset += nbytes; + } + } + + /* If we've advanced beyond our last chunk then + * we have no more data to send. + */ + if (msr->msc_reqbody_chunk_position >= msr->msc_reqbody_chunks->nelts) { + return 0; /* No more chunks. */ + } + + /* More data available. */ + return 1; + } + + if (msr->msc_reqbody_storage == MSC_REQBODY_DISK) { + long int my_nbytes = CHUNK_CAPACITY; + int i; + + /* Send CHUNK_CAPACITY bytes at a time unless a lower limit was requested. */ + if ((nbytes != -1)&&(my_nbytes > nbytes)) { + my_nbytes = nbytes; + } + + i = read(msr->msc_reqbody_fd, msr->msc_reqbody_disk_chunk->data, my_nbytes); + if (i < 0) { + *error_msg = apr_psprintf(msr->mp, "Input filter: Error reading from temporary file: %s", + strerror(errno)); + return -1; + } + + *chunk = msr->msc_reqbody_disk_chunk; + msr->msc_reqbody_disk_chunk->length = i; + + if (i == 0) return 0; /* No more data available. */ + + return 1; /* More data available. */ + } + + /* Should never happen. */ + *error_msg = apr_psprintf(msr->mp, "Internal error, invalid msc_reqbody_storage value: %u", + msr->msc_reqbody_storage); + + return -1; +} + +/** + * + */ +apr_status_t modsecurity_request_body_clear(modsec_rec *msr, char **error_msg) { + *error_msg = NULL; + + /* Release memory we used to store request body data. */ + if (msr->msc_reqbody_chunks != NULL) { + msc_data_chunk **chunks = (msc_data_chunk **)msr->msc_reqbody_chunks->elts; + int i; + + for(i = 0; i < msr->msc_reqbody_chunks->nelts; i++) { + if (chunks[i]->data != NULL) { + free(chunks[i]->data); + chunks[i]->data = NULL; + } + } + } + + if (msr->msc_reqbody_storage == MSC_REQBODY_DISK) { + int keep_body = 0; + + /* Should we keep the body? This normally + * happens when a PUT method was used, which + * means the body is actually a file. + */ + if ((msr->upload_remove_files == 0)&&(strcasecmp(msr->request_method, "PUT") == 0)) { + if (msr->txcfg->upload_dir != NULL) { + keep_body = 1; + } else { + *error_msg = apr_psprintf(msr->mp, "Input filter: SecUploadDir is undefined, " + "unable to store PUT file."); + } + } + + /* Deal with a request body stored in a file. */ + + if (msr->msc_reqbody_filename != NULL) { + if (keep_body) { + /* Move request body (which is a file) to the storage area. */ + const char *put_filename = NULL; + const char *put_basename = NULL; + + /* Construct the new filename. */ + put_basename = file_basename(msr->msc_reqbody_mp, msr->msc_reqbody_filename); + if (put_basename == NULL) { + *error_msg = apr_psprintf(msr->mp, "Input filter: Failed to generate basename to PUT file \"%s\"", log_escape(msr->msc_reqbody_mp, msr->msc_reqbody_filename)); + return -1; + } + put_filename = apr_psprintf(msr->msc_reqbody_mp, "%s/%s", + msr->txcfg->upload_dir, put_basename); + if (put_filename == NULL) { + *error_msg = apr_psprintf(msr->mp, "Input filter: Failed to generate filename to PUT file \"%s\"", log_escape(msr->msc_reqbody_mp, msr->msc_reqbody_filename)); + return -1; + } + + if (apr_file_rename(msr->msc_reqbody_filename, put_filename, + msr->msc_reqbody_mp) != APR_SUCCESS) + { + *error_msg = apr_psprintf(msr->mp, "Input filter: Failed to rename file from \"%s\" to \"%s\".", + log_escape(msr->msc_reqbody_mp, msr->msc_reqbody_filename), + log_escape(msr->msc_reqbody_mp, put_filename)); + return -1; + } else { + msr_log(msr, 4, "Input filter: Moved file from \"%s\" to \"%s\".", + log_escape(msr->msc_reqbody_mp, msr->msc_reqbody_filename), + log_escape(msr->msc_reqbody_mp, put_filename)); + } + } else { + /* make sure it is closed first */ + if (msr->msc_reqbody_fd > 0) { + close(msr->msc_reqbody_fd); + msr->msc_reqbody_fd = -1; + } + + /* We do not want to keep the request body. */ + if (apr_file_remove(msr->msc_reqbody_filename, + msr->msc_reqbody_mp) != APR_SUCCESS) + { + *error_msg = apr_psprintf(msr->mp, "Input filter: Failed to delete temporary file: %s", + log_escape(msr->mp, msr->msc_reqbody_filename)); + return -1; + } + + msr_log(msr, 4, "Input filter: Removed temporary file: %s", + msr->msc_reqbody_filename); + } + + msr->msc_reqbody_filename = NULL; + } + } + + if (msr->msc_reqbody_mp != NULL) { + apr_pool_destroy(msr->msc_reqbody_mp); + msr->msc_reqbody_mp = NULL; + } + + return 1; +} diff --git a/apache2/msc_test.c b/apache2/msc_test.c new file mode 100644 index 0000000..9e7b978 --- /dev/null +++ b/apache2/msc_test.c @@ -0,0 +1,920 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ +#include +#include + +#include "modsecurity.h" +#include "re.h" +#include "pdf_protect.h" + +#define ISHEX(X) (((X >= '0')&&(X <= '9')) || ((X >= 'a')&&(X <= 'f')) || ((X >= 'A')&&(X <= 'F'))) + +#define BUFLEN 32768 + +#define RESULT_SUCCESS 0 +#define RESULT_ERROR -1 +#define RESULT_MISMATCHED -2 +#define RESULT_WRONGSIZE -3 +#define RESULT_WRONGRET -4 + +#define DEFAULT_ACTION "phase:2,log,auditlog,pass" + +#define CMDLINE_OPTS "t:n:p:P:r:I:D:Nh" + +/* Types */ +typedef struct tfn_data_t tfn_data_t; +typedef struct op_data_t op_data_t; +typedef struct action_data_t action_data_t; + +struct tfn_data_t { + const char *name; + const char *param; + unsigned char *input; + apr_size_t input_len; + msre_tfn_metadata *metadata; +}; + +struct op_data_t { + const char *name; + const char *param; + unsigned char *input; + apr_size_t input_len; + msre_ruleset *ruleset; + msre_rule *rule; + msre_var *var; + msre_op_metadata *metadata; +}; + +struct action_data_t { + const char *name; + unsigned char *input; + apr_size_t input_len; + msre_ruleset *ruleset; + msre_rule *rule; + msre_var *var; + msre_actionset *actionset; + msre_action *action; +}; + + +/* Globals */ +static int debuglog_level = 0; +static char *test_name = NULL; +static apr_pool_t *g_mp = NULL; +static modsec_rec *g_msr = NULL; +static unsigned char buf[BUFLEN]; +msc_engine *modsecurity = NULL; + + +/* Stubs */ +char *format_error_log_message(apr_pool_t *mp, error_message *em) { + return "FAKE ERROR LOG MESSAGE"; +} + +apr_status_t send_error_bucket(modsec_rec *msr, ap_filter_t *f, int status) { + return APR_SUCCESS; +} + +int apache2_exec(modsec_rec *msr, const char *command, const char **argv, char **output) { + return 0; +} + +char *get_apr_error(apr_pool_t *p, apr_status_t rc) { + char *text = apr_pcalloc(p, 201); + if (text == NULL) return NULL; + apr_strerror(rc, text, 200); + return text; +} + +void msr_log(modsec_rec *msr, int level, const char *text, ...) { + va_list ap; + char str1[1024] = ""; + char str2[1256] = ""; + + if ((msr == NULL) || (level > msr->txcfg->debuglog_level)) { + return; + } + if (msr->txcfg->debuglog_fd == NOT_SET_P) { + if (apr_file_open(&msr->txcfg->debuglog_fd, msr->txcfg->debuglog_name, APR_READ|APR_WRITE|APR_CREATE|APR_APPEND|APR_BINARY, APR_OS_DEFAULT, g_mp) != APR_SUCCESS) { + fprintf(stderr, "ERROR: failed to create unit test debug log \"%s\".\n", msr->txcfg->debuglog_name); + msr->txcfg->debuglog_fd = NULL; + } + } + + va_start(ap, text); + if (msr->txcfg->debuglog_fd != NULL) { + apr_size_t nbytes_written = 0; + apr_vsnprintf(str1, sizeof(str1), text, ap); + apr_snprintf(str2, sizeof(str2), "%lu: [%d] [%s] %s\n", (unsigned long)getpid(), level, test_name, str1); + + apr_file_write_full(msr->txcfg->debuglog_fd, str2, strlen(str2), &nbytes_written); + } + va_end(ap); +} + +void msr_log_error(modsec_rec *msr, const char *text, ...) { + va_list ap; + int level = 3; + char str1[1024] = ""; + char str2[1256] = ""; + + if ((msr == NULL) || (level > msr->txcfg->debuglog_level)) { + return; + } + if (msr->txcfg->debuglog_fd == NOT_SET_P) { + if (apr_file_open(&msr->txcfg->debuglog_fd, msr->txcfg->debuglog_name, APR_READ|APR_WRITE|APR_CREATE|APR_APPEND|APR_BINARY, APR_OS_DEFAULT, g_mp) != APR_SUCCESS) { + fprintf(stderr, "ERROR: failed to create unit test debug log \"%s\".\n", msr->txcfg->debuglog_name); + msr->txcfg->debuglog_fd = NULL; + } + } + + va_start(ap, text); + if (msr->txcfg->debuglog_fd != NULL) { + apr_size_t nbytes_written = 0; + apr_vsnprintf(str1, sizeof(str1), text, ap); + apr_snprintf(str2, sizeof(str2), "%lu: [%d] [%s] %s\n", (unsigned long)getpid(), level, test_name, str1); + + apr_file_write_full(msr->txcfg->debuglog_fd, str2, strlen(str2), &nbytes_written); + } + va_end(ap); +} + +void msr_log_warn(modsec_rec *msr, const char *text, ...) { + va_list ap; + int level = 4; + char str1[1024] = ""; + char str2[1256] = ""; + + if ((msr == NULL) || (level > msr->txcfg->debuglog_level)) { + return; + } + if (msr->txcfg->debuglog_fd == NOT_SET_P) { + if (apr_file_open(&msr->txcfg->debuglog_fd, msr->txcfg->debuglog_name, APR_READ|APR_WRITE|APR_CREATE|APR_APPEND|APR_BINARY, APR_OS_DEFAULT, g_mp) != APR_SUCCESS) { + fprintf(stderr, "ERROR: failed to create unit test debug log \"%s\".\n", msr->txcfg->debuglog_name); + msr->txcfg->debuglog_fd = NULL; + } + } + + va_start(ap, text); + if (msr->txcfg->debuglog_fd != NULL) { + apr_size_t nbytes_written = 0; + apr_vsnprintf(str1, sizeof(str1), text, ap); + apr_snprintf(str2, sizeof(str2), "%lu: [%d] [%s] %s\n", (unsigned long)getpid(), level, test_name, str1); + + apr_file_write_full(msr->txcfg->debuglog_fd, str2, strlen(str2), &nbytes_written); + } + va_end(ap); +} + +const char *ap_get_remote_host(conn_rec *conn, void *dir_config, int type, int *str_is_ip) { + return "FAKE-REMOTE-HOST"; +} + +char *get_env_var(request_rec *r, char *name) { + return "FAKE-ENV-VAR"; +} + +apr_status_t unixd_set_global_mutex_perms(apr_global_mutex_t *gmutex) { + return APR_SUCCESS; +} + +apr_status_t unixd_set_proc_mutex_perms(apr_proc_mutex_t *pmutex) { + return APR_SUCCESS; +} + + +/* Escaping functions */ + +static unsigned char hex2dec(unsigned char *what) { + register unsigned char digit; + + digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0')); + digit *= 16; + digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0')); + + return digit; +} + +static unsigned char *unescape_inplace(unsigned char *str, apr_size_t *len) +{ + apr_size_t i, j; + for (i = j = 0; i < *len; j++) { + if ((str[i] == '\\') && (i + 3 < *len) && (str[i + 1] == 'x') && ISHEX(str[i + 2]) && ISHEX(str[i + 3]) ) { + str[j] = hex2dec(str + i + 2); + i += 4; + } + else { + str[j] = str[i++]; + } + } + *len = j; + + while (j < i) { + str[j++] = '\0'; + } + + return str; +} + +static char *escape(unsigned char *str, apr_size_t *len) +{ + char *new = apr_pcalloc(g_mp, (*len * 4) + 1); + apr_size_t i, j; + for (i = j = 0; i < *len; i++) { + if ((str[i] >= 0x20) && (str[i] <= 0x7e)) { + new[j++] = str[i]; + } + else { + sprintf(new + j, "\\x%02x", str[i]); + j += 4; + } + } + *len = j; + + return new; +} + + +/* Testing functions */ + +static int init_tfn(tfn_data_t *data, const char *name, unsigned char *input, apr_size_t input_len, char **errmsg) { + *errmsg = NULL; + + data->name = name; + data->input = apr_pmemdup(g_mp, input, input_len); + data->input_len = input_len; + data->metadata = msre_engine_tfn_resolve(modsecurity->msre, name); + if (data->metadata == NULL) { + *errmsg = apr_psprintf(g_mp, "Failed to fetch tfn \"%s\".", name); + return -1; + } + + return 0; +} + +static int test_tfn(tfn_data_t *data, unsigned char **rval, apr_size_t *rval_len, char **errmsg) +{ + int rc = -1; + + *errmsg = NULL; + + /* Execute the tfn */ + rc = data->metadata->execute(g_mp, data->input, (long)(data->input_len), (char **)rval, (long *)rval_len); + if (rc < 0) { + *errmsg = apr_psprintf(g_mp, "Failed to execute tfn \"%s\".", data->name); + } + + return rc; +} + +static int init_op(op_data_t *data, const char *name, const char *param, unsigned char *input, apr_size_t input_len, char **errmsg) { + const char *args = apr_psprintf(g_mp, "@%s %s", name, param); + char *conf_fn; + int rc = -1; + + *errmsg = NULL; + + data->name = name; + data->param = param; + data->input = input; + data->input_len = input_len; + + if ( apr_filepath_merge(&conf_fn, NULL, "t/unit-test.conf", APR_FILEPATH_TRUENAME, g_mp) != APR_SUCCESS) { + *errmsg = apr_psprintf(g_mp, "Failed to build a conf filename."); + return -1; + } + + /* Register UNIT_TEST variable */ + msre_engine_variable_register(modsecurity->msre, + "UNIT_TEST", + VAR_SIMPLE, + 0, 0, + NULL, + NULL, + VAR_DONT_CACHE, + PHASE_REQUEST_HEADERS + ); + + /* Lookup the operator */ + data->metadata = msre_engine_op_resolve(modsecurity->msre, name); + if (data->metadata == NULL) { + *errmsg = apr_psprintf(g_mp, "Failed to fetch op \"%s\".", name); + return -1; + } + + /* Create a ruleset/rule */ + data->ruleset = msre_ruleset_create(modsecurity->msre, g_mp); + if (data->ruleset == NULL) { + *errmsg = apr_psprintf(g_mp, "Failed to create ruleset for op \"%s\".", name); + return -1; + } + data->rule = msre_rule_create(data->ruleset, RULE_TYPE_NORMAL, conf_fn, 1, "UNIT_TEST", args, DEFAULT_ACTION, errmsg); + if (data->rule == NULL) { + *errmsg = apr_psprintf(g_mp, "Failed to create rule for op \"%s\": %s", name, *errmsg); + return -1; + } + + /* Create a fake variable */ + data->var = (msre_var *)apr_pcalloc(g_mp, sizeof(msre_var)); + data->var->name = "UNIT_TEST"; + data->var->value = apr_pstrmemdup(g_mp, (char *)input, input_len); + data->var->value_len = input_len; + data->var->metadata = msre_resolve_var(modsecurity->msre, data->var->name); + if (data->var->metadata == NULL) { + *errmsg = apr_psprintf(g_mp, "Failed to resolve variable for op \"%s\": %s", name, data->var->name); + return -1; + } + + /* Initialize the operator parameter */ + if (data->metadata->param_init != NULL) { + rc = data->metadata->param_init(data->rule, errmsg); + if (rc <= 0) { + *errmsg = apr_psprintf(g_mp, "Failed to init op \"%s\": %s", name, *errmsg); + return rc; + } + } + + return 0; +} + +static int test_op(op_data_t *data, char **errmsg) +{ + int rc = -1; + + *errmsg = NULL; + + /* Execute the operator */ + if (data->metadata->execute != NULL) { + rc = data->metadata->execute(g_msr, data->rule, data->var, errmsg); + if (rc < 0) { + *errmsg = apr_psprintf(g_mp, "Failed to execute op \"%s\": %s", data->name, *errmsg); + } + } + + return rc; +} + +static int init_action(action_data_t *data, const char *name, const char *param, char **errmsg) +{ + const char *action_string = NULL; + char *conf_fn; + + *errmsg = NULL; + + if ((param == NULL) || (strcmp("", param) == 0)) { + action_string = apr_psprintf(g_mp, "%s", name); + } + else { + action_string = apr_psprintf(g_mp, "%s:%s", name, param); + } + if (action_string == NULL) { + *errmsg = apr_psprintf(g_mp, "Failed to build action string for action: \"%s\".", name); + return -1; + } + + if ( apr_filepath_merge(&conf_fn, NULL, "t/unit-test.conf", APR_FILEPATH_TRUENAME, g_mp) != APR_SUCCESS) { + *errmsg = apr_psprintf(g_mp, "Failed to build a conf filename."); + return -1; + } + + /* Register UNIT_TEST variable */ + msre_engine_variable_register(modsecurity->msre, + "UNIT_TEST", + VAR_SIMPLE, + 0, 0, + NULL, + NULL, + VAR_DONT_CACHE, + PHASE_REQUEST_HEADERS + ); + + /* Create a ruleset/rule */ + data->ruleset = msre_ruleset_create(modsecurity->msre, g_mp); + if (data->ruleset == NULL) { + *errmsg = apr_psprintf(g_mp, "Failed to create ruleset for action \"%s\".", name); + return -1; + } + data->rule = msre_rule_create(data->ruleset, RULE_TYPE_NORMAL, conf_fn, 1, "UNIT_TEST", "@unconditionalMatch", action_string, errmsg); + if (data->rule == NULL) { + *errmsg = apr_psprintf(g_mp, "Failed to create rule for action \"%s\": %s", name, *errmsg); + return -1; + } + + /* Get the actionset/action */ + data->actionset = data->rule->actionset; + if (data->actionset == NULL) { + *errmsg = apr_psprintf(g_mp, "Failed to fetch actionset for action \"%s\"", name); + return -1; + } + data->action = (msre_action *)apr_table_get(data->actionset->actions, name); + if (data->action == NULL) { + *errmsg = apr_psprintf(g_mp, "Failed to fetch action for action \"%s\"", name); + return -1; + } + + return 0; +} + +static int test_action(action_data_t *data, char **errmsg) +{ + int rc = -1; + + *errmsg = NULL; + + /* Execute the action */ + if (data->action->metadata->execute != NULL) { + rc = data->action->metadata->execute(g_msr, g_mp, data->rule, data->action); + if (rc < 0) { + *errmsg = apr_psprintf(g_mp, "Failed to execute action \"%s\": %d", data->name, rc); + } + } + + return rc; +} + + +/* Initialization */ +static void init_msr(void) +{ + directory_config *dcfg = NULL; + request_rec *r = NULL; + r = (request_rec *)apr_pcalloc(g_mp, sizeof(request_rec)); + + dcfg = (directory_config *)apr_pcalloc(g_mp, sizeof(directory_config)); + dcfg->is_enabled = 0; + dcfg->reqbody_access = 0; + dcfg->reqbody_buffering = 0; + dcfg->reqbody_inmemory_limit = REQUEST_BODY_DEFAULT_INMEMORY_LIMIT; + dcfg->reqbody_limit = REQUEST_BODY_DEFAULT_LIMIT; + dcfg->reqbody_no_files_limit = REQUEST_BODY_NO_FILES_DEFAULT_LIMIT; + dcfg->resbody_access = 0; + dcfg->of_limit = RESPONSE_BODY_DEFAULT_LIMIT; + dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_REJECT; + dcfg->debuglog_fd = NOT_SET_P; + dcfg->debuglog_name = "msc-test-debug.log"; + dcfg->debuglog_level = debuglog_level; + dcfg->cookie_format = 0; + dcfg->argument_separator = '&'; + dcfg->rule_inheritance = 0; + dcfg->auditlog_flag = 0; + dcfg->auditlog_type = AUDITLOG_SERIAL; + dcfg->auditlog_fd = NULL; + dcfg->auditlog2_fd = NULL; + dcfg->auditlog_name = NULL; + dcfg->auditlog2_name = NULL; + dcfg->auditlog_storage_dir = NULL; + dcfg->auditlog_parts = "ABCFHZ"; + dcfg->auditlog_relevant_regex = NULL; + dcfg->tmp_dir = guess_tmp_dir(g_mp); + dcfg->upload_dir = NULL; + dcfg->upload_keep_files = KEEP_FILES_OFF; + dcfg->upload_validates_files = 0; + dcfg->data_dir = "."; + dcfg->webappid = "default"; + dcfg->content_injection_enabled = 0; + dcfg->pdfp_enabled = 0; + dcfg->pdfp_secret = NULL; + dcfg->pdfp_timeout = 10; + dcfg->pdfp_token_name = "PDFPTOKEN"; + dcfg->pdfp_only_get = 1; + dcfg->pdfp_method = PDF_PROTECT_METHOD_TOKEN_REDIRECTION; + dcfg->geo = NULL; + dcfg->cache_trans = MODSEC_CACHE_ENABLED; + dcfg->cache_trans_min = 15; + dcfg->cache_trans_max = 0; + dcfg->request_encoding = NULL; + + g_msr = (modsec_rec *)apr_pcalloc(g_mp, sizeof(modsec_rec)); + g_msr->modsecurity = modsecurity; + g_msr->mp = g_mp; + g_msr->r = r; + g_msr->r_early = r; + g_msr->request_time = apr_time_now(); + g_msr->dcfg1 = NULL; + g_msr->usercfg = NULL; + g_msr->txcfg = dcfg; + g_msr->txid = "FAKE-TXID"; + g_msr->error_messages = NULL; + g_msr->alerts = NULL; + g_msr->server_software = "FAKE-SERVER-SOFTWARE"; + g_msr->local_addr = "127.0.0.1"; + g_msr->local_port = 80; + g_msr->remote_addr = "127.0.0.1"; + g_msr->remote_port = 1080; + g_msr->request_line = "GET /unit-tests HTTP/1.1"; + g_msr->request_uri = "http://localhost/unit-tests"; + g_msr->request_method = "GET"; + g_msr->query_string = ""; + g_msr->request_protocol = "HTTP/1.1"; + g_msr->request_headers = NULL; + g_msr->hostname = "localhost"; + g_msr->msc_rule_mptmp = g_mp; + g_msr->tx_vars = apr_table_make(g_mp, 1); + g_msr->collections_original = apr_table_make(g_mp, 1); + g_msr->collections = apr_table_make(g_mp, 1); + g_msr->collections_dirty = apr_table_make(g_mp, 1); +} + +/** + * Usage text. + */ +static void usage(void) +{ + fprintf(stderr, "ModSecurity Unit Tester v%s\n", MODSEC_VERSION); + fprintf(stderr, " Usage: msc_test [options]\n"); + fprintf(stderr, "\n"); + fprintf(stderr, " Options:\n"); + fprintf(stderr, " -t Type (required)\n"); + fprintf(stderr, " -n Name (required)\n"); + fprintf(stderr, " -p Parameter (required)\n"); + fprintf(stderr, " -P Prerun (optional for actions)\n"); + fprintf(stderr, " -r Function return code (required for some types)\n"); + fprintf(stderr, " -I Iterations (default 1)\n"); + fprintf(stderr, " -D Debug log level (default 0)\n"); + fprintf(stderr, " -N No input on stdin.\n\n"); + fprintf(stderr, " -h This help\n\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "Input is from stdin unless -N is used.\n"); +} + + + +/* Main */ + +int main(int argc, const char * const argv[]) +{ + apr_getopt_t *opt; + apr_file_t *fd; + apr_size_t nbytes = 0; + const char *type = NULL; + const char *name = NULL; + unsigned char *param = NULL; + unsigned char *prerun = NULL; + const char *returnval = NULL; + int iterations = 1; + char *errmsg = NULL; + unsigned char *out = NULL; + apr_size_t param_len = 0; + apr_size_t prerun_len = 0; + apr_size_t out_len = 0; + int noinput = 0; + int rc = 0; + int result = 0; + int ec = 0; + int i; + apr_time_t T0 = 0; + apr_time_t T1 = 0; + tfn_data_t tfn_data; + op_data_t op_data; + action_data_t action_data; + int ret = 0; + + memset(&tfn_data, 0, sizeof(tfn_data_t)); + memset(&op_data, 0, sizeof(op_data_t)); + memset(&action_data, 0, sizeof(action_data_t)); + + apr_app_initialize(&argc, &argv, NULL); + atexit(apr_terminate); + + apr_pool_create(&g_mp, NULL); + + rc = apr_getopt_init(&opt, g_mp, argc, argv); + if (rc != APR_SUCCESS) { + fprintf(stderr, "Failed to initialize.\n\n"); + usage(); + exit(1); + } + + do { + char ch; + const char *val; + rc = apr_getopt(opt, CMDLINE_OPTS, &ch, &val); + switch (rc) { + case APR_SUCCESS: + switch (ch) { + case 't': + type = val; + break; + case 'n': + name = val; + break; + case 'p': + param_len = strlen(val); + param = apr_pmemdup(g_mp, val, param_len + 1); + unescape_inplace(param, ¶m_len); + break; + case 'P': + prerun_len = strlen(val); + prerun = apr_pmemdup(g_mp, val, prerun_len + 1); + unescape_inplace(prerun, &prerun_len); + break; + case 'r': + returnval = val; + break; + case 'I': + iterations = atoi(val); + break; + case 'D': + debuglog_level = atoi(val); + break; + case 'N': + noinput = 1; + break; + case 'h': + usage(); + exit(0); + } + break; + case APR_BADCH: + case APR_BADARG: + usage(); + exit(1); + } + } while (rc != APR_EOF); + + rc = apr_getopt_init(&opt, g_mp, argc, argv); + if (!type || !name || !param) { + usage(); + exit(1); + } + + modsecurity = modsecurity_create(g_mp, MODSEC_OFFLINE); + test_name = apr_psprintf(g_mp, "%s/%s", type, name); + + if (noinput == 0) { + if (apr_file_open_stdin(&fd, g_mp) != APR_SUCCESS) { + fprintf(stderr, "Failed to open stdin\n"); + exit(1); + } + + /* Read in the input */ + nbytes = BUFLEN; + memset(buf, 0, nbytes); + rc = apr_file_read(fd, buf, &nbytes); + if ((rc != APR_EOF) && (rc != APR_SUCCESS)) { + fprintf(stderr, "Failed to read data\n"); + exit(1); + } + + if (nbytes < 0) { + fprintf(stderr, "Error reading data\n"); + exit(1); + } + + apr_file_close(fd); + } + + if (strcmp("tfn", type) == 0) { + ret = returnval ? atoi(returnval) : -8888; + + rc = init_tfn(&tfn_data, name, buf, nbytes, &errmsg); + if (rc < 0) { + fprintf(stderr, "ERROR: %s\n", errmsg); + result = RESULT_ERROR; + } + } + else if (strcmp("op", type) == 0) { + if (!returnval) { + fprintf(stderr, "Return value required for type \"%s\"\n", type); + exit(1); + } + ret = atoi(returnval); + + init_msr(); + + rc = init_op(&op_data, name, (const char *)param, buf, nbytes, &errmsg); + if (rc < 0) { + fprintf(stderr, "ERROR: %s\n", errmsg); + result = RESULT_ERROR; + } + } + else if (strcmp("action", type) == 0) { + if (!returnval) { + fprintf(stderr, "Return value required for type \"%s\"\n", type); + exit(1); + } + ret = atoi(returnval); + + init_msr(); + + if (prerun) { + action_data_t paction_data; + char *pname = apr_pstrdup(g_mp, (const char *)prerun); + char *pparam = NULL; + + if ((pparam = strchr((const char *)pname, ':'))) { + pparam[0] = '\0'; + pparam++; + } + + rc = init_action(&paction_data, pname, (const char *)pparam, &errmsg); + if (rc < 0) { + fprintf(stderr, "ERROR: prerun - %s\n", errmsg); + exit(1); + } + + rc = test_action(&paction_data, &errmsg); + if (rc < 0) { + fprintf(stderr, "ERROR: prerun - %s\n", errmsg); + exit(1); + } + } + + rc = init_action(&action_data, name, (const char *)param, &errmsg); + if (rc < 0) { + fprintf(stderr, "ERROR: %s\n", errmsg); + result = RESULT_ERROR; + } + } + + if (iterations > 1) { + apr_time_clock_hires (g_mp); + T0 = apr_time_now(); + } + + for (i = 1; i <= iterations; i++) { + #ifdef VERBOSE + if (i % 100 == 0) { + if (i == 100) { + fprintf(stderr, "Iterations/100: ."); + } + else { + fprintf(stderr, "."); + } + } + #endif + + if (strcmp("tfn", type) == 0) { + /* Transformations */ + rc = test_tfn(&tfn_data, &out, &out_len, &errmsg); + if (rc < 0) { + fprintf(stderr, "ERROR: %s\n", errmsg); + result = RESULT_ERROR; + } + else if ((ret != -8888) && (rc != ret)) { + fprintf(stderr, "Returned %d (expected %d)\n", rc, ret); + result = RESULT_WRONGRET; + } + else if (param_len != out_len) { + fprintf(stderr, "Lenth %" APR_SIZE_T_FMT " (expected %" APR_SIZE_T_FMT ")\n", out_len, param_len); + result = RESULT_WRONGSIZE; + } + else { + result = memcmp(param, out, param_len) ? RESULT_MISMATCHED : RESULT_SUCCESS; + } + + if (result != RESULT_SUCCESS) { + apr_size_t s0len = nbytes; + const char *s0 = escape(buf, &s0len); + apr_size_t s1len = out_len; + const char *s1 = escape(out, &s1len); + apr_size_t s2len = param_len; + const char *s2 = escape(param, &s2len); + + fprintf(stderr, " Input: '%s' len=%" APR_SIZE_T_FMT "\n" + "Output: '%s' len=%" APR_SIZE_T_FMT "\n" + "Expect: '%s' len=%" APR_SIZE_T_FMT "\n", + s0, nbytes, s1, out_len, s2, param_len); + ec = 1; + } + } + else if (strcmp("op", type) == 0) { + /* Operators */ + rc = test_op(&op_data, &errmsg); + if (rc < 0) { + fprintf(stderr, "ERROR: %s\n", errmsg); + result = RESULT_ERROR; + } + else if (rc != ret) { + fprintf(stderr, "Returned %d (expected %d)\n", rc, ret); + result = RESULT_WRONGRET; + } + else { + result = RESULT_SUCCESS; + } + + if (result != RESULT_SUCCESS) { + apr_size_t s0len = nbytes; + const char *s0 = escape(buf, &s0len); + + fprintf(stderr, " Test: '@%s %s'\n" + "Input: '%s' len=%" APR_SIZE_T_FMT "\n", + name, param, s0, nbytes); + ec = 1; + } + } + else if (strcmp("action", type) == 0) { + /* Actions */ + int n; + const apr_array_header_t *arr; + apr_table_entry_t *te; + + rc = test_action(&action_data, &errmsg); + if (rc < 0) { + fprintf(stderr, "ERROR: %s\n", errmsg); + result = RESULT_ERROR; + } + else if (rc != ret) { + fprintf(stderr, "Returned %d (expected %d)\n", rc, ret); + result = RESULT_WRONGRET; + } + else { + result = RESULT_SUCCESS; + } + + if (result != RESULT_SUCCESS) { + fprintf(stderr, " Test: '%s:%s'\n" + "Prerun: '%s'\n", + name, param, (prerun ? (const char *)prerun : "")); + ec = 1; + } + + /* Store any collections that were initialized and changed */ + arr = apr_table_elts(g_msr->collections); + te = (apr_table_entry_t *)arr->elts; + for (n = 0; n < arr->nelts; n++) { + apr_table_t *col = (apr_table_t *)te[n].val; +// apr_table_t *orig_col = NULL; + + if (g_msr->txcfg->debuglog_level >= 9) { + msr_log(g_msr, 9, "Found loaded collection: %s", te[n].key); + } + /* Only store those collections that changed. */ + if (apr_table_get(g_msr->collections_dirty, te[n].key)) { + int x = collection_store(g_msr, col); + + if (g_msr->txcfg->debuglog_level >= 9) { + msr_log(g_msr, 9, "Stored collection: %s (%d)", te[n].key, x); + } + } +#if 0 + /* Re-populate the original values with the new ones. */ + if ((orig_col = (apr_table_t *)apr_table_get(g_msr->collections_original, te[n].key)) != NULL) { + const apr_array_header_t *orig_arr = apr_table_elts(orig_col); + apr_table_entry_t *orig_te = (apr_table_entry_t *)orig_arr->elts; + int m; + + for (m = 0; m < orig_arr->nelts; m++) { + msc_string *mstr = (msc_string *)apr_table_get(col, orig_te[m].key); + + if (g_msr->txcfg->debuglog_level >= 9) { + msr_log(g_msr, 9, "Updating original collection: %s.%s=%s", te[n].key, mstr->name, mstr->value); + } + //apr_table_setn(orig_col, orig_te[m].key, (void *)mstr ); + collection_original_setvar(g_msr, te[n].key, mstr); + + + } + } +#endif + } + apr_table_clear(g_msr->collections_dirty); + apr_table_clear(g_msr->collections_original); + } + else { + fprintf(stderr, "Unknown type: \"%s\"\n", type); + exit(1); + } + + if (ec != 0) { + fprintf(stdout, "%s\n", errmsg ? errmsg : ""); + return ec; + } + } + + if (iterations > 1) { + double dT; + T1 = apr_time_now(); + + dT = apr_time_as_msec(T1 - T0); + + #ifdef VERBOSE + if (i >= 100) { + fprintf(stderr, "\n"); + } + #endif + + fprintf(stdout, "%d @ %.4f msec per iteration.\n", iterations, dT / iterations); + } + fprintf(stdout, "%s\n", errmsg ? errmsg : ""); + + return ec; +} + + diff --git a/apache2/msc_util.c b/apache2/msc_util.c new file mode 100644 index 0000000..1512040 --- /dev/null +++ b/apache2/msc_util.c @@ -0,0 +1,1399 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ +#include "msc_release.h" +#include "msc_util.h" + +#include +#include +#include +#include +#include + +#include + +/** + * NOTE: Be careful as these can ONLY be used on static values for X. + * (i.e. VALID_HEX(c++) will NOT work) + */ +#define VALID_HEX(X) (((X >= '0')&&(X <= '9')) || ((X >= 'a')&&(X <= 'f')) || ((X >= 'A')&&(X <= 'F'))) +#define ISODIGIT(X) ((X >= '0')&&(X <= '7')) + +#if (defined(WIN32) || defined(NETWARE)) +/** Windows does not define all the octal modes */ +#define S_IXOTH 00001 +#define S_IWOTH 00002 +#define S_IROTH 00004 +#define S_IXGRP 00010 +#define S_IWGRP 00020 +#define S_IRGRP 00040 +#define S_IXUSR 00100 +#define S_IWUSR 00200 +#define S_IRUSR 00400 +#define S_ISVTX 01000 +#define S_ISGID 02000 +#define S_ISUID 04000 +#endif /* defined(WIN32 || NETWARE) */ + +/** + * + */ +int parse_boolean(const char *input) { + if (input == NULL) return -1; + if (strcasecmp(input, "on") == 0) return 1; + if (strcasecmp(input, "true") == 0) return 1; + if (strcasecmp(input, "1") == 0) return 1; + if (strcasecmp(input, "off") == 0) return 0; + if (strcasecmp(input, "false") == 0) return 0; + if (strcasecmp(input, "0") == 0) return 0; + + return -1; +} + +/** + * Parses a string that contains a name-value pair in the form "name=value". + * IMP1 It does not check for whitespace between tokens. + */ +int parse_name_eq_value(apr_pool_t *mp, const char *input, char **name, char **value) { + char *p = NULL; + + if ((name == NULL)||(value == NULL)) return -1; + if (input == NULL) return 0; + + *name = NULL; + *value = NULL; + p = (char *)input; + + while((*p != '=')&&(*p != '\0')) p++; + if (*p == '\0') { + *name = (char *)input; + return 1; + } + + *name = apr_pstrmemdup(mp, input, p - input); + if (*name == NULL) return -1; + p++; + + *value = apr_pstrdup(mp, p); + if (*value == NULL) return -1; + + return 1; +} + +/** + * + * IMP1 Assumes NUL-terminated + */ +char *url_encode(apr_pool_t *mp, char *input, unsigned int input_len, int *changed) { + char *rval, *d; + unsigned int i, len; + + *changed = 0; + + len = input_len * 3 + 1; + d = rval = apr_palloc(mp, len); + if (rval == NULL) return NULL; + + /* ENH Only encode the characters that really need to be encoded. */ + + for(i = 0; i < input_len; i++) { + unsigned char c = input[i]; + + if (c == ' ') { + *d++ = '+'; + *changed = 1; + } else + if ( (c == 42) || ((c >= 48)&&(c <= 57)) || ((c >= 65)&&(c <= 90)) + || ((c >= 97)&&(c <= 122)) + ) { + *d++ = c; + } else { + *d++ = '%'; + c2x(c, (unsigned char *)d); + d += 2; + *changed = 1; + } + } + + *d = '\0'; + + return rval; +} + +/** + * Appends an URL-encoded version of the source string to the + * destination string, but makes sure that no more than "maxlen" + * bytes are added. + */ +char *strnurlencat(char *destination, char *source, unsigned int maxlen) { + char *s = source; + char *d = destination; + + /* ENH Only encode the characters that really need to be encoded. */ + + /* Advance to the end of destination string. */ + while(*d != '\0') d++; + + /* Loop while there's bytes in the source string or + * until we reach the output limit. + */ + while((*s != '\0')&&(maxlen > 0)) { + unsigned char c = *s; + + if (c == ' ') { + *d++ = '+'; + maxlen--; + } else + if ( (c == 42) || ((c >= 48)&&(c <= 57)) || ((c >= 65)&&(c <= 90)) + || ((c >= 97)&&(c <= 122)) + ) { + *d++ = c; + maxlen--; + } else { + if (maxlen >= 3) { + *d++ = '%'; + c2x(c, (unsigned char *)d); + d += 2; + maxlen -= 3; + } else { + /* If there's not enough room for the encoded + * byte we ignore it. + */ + maxlen = 0; + } + } + + s++; + } + + *d++ = '\0'; + + return destination; +} + +/** + * + */ +char *file_basename(apr_pool_t *mp, const char *filename) { + char *d, *p; + + if (filename == NULL) return NULL; + d = apr_pstrdup(mp, filename); + if (d == NULL) return NULL; + + p = strrchr(d, '/'); + if (p != NULL) d = p + 1; + p = strrchr(d, '\\'); + if (p != NULL) d = p + 1; + + return d; +} + +/** + * + */ +#ifdef WIN32 +char *file_dirname(apr_pool_t *p, const char *filename) { + char *b, *c, *d; + + if (filename == NULL) return NULL; + b = apr_pstrdup(p, filename); + if (b == NULL) return NULL; + + c = strrchr(b, '/'); + if (c != NULL) { + d = strrchr(c, '\\'); + if (d != NULL) *d = '\0'; + else *c = '\0'; + } else { + d = strrchr(b, '\\'); + if (d != NULL) *d = '\0'; + } + + return b; +} +#else +char *file_dirname(apr_pool_t *p, const char *filename) { + char *b, *c; + + if (filename == NULL) return NULL; + b = apr_pstrdup(p, filename); + if (b == NULL) return NULL; + + c = strrchr(b, '/'); + if (c != NULL) *c = '\0'; + + return b; +} +#endif + + +/** + * + */ +int hex2bytes_inplace(unsigned char *data, int len) { + unsigned char *d = data; + int i, count = 0; + + if ((data == NULL)||(len == 0)) return 0; + + for(i = 0; i <= len - 2; i += 2) { + *d++ = x2c(&data[i]); + count++; + } + *d = '\0'; + + return count; +} + +/** + * Converts a series of bytes into its hexadecimal + * representation. + */ +char *bytes2hex(apr_pool_t *pool, unsigned char *data, int len) { + static unsigned char b2hex[] = "0123456789abcdef"; + char *hex = NULL; + int i, j; + + hex = apr_palloc(pool, (len * 2) + 1); + if (hex == NULL) return NULL; + + j = 0; + for(i = 0; i < len; i++) { + hex[j++] = b2hex[data[i] >> 4]; + hex[j++] = b2hex[data[i] & 0x0f]; + } + hex[j] = 0; + + return hex; +} + +/** + * + */ +int is_token_char(unsigned char c) { + /* ENH Is the performance important at all? We could use a table instead. */ + + /* CTLs not allowed */ + if ((c <= 32)||(c >= 127)) return 0; + + switch(c) { + case '(' : + case ')' : + case '<' : + case '>' : + case '@' : + case ',' : + case ';' : + case ':' : + case '\\' : + case '"' : + case '/' : + case '[' : + case ']' : + case '?' : + case '=' : + return 0; + } + + return 1; +} + +/** + * + */ +int remove_lf_crlf_inplace(char *text) { + char *p = text; + int count = 0; + + if (text == NULL) return -1; + + while(*p != '\0') { + count++; + p++; + } + + if (count > 0) { + if (*(p - 1) == '\n') { + *(p - 1) = '\0'; + if (count > 1) { + if (*(p - 2) == '\r') { + *(p - 2) = '\0'; + } + } + } + } + + return 1; +} + +/** + * Converts a byte given as its hexadecimal representation + * into a proper byte. Handles uppercase and lowercase letters + * but does not check for overflows. + */ +unsigned char x2c(unsigned char *what) { + register unsigned char digit; + + digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0')); + digit *= 16; + digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0')); + + return digit; +} + +/** + * Converts a single hexadecimal digit into a decimal value. + */ +unsigned char xsingle2c(unsigned char *what) { + register unsigned char digit; + + digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0')); + + return digit; +} + +/** + * + */ +char *guess_tmp_dir(apr_pool_t *p) { + char *filename = NULL; + + /* ENH Use apr_temp_dir_get instead. */ + + #ifdef WIN32 + filename = apr_pcalloc(p, 256); + if (filename == NULL) return ""; + if (GetTempPath(255, filename) != 0) return filename; + #endif + + filename = getenv("TMPDIR"); + if (filename != NULL) return filename; + + filename = getenv("TEMP"); + if (filename != NULL) return filename; + + filename = getenv("TMP"); + if (filename != NULL) return filename; + + #if defined NETWARE + return("sys:/tmp/"); + #elif defined WIN32 + return(""); + #else + return("/tmp/"); + #endif +} + +/** + * + */ +char *current_logtime(apr_pool_t *mp) { + apr_time_exp_t t; + char tstr[100]; + apr_size_t len; + + apr_time_exp_lt(&t, apr_time_now()); + + apr_strftime(tstr, &len, 80, "%d/%b/%Y:%H:%M:%S ", &t); + apr_snprintf(tstr + strlen(tstr), 80 - strlen(tstr), "%c%.2d%.2d", + t.tm_gmtoff < 0 ? '-' : '+', + t.tm_gmtoff / (60 * 60), t.tm_gmtoff % (60 * 60)); + return apr_pstrdup(mp, tstr); +} + +/** + * + */ +char *current_filetime(apr_pool_t *mp) { + apr_time_exp_t t; + char tstr[100]; + apr_size_t len; + + apr_time_exp_lt(&t, apr_time_now()); + + apr_strftime(tstr, &len, 80, "%Y%m%d-%H%M%S", &t); + return apr_pstrdup(mp, tstr); +} + +/** + * + */ +int msc_mkstemp_ex(char *template, int mode) { + /* ENH Use apr_file_mktemp instead. */ + + #if !(defined(WIN32)||defined(NETWARE)) + return mkstemp(template); + #else + if (mktemp(template) == NULL) return -1; + return open(template, O_WRONLY | O_APPEND | O_CREAT | O_BINARY, mode); + #endif +} + +/** + * + */ +int msc_mkstemp(char *template) { + return msc_mkstemp_ex(template, CREATEMODE_UNISTD); +} + +/** + * Converts the input string to lowercase (in-place). + */ +char *strtolower_inplace(unsigned char *str) { + unsigned char *c = str; + + if (str == NULL) return NULL; + + while(*c != 0) { + *c = tolower(*c); + c++; + } + + return (char *)str; +} + +/** + * Converts a single byte into its hexadecimal representation. + * Will overwrite two bytes at the destination. + */ +unsigned char *c2x(unsigned what, unsigned char *where) { + static const char c2x_table[] = "0123456789abcdef"; + + what = what & 0xff; + *where++ = c2x_table[what >> 4]; + *where++ = c2x_table[what & 0x0f]; + + return where; +} + +char *log_escape(apr_pool_t *mp, const char *text) { + return _log_escape(mp, (const unsigned char *)text, text ? strlen(text) : 0, 1, 0); +} + +char *log_escape_nq(apr_pool_t *mp, const char *text) { + return _log_escape(mp, (const unsigned char *)text, text ? strlen(text) : 0, 0, 0); +} + +char *log_escape_ex(apr_pool_t *mp, const char *text, unsigned long int text_length) { + return _log_escape(mp, (const unsigned char *)text, text_length, 1, 0); +} + +char *log_escape_nq_ex(apr_pool_t *mp, const char *text, unsigned long int text_length) { + return _log_escape(mp, (const unsigned char *)text, text_length, 0, 0); +} + +char *log_escape_header_name(apr_pool_t *mp, const char *text) { + return _log_escape(mp, (const unsigned char *)text, text ? strlen(text) : 0, 0, 1); +} + +char *log_escape_raw(apr_pool_t *mp, const unsigned char *text, unsigned long int text_length) { + unsigned char *ret = apr_palloc(mp, text_length * 4 + 1); + unsigned long int i, j; + + for (i = 0, j = 0; i < text_length; i++, j += 4) { + ret[j] = '\\'; + ret[j+1] = 'x'; + c2x(text[i], ret+j+2); + } + ret[text_length * 4] = '\0'; + + return (char *)ret; +} + +/** + * Transform text to ASCII printable or hex escaped + */ +char *log_escape_hex(apr_pool_t *mp, const unsigned char *text, unsigned long int text_length) { + unsigned char *ret = apr_palloc(mp, text_length * 4 + 1); + unsigned long int i, j; + + for (i = 0, j = 0; i < text_length; i++) { + if ( (text[i] == '"') + ||(text[i] == '\\') + ||(text[i] <= 0x1f) + ||(text[i] >= 0x7f)) + { + ret[j] = '\\'; + ret[j+1] = 'x'; + c2x(text[i], ret+j+2); + j += 4; + } + else { + ret[j] = text[i]; + j ++; + } + } + ret[j] = '\0'; + + return (char *)ret; +} + +/** + * Transform input into a form safe for logging. + */ +char *_log_escape(apr_pool_t *mp, const unsigned char *input, unsigned long int input_len, + int escape_quotes, int escape_colon) +{ + unsigned char *d = NULL; + char *ret = NULL; + unsigned long int i; + + if (input == NULL) return NULL; + + ret = apr_palloc(mp, input_len * 4 + 1); + if (ret == NULL) return NULL; + d = (unsigned char *)ret; + + i = 0; + while(i < input_len) { + switch(input[i]) { + case ':' : + if (escape_colon) { + *d++ = '\\'; + *d++ = ':'; + } else { + *d++ = input[i]; + } + break; + case '"' : + if (escape_quotes) { + *d++ = '\\'; + *d++ = '"'; + } else { + *d++ = input[i]; + } + break; + case '\b' : + *d++ = '\\'; + *d++ = 'b'; + break; + case '\n' : + *d++ = '\\'; + *d++ = 'n'; + break; + case '\r' : + *d++ = '\\'; + *d++ = 'r'; + break; + case '\t' : + *d++ = '\\'; + *d++ = 't'; + break; + case '\v' : + *d++ = '\\'; + *d++ = 'v'; + break; + case '\\' : + *d++ = '\\'; + *d++ = '\\'; + break; + default : + if ((input[i] <= 0x1f)||(input[i] >= 0x7f)) { + *d++ = '\\'; + *d++ = 'x'; + c2x(input[i], d); + d += 2; + } else { + *d++ = input[i]; + } + break; + } + + i++; + } + + *d = 0; + + return ret; +} + +/** + * JavaScript decoding. + * IMP1 Assumes NUL-terminated + */ + +int js_decode_nonstrict_inplace(unsigned char *input, long int input_len) { + unsigned char *d = (unsigned char *)input; + long int i, count; + + if (input == NULL) return -1; + + i = count = 0; + while (i < input_len) { + if (input[i] == '\\') { + /* Character is an escape. */ + + if ( (i + 5 < input_len) && (input[i + 1] == 'u') + && (VALID_HEX(input[i + 2])) && (VALID_HEX(input[i + 3])) + && (VALID_HEX(input[i + 4])) && (VALID_HEX(input[i + 5])) ) + { + /* \uHHHH */ + + /* Use only the lower byte. */ + *d = x2c(&input[i + 4]); + + /* Full width ASCII (ff01 - ff5e) needs 0x20 added */ + if ( (*d > 0x00) && (*d < 0x5f) + && ((input[i + 2] == 'f') || (input[i + 2] == 'F')) + && ((input[i + 3] == 'f') || (input[i + 3] == 'F'))) + { + (*d) += 0x20; + } + + d++; + count++; + i += 6; + } + else if ( (i + 3 < input_len) && (input[i + 1] == 'x') + && VALID_HEX(input[i + 2]) && VALID_HEX(input[i + 3])) { + /* \xHH */ + *d++ = x2c(&input[i + 2]); + count++; + i += 4; + } + else if ((i + 1 < input_len) && ISODIGIT(input[i + 1])) { + /* \OOO (only one byte, \000 - \377) */ + char buf[4]; + int j = 0; + + while((i + 1 + j < input_len)&&(j < 3)) { + buf[j] = input[i + 1 + j]; + j++; + if (!ISODIGIT(input[i + 1 + j])) break; + } + buf[j] = '\0'; + + if (j > 0) { + /* Do not use 3 characters if we will be > 1 byte */ + if ((j == 3) && (buf[0] > '3')) { + j = 2; + buf[j] = '\0'; + } + *d++ = (unsigned char)strtol(buf, NULL, 8); + i += 1 + j; + count++; + } + } + else if (i + 1 < input_len) { + /* \C */ + unsigned char c = input[i + 1]; + switch(input[i + 1]) { + case 'a' : + c = '\a'; + break; + case 'b' : + c = '\b'; + break; + case 'f' : + c = '\f'; + break; + case 'n' : + c = '\n'; + break; + case 'r' : + c = '\r'; + break; + case 't' : + c = '\t'; + break; + case 'v' : + c = '\v'; + break; + /* The remaining (\?,\\,\',\") are just a removal + * of the escape char which is default. + */ + } + + *d++ = c; + i += 2; + count++; + } + else { + /* Not enough bytes */ + while(i < input_len) { + *d++ = input[i++]; + count++; + } + } + } + else { + *d++ = input[i++]; + count++; + } + } + + *d = '\0'; + + return count; +} + +/** + * + * IMP1 Assumes NUL-terminated + */ +int urldecode_uni_nonstrict_inplace_ex(unsigned char *input, long int input_len, int *changed) { + unsigned char *d = input; + long int i, count; + + *changed = 0; + + if (input == NULL) return -1; + + i = count = 0; + while (i < input_len) { + if (input[i] == '%') { + /* Character is a percent sign. */ + + if ((i + 1 < input_len)&&( (input[i + 1] == 'u')||(input[i + 1] == 'U') )) { + /* IIS-specific %u encoding. */ + if (i + 5 < input_len) { + /* We have at least 4 data bytes. */ + if ( (VALID_HEX(input[i + 2]))&&(VALID_HEX(input[i + 3])) + &&(VALID_HEX(input[i + 4]))&&(VALID_HEX(input[i + 5])) ) + { + /* We first make use of the lower byte here, ignoring the higher byte. */ + *d = x2c(&input[i + 4]); + + /* Full width ASCII (ff01 - ff5e) needs 0x20 added */ + if ( (*d > 0x00) && (*d < 0x5f) + && ((input[i + 2] == 'f') || (input[i + 2] == 'F')) + && ((input[i + 3] == 'f') || (input[i + 3] == 'F'))) + { + (*d) += 0x20; + } + + d++; + count++; + i += 6; + *changed = 1; + } else { + /* Invalid data, skip %u. */ + *d++ = input[i++]; + *d++ = input[i++]; + count += 2; + } + } else { + /* Not enough bytes (4 data bytes), skip %u. */ + *d++ = input[i++]; + *d++ = input[i++]; + count += 2; + } + } + else { + /* Standard URL encoding. */ + + /* Are there enough bytes available? */ + if (i + 2 < input_len) { + /* Yes. */ + + /* Decode a %xx combo only if it is valid. + */ + char c1 = input[i + 1]; + char c2 = input[i + 2]; + + if (VALID_HEX(c1) && VALID_HEX(c2)) { + *d++ = x2c(&input[i + 1]); + count++; + i += 3; + *changed = 1; + } else { + /* Not a valid encoding, skip this % */ + *d++ = input[i++]; + count++; + } + } else { + /* Not enough bytes available, skip this % */ + *d++ = input[i++]; + count++; + } + } + } + else { + /* Character is not a percent sign. */ + if (input[i] == '+') { + *d++ = ' '; + *changed = 1; + } else { + *d++ = input[i]; + } + + count++; + i++; + } + } + + *d = '\0'; + + return count; +} + +/** + * + * IMP1 Assumes NUL-terminated + */ +int urldecode_nonstrict_inplace_ex(unsigned char *input, long int input_len, int *invalid_count, int *changed) { + unsigned char *d = (unsigned char *)input; + long int i, count; + + *changed = 0; + + if (input == NULL) return -1; + + i = count = 0; + while (i < input_len) { + if (input[i] == '%') { + /* Character is a percent sign. */ + + /* Are there enough bytes available? */ + if (i + 2 < input_len) { + char c1 = input[i + 1]; + char c2 = input[i + 2]; + + if (VALID_HEX(c1) && VALID_HEX(c2)) { + /* Valid encoding - decode it. */ + *d++ = x2c(&input[i + 1]); + count++; + i += 3; + *changed = 1; + } else { + /* Not a valid encoding, skip this % */ + *d++ = input[i++]; + count ++; + (*invalid_count)++; + } + } else { + /* Not enough bytes available, copy the raw bytes. */ + *d++ = input[i++]; + count ++; + (*invalid_count)++; + } + } else { + /* Character is not a percent sign. */ + if (input[i] == '+') { + *d++ = ' '; + *changed = 1; + } else { + *d++ = input[i]; + } + count++; + i++; + } + } + + *d = '\0'; + + return count; +} + +/** + * + * IMP1 Assumes NUL-terminated + */ +int html_entities_decode_inplace(apr_pool_t *mp, unsigned char *input, int input_len) { + unsigned char *d = input; + int i, count; + + if ((input == NULL)||(input_len <= 0)) return 0; + + i = count = 0; + while((i < input_len)&&(count < input_len)) { + int z, copy = 1; + + /* Require an ampersand and at least one character to + * start looking into the entity. + */ + if ((input[i] == '&')&&(i + 1 < input_len)) { + int k, j = i + 1; + + if (input[j] == '#') { + /* Numerical entity. */ + copy++; + + if (!(j + 1 < input_len)) goto HTML_ENT_OUT; /* Not enough bytes. */ + j++; + + if ((input[j] == 'x')||(input[j] == 'X')) { + /* Hexadecimal entity. */ + copy++; + + if (!(j + 1 < input_len)) goto HTML_ENT_OUT; /* Not enough bytes. */ + j++; /* j is the position of the first digit now. */ + + k = j; + while((j < input_len)&&(isxdigit(input[j]))) j++; + if (j > k) { /* Do we have at least one digit? */ + /* Decode the entity. */ + char *x = apr_pstrmemdup(mp, (const char *)&input[k], j - k); + *d++ = (unsigned char)strtol(x, NULL, 16); + count++; + + /* Skip over the semicolon if it's there. */ + if ((j < input_len)&&(input[j] == ';')) i = j + 1; + else i = j; + + continue; + } else { + goto HTML_ENT_OUT; + } + } else { + /* Decimal entity. */ + k = j; + while((j < input_len)&&(isdigit(input[j]))) j++; + if (j > k) { /* Do we have at least one digit? */ + /* Decode the entity. */ + char *x = apr_pstrmemdup(mp, (const char *)&input[k], j - k); + *d++ = (unsigned char)strtol(x, NULL, 10); + count++; + + /* Skip over the semicolon if it's there. */ + if ((j < input_len)&&(input[j] == ';')) i = j + 1; + else i = j; + + continue; + } else { + goto HTML_ENT_OUT; + } + } + } else { + /* Text entity. */ + + k = j; + while((j < input_len)&&(isalnum(input[j]))) j++; + if (j > k) { /* Do we have at least one digit? */ + char *x = apr_pstrmemdup(mp, (const char *)&input[k], j - k); + + /* Decode the entity. */ + /* ENH What about others? */ + if (strcasecmp(x, "quot") == 0) *d++ = '"'; + else + if (strcasecmp(x, "amp") == 0) *d++ = '&'; + else + if (strcasecmp(x, "lt") == 0) *d++ = '<'; + else + if (strcasecmp(x, "gt") == 0) *d++ = '>'; + else + if (strcasecmp(x, "nbsp") == 0) *d++ = NBSP; + else { + /* We do no want to convert this entity, copy the raw data over. */ + copy = j - k + 1; + goto HTML_ENT_OUT; + } + + count++; + + /* Skip over the semicolon if it's there. */ + if ((j < input_len)&&(input[j] == ';')) i = j + 1; + else i = j; + + continue; + } + } + } + + HTML_ENT_OUT: + + for(z = 0; ((z < copy) && (count < input_len)); z++) { + *d++ = input[i++]; + count++; + } + } + + *d = '\0'; + + return count; +} + +/** + * + * IMP1 Assumes NUL-terminated + */ +int ansi_c_sequences_decode_inplace(unsigned char *input, int input_len) { + unsigned char *d = input; + int i, count; + + i = count = 0; + while(i < input_len) { + if ((input[i] == '\\')&&(i + 1 < input_len)) { + int c = -1; + + switch(input[i + 1]) { + case 'a' : + c = '\a'; + break; + case 'b' : + c = '\b'; + break; + case 'f' : + c = '\f'; + break; + case 'n' : + c = '\n'; + break; + case 'r' : + c = '\r'; + break; + case 't' : + c = '\t'; + break; + case 'v' : + c = '\v'; + break; + case '\\' : + c = '\\'; + break; + case '?' : + c = '?'; + break; + case '\'' : + c = '\''; + break; + case '"' : + c = '"'; + break; + } + + if (c != -1) i += 2; + + /* Hexadecimal or octal? */ + if (c == -1) { + if ((input[i + 1] == 'x')||(input[i + 1] == 'X')) { + /* Hexadecimal. */ + if ((i + 3 < input_len)&&(isxdigit(input[i + 2]))&&(isxdigit(input[i + 3]))) { + /* Two digits. */ + c = x2c(&input[i + 2]); + i += 4; + } else { + /* Invalid encoding, do nothing. */ + } + } + else + if (ISODIGIT(input[i + 1])) { /* Octal. */ + char buf[4]; + int j = 0; + + while((i + 1 + j < input_len)&&(j < 3)) { + buf[j] = input[i + 1 + j]; + j++; + if (!ISODIGIT(input[i + 1 + j])) break; + } + buf[j] = '\0'; + + if (j > 0) { + c = strtol(buf, NULL, 8); + i += 1 + j; + } + } + } + + if (c == -1) { + /* Didn't recognise encoding, copy raw bytes. */ + *d++ = input[i + 1]; + count++; + i += 2; + } else { + /* Converted the encoding. */ + *d++ = c; + count++; + } + } else { + /* Input character not a backslash, copy it. */ + *d++ = input[i++]; + count++; + } + } + + *d = '\0'; + + return count; +} + +/** + * + * IMP1 Assumes NUL-terminated + */ +int normalise_path_inplace(unsigned char *input, int input_len, int win, int *changed) { + unsigned char *d = input; + int i, count; + + *changed = 0; + + i = count = 0; + while ((i < input_len)&&(count < input_len)) { + char c = input[i]; + + /* Convert backslash to forward slash on Windows only. */ + if ((win)&&(c == '\\')) { + c = '/'; + *changed = 1; + } + + if (c == '/') { + /* Is there a directory back-reference? Yes, we + * require at least 5 prior bytes here. That's on + * purpose. + */ + if ((count >= 5)&&(*(d - 1) == '.')&&(*(d - 2) == '.')&&(*(d - 3) == '/')) { + unsigned char *cd = d - 4; + int ccount = count - 4; + + *changed = 1; + + /* Go back until we reach the beginning or a forward slash. */ + while ((ccount > 0)&&(*cd != '/')) { + ccount--; + cd--; + } + + if (*cd == '/') { + d = cd; + count = ccount; + } + } else + /* Is there a directory self-reference? */ + if ((count >= 2)&&(*(d - 1) == '.')&&(*(d - 2) == '/')) { + /* Ignore the last two bytes. */ + d -= 2; + count -= 2; + *changed = 1; + } else + /* Or are there just multiple occurences of forward slash? */ + if ((count >= 1)&&(*(d - 1) == '/')) { + /* Ignore the last one byte. */ + d--; + count--; + *changed = 1; + } + } + + /* Copy the byte over. */ + *d++ = c; + count++; + i++; + } + + *d = '\0'; + + return count; +} + +char *modsec_build(apr_pool_t *mp) { + return apr_psprintf(mp, "%02i%02i%02i%1i%02i", + atoi(MODSEC_VERSION_MAJOR), + atoi(MODSEC_VERSION_MINOR), + atoi(MODSEC_VERSION_MAINT), + get_modsec_build_type(NULL), + atoi(MODSEC_VERSION_RELEASE)); +} + +int is_empty_string(const char *string) { + unsigned int i; + + if (string == NULL) return 1; + + for(i = 0; string[i] != '\0'; i++) { + if (!isspace(string[i])) { + return 0; + } + } + + return 1; +} + +char *resolve_relative_path(apr_pool_t *pool, const char *parent_filename, const char *filename) { + if (filename == NULL) return NULL; + // TODO Support paths on operating systems other than Unix. + if (filename[0] == '/') return (char *)filename; + + return apr_pstrcat(pool, apr_pstrndup(pool, parent_filename, + strlen(parent_filename) - strlen(apr_filepath_name_get(parent_filename))), + filename, NULL); +} + +/** + * Decode a string that contains CSS-escaped characters. + * + * References: + * http://www.w3.org/TR/REC-CSS2/syndata.html#q4 + * http://www.unicode.org/roadmaps/ + */ +int css_decode_inplace(unsigned char *input, long int input_len) { + unsigned char *d = (unsigned char *)input; + long int i, j, count; + + if (input == NULL) return -1; + + i = count = 0; + while (i < input_len) { + + /* Is the character a backslash? */ + if (input[i] == '\\') { + + /* Is there at least one more byte? */ + if (i + 1 < input_len) { + i++; /* We are not going to need the backslash. */ + + /* Check for 1-6 hex characters following the backslash */ + j = 0; + while ( (j < 6) + && (i + j < input_len) + && (VALID_HEX(input[i + j]))) + { + j++; + } + + if (j > 0) { /* We have at least one valid hexadecimal character. */ + int fullcheck = 0; + + /* For now just use the last two bytes. */ + switch (j) { + /* Number of hex characters */ + case 1: + *d++ = xsingle2c(&input[i]); + break; + + case 2: + case 3: + /* Use the last two from the end. */ + *d++ = x2c(&input[i + j - 2]); + break; + + case 4: + /* Use the last two from the end, but request + * a full width check. + */ + *d = x2c(&input[i + j - 2]); + fullcheck = 1; + break; + + case 5: + /* Use the last two from the end, but request + * a full width check if the number is greater + * or equal to 0xFFFF. + */ + *d = x2c(&input[i + j - 2]); + + /* Do full check if first byte is 0 */ + if (input[i] == '0') { + fullcheck = 1; + } + else { + d++; + } + break; + + case 6: + /* Use the last two from the end, but request + * a full width check if the number is greater + * or equal to 0xFFFF. + */ + *d = x2c(&input[i + j - 2]); + + /* Do full check if first/second bytes are 0 */ + if ( (input[i] == '0') + && (input[i + 1] == '0') + ) { + fullcheck = 1; + } + else { + d++; + } + break; + } + + /* Full width ASCII (0xff01 - 0xff5e) needs 0x20 added */ + if (fullcheck) { + if ( (*d > 0x00) && (*d < 0x5f) + && ((input[i + j - 3] == 'f') || + (input[i + j - 3] == 'F')) + && ((input[i + j - 4] == 'f') || + (input[i + j - 4] == 'F'))) + { + (*d) += 0x20; + } + + d++; + } + + /* We must ignore a single whitespace after a hex escape */ + if ((i + j < input_len) && isspace(input[i + j])) { + j++; + } + + /* Move over. */ + count++; + i += j; + } + + /* No hexadecimal digits after backslash */ + else if (input[i] == '\n') { + /* A newline character following backslash is ignored. */ + i++; + } + + /* The character after backslash is not a hexadecimal digit, nor a newline. */ + else { + /* Use one character after backslash as is. */ + *d++ = input[i++]; + count++; + } + } + + /* No characters after backslash. */ + else { + /* Do not include backslash in output (continuation to nothing) */ + i++; + } + } + + /* Character is not a backslash. */ + else { + /* Copy one normal character to output. */ + *d++ = input[i++]; + count++; + } + } + + /* Terminate output string. */ + *d = '\0'; + + return count; +} + +/** + * Translate UNIX octal umask/mode to APR apr_fileperms_t + */ +apr_fileperms_t mode2fileperms(int mode) { + apr_fileperms_t perms = 0; + + if (mode & S_IXOTH) perms |= APR_WEXECUTE; + if (mode & S_IWOTH) perms |= APR_WWRITE; + if (mode & S_IROTH) perms |= APR_WREAD; + if (mode & S_IXGRP) perms |= APR_GEXECUTE; + if (mode & S_IWGRP) perms |= APR_GWRITE; + if (mode & S_IRGRP) perms |= APR_GREAD; + if (mode & S_IXUSR) perms |= APR_UEXECUTE; + if (mode & S_IWUSR) perms |= APR_UWRITE; + if (mode & S_IRUSR) perms |= APR_UREAD; + if (mode & S_ISVTX) perms |= APR_WSTICKY; + if (mode & S_ISGID) perms |= APR_GSETID; + if (mode & S_ISUID) perms |= APR_USETID; + + return perms; +} + diff --git a/apache2/msc_util.h b/apache2/msc_util.h new file mode 100644 index 0000000..f91ec3a --- /dev/null +++ b/apache2/msc_util.h @@ -0,0 +1,104 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ +#ifndef _UTIL_H_ +#define _UTIL_H_ + +#include +#include + +#include "modsecurity.h" + +int DSOLOCAL normalise_path_inplace(unsigned char *input, int len, int win, int *changed); + +int DSOLOCAL parse_boolean(const char *input); + +int DSOLOCAL parse_name_eq_value(apr_pool_t *mp, const char *input, char **name, char **value); + +char DSOLOCAL *url_encode(apr_pool_t *mp, char *input, unsigned int input_len, int *changed); + +char DSOLOCAL *strnurlencat(char *destination, char *source, unsigned int maxlen); + +char DSOLOCAL *file_dirname(apr_pool_t *p, const char *filename); + +char DSOLOCAL *file_basename(apr_pool_t *p, const char *filename); + +int DSOLOCAL hex2bytes_inplace(unsigned char *data, int len); + +char DSOLOCAL *bytes2hex(apr_pool_t *pool, unsigned char *data, int len); + +int DSOLOCAL is_token_char(unsigned char c); + +int DSOLOCAL remove_lf_crlf_inplace(char *text); + +unsigned char DSOLOCAL x2c(unsigned char *what); + +unsigned char DSOLOCAL xsingle2c(unsigned char *what); + +char DSOLOCAL *guess_tmp_dir(apr_pool_t *p); + +char DSOLOCAL *current_logtime(apr_pool_t *mp); + +char DSOLOCAL *current_filetime(apr_pool_t *mp); + +int DSOLOCAL msc_mkstemp_ex(char *template, int mode); + +int DSOLOCAL msc_mkstemp(char *template); + +char DSOLOCAL *strtolower_inplace(unsigned char *str); + +unsigned char DSOLOCAL *c2x(unsigned what, unsigned char *where); + +char DSOLOCAL *log_escape(apr_pool_t *p, const char *text); + +char DSOLOCAL *log_escape_nq(apr_pool_t *p, const char *text); + +char DSOLOCAL *log_escape_ex(apr_pool_t *p, const char *text, unsigned long int text_length); + +char DSOLOCAL *log_escape_nq_ex(apr_pool_t *p, const char *text, unsigned long int text_length); + +char DSOLOCAL *log_escape_header_name(apr_pool_t *p, const char *text); + +char DSOLOCAL *log_escape_hex(apr_pool_t *mp, const unsigned char *text, unsigned long int text_length); + +char DSOLOCAL *log_escape_raw(apr_pool_t *mp, const unsigned char *text, unsigned long int text_length); + +char DSOLOCAL *_log_escape(apr_pool_t *p, const unsigned char *input, + unsigned long int input_length, int escape_quotes, int escape_colon); + +int DSOLOCAL js_decode_nonstrict_inplace(unsigned char *input, long int input_len); + +int DSOLOCAL urldecode_uni_nonstrict_inplace_ex(unsigned char *input, long int input_length, int * changed); + +int DSOLOCAL urldecode_nonstrict_inplace_ex(unsigned char *input, long int input_length, int *invalid_count, int *changed); + +int DSOLOCAL html_entities_decode_inplace(apr_pool_t *mp, unsigned char *input, int len); + +int DSOLOCAL ansi_c_sequences_decode_inplace(unsigned char *input, int len); + +char DSOLOCAL *modsec_build(apr_pool_t *mp); + +int DSOLOCAL is_empty_string(const char *string); + +char DSOLOCAL *resolve_relative_path(apr_pool_t *pool, const char *parent_filename, const char *filename); + +int DSOLOCAL css_decode_inplace(unsigned char *input, long int input_len); + +apr_fileperms_t DSOLOCAL mode2fileperms(int mode); + +#endif diff --git a/apache2/msc_xml.c b/apache2/msc_xml.c new file mode 100644 index 0000000..4f33014 --- /dev/null +++ b/apache2/msc_xml.c @@ -0,0 +1,139 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ +#include "msc_xml.h" + + +/** + * Initialise XML parser. + */ +int xml_init(modsec_rec *msr, char **error_msg) { + if (error_msg == NULL) return -1; + *error_msg = NULL; + + msr->xml = apr_pcalloc(msr->mp, sizeof(xml_data)); + if (msr->xml == NULL) return -1; + + return 1; +} + +#if 0 +static void xml_receive_sax_error(void *data, const char *msg, ...) { + modsec_rec *msr = (modsec_rec *)data; + char message[256]; + + if (msr == NULL) return; + + apr_snprintf(message, sizeof(message), "%s (line %d offset %d)", + log_escape_nq(msr->mp, msr->xml->parsing_ctx->lastError.message), + msr->xml->parsing_ctx->lastError.line, + msr->xml->parsing_ctx->lastError.int2); + + msr_log(msr, 5, "XML: Parsing error: %s", message); +} +#endif + +/** + * Feed one chunk of data to the XML parser. + */ +int xml_process_chunk(modsec_rec *msr, const char *buf, unsigned int size, char **error_msg) { + if (error_msg == NULL) return -1; + *error_msg = NULL; + + /* We want to initialise our parsing context here, to + * enable us to pass it the first chunk of data so that + * it can attempt to auto-detect the encoding. + */ + if (msr->xml->parsing_ctx == NULL) { + + /* First invocation. */ + + msr_log(msr, 4, "XML: Initialising parser."); + + /* NOTE When Sax interface is used libxml will not + * create the document object, but we need it. + + msr->xml->sax_handler = (xmlSAXHandler *)apr_pcalloc(msr->mp, sizeof(xmlSAXHandler)); + if (msr->xml->sax_handler == NULL) return -1; + msr->xml->sax_handler->error = xml_receive_sax_error; + msr->xml->sax_handler->warning = xml_receive_sax_error; + msr->xml->parsing_ctx = xmlCreatePushParserCtxt(msr->xml->sax_handler, msr, + buf, size, "body.xml"); + + */ + + msr->xml->parsing_ctx = xmlCreatePushParserCtxt(NULL, NULL, buf, size, "body.xml"); + if (msr->xml->parsing_ctx == NULL) { + *error_msg = apr_psprintf(msr->mp, "XML: Failed to create parsing context."); + return -1; + } + } else { + + /* Not a first invocation. */ + + xmlParseChunk(msr->xml->parsing_ctx, buf, size, 0); + if (msr->xml->parsing_ctx->wellFormed != 1) { + *error_msg = apr_psprintf(msr->mp, "XML: Failed parsing document."); + return -1; + } + } + + return 1; +} + +/** + * Finalise XML parsing. + */ +int xml_complete(modsec_rec *msr, char **error_msg) { + if (error_msg == NULL) return -1; + *error_msg = NULL; + + /* Only if we have a context, meaning we've done some work. */ + if (msr->xml->parsing_ctx != NULL) { + /* This is how we signalise the end of parsing to libxml. */ + xmlParseChunk(msr->xml->parsing_ctx, NULL, 0, 1); + + /* Preserve the results for our reference. */ + msr->xml->well_formed = msr->xml->parsing_ctx->wellFormed; + msr->xml->doc = msr->xml->parsing_ctx->myDoc; + + /* Clean up everything else. */ + xmlFreeParserCtxt(msr->xml->parsing_ctx); + msr->xml->parsing_ctx = NULL; + msr_log(msr, 4, "XML: Parsing complete (well_formed %u).", msr->xml->well_formed); + + if (msr->xml->well_formed != 1) { + *error_msg = apr_psprintf(msr->mp, "XML: Failed parsing document."); + return -1; + } + } + + return 1; +} + +/** + * Frees the resources used for XML parsing. + */ +apr_status_t xml_cleanup(modsec_rec *msr) { + if (msr->xml->doc != NULL) { + xmlFreeDoc(msr->xml->doc); + msr->xml->doc = NULL; + } + + return 1; +} diff --git a/apache2/msc_xml.h b/apache2/msc_xml.h new file mode 100644 index 0000000..34c078e --- /dev/null +++ b/apache2/msc_xml.h @@ -0,0 +1,49 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ +#ifndef _MSC_XML_H_ +#define _MSC_XML_H_ + +typedef struct xml_data xml_data; + +#include "modsecurity.h" +#include +#include + +/* Structures */ + +struct xml_data { + xmlSAXHandler *sax_handler; + xmlParserCtxtPtr parsing_ctx; + xmlDocPtr doc; + + unsigned int well_formed; +}; + +/* Functions */ + +int DSOLOCAL xml_init(modsec_rec *msr, char **error_msg); + +int DSOLOCAL xml_process_chunk(modsec_rec *msr, const char *buf, + unsigned int size, char **error_msg); + +int DSOLOCAL xml_complete(modsec_rec *msr, char **error_msg); + +apr_status_t DSOLOCAL xml_cleanup(modsec_rec *msr); + +#endif diff --git a/apache2/pdf_protect.c b/apache2/pdf_protect.c new file mode 100644 index 0000000..e1e6c86 --- /dev/null +++ b/apache2/pdf_protect.c @@ -0,0 +1,498 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ +#include "modsecurity.h" +#include "apache2.h" +#include "pdf_protect.h" + +#include +#include "apr_sha1.h" + +#define DEFAULT_TIMEOUT 10 +#define DEFAULT_TOKEN_NAME "PDFPTOKEN" +#define ATTACHMENT_MIME_TYPE "application/octet-stream" +#define NOTE_TWEAK_HEADERS "pdfp-note-tweakheaders" +#define NOTE_DONE "pdfp-note-done" +#define REDIRECT_STATUS HTTP_TEMPORARY_REDIRECT +#define DISPOSITION_VALUE "attachment;" + +// TODO We need ID and REV values for the PDF XSS alert. + +// TODO It would be nice if the user could choose the ID/REV/SEVERITY/MESSAGE, etc. + +static char *encode_sha1_base64(apr_pool_t *mp, const char *data) { + unsigned char digest[APR_SHA1_DIGESTSIZE]; + apr_sha1_ctx_t context; + + /* Calculate the hash first. */ + apr_sha1_init(&context); + apr_sha1_update(&context, data, strlen(data)); + apr_sha1_final(digest, &context); + + /* Now transform with transport-friendly hex encoding. */ + return bytes2hex(mp, digest, APR_SHA1_DIGESTSIZE); +} + +static char *create_hash(modsec_rec *msr, + const char *time_string) +{ + const char *content = NULL; + + if (msr->txcfg->pdfp_secret == NULL) { + msr_log(msr, 1, "PdfProtect: Unable to generate hash. Please configure SecPdfProtectSecret."); + return NULL; + } + + /* Our protection token is made out of the client's IP + * address, the secret key, and the token expiry time. + */ + content = apr_pstrcat(msr->mp, msr->remote_addr, msr->txcfg->pdfp_secret, + time_string, NULL); + if (content == NULL) return NULL; + + return encode_sha1_base64(msr->mp, content); +} + +/** + * + */ +static char *create_token(modsec_rec *msr) { + apr_time_t current_time; + const char *time_string = NULL; + const char *hash = NULL; + int timeout = DEFAULT_TIMEOUT; + + if (msr->txcfg->pdfp_timeout != -1) { + timeout = msr->txcfg->pdfp_timeout; + } + + current_time = apr_time_sec(apr_time_now()); + time_string = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, (apr_time_t)(current_time + timeout)); + if (time_string == NULL) return NULL; + + hash = create_hash(msr, time_string); + if (hash == NULL) return NULL; + + return apr_pstrcat(msr->mp, hash, "|", time_string, NULL); +} + +/** + * + */ +static char *construct_new_uri(modsec_rec *msr) { + const char *token_parameter = NULL; + const char *new_uri = NULL; + const char *token = NULL; + const char *token_name = DEFAULT_TOKEN_NAME; + + token = create_token(msr); + if (token == NULL) return NULL; + + if (msr->txcfg->pdfp_token_name != NULL) { + token_name = msr->txcfg->pdfp_token_name; + } + + token_parameter = apr_pstrcat(msr->mp, token_name, "=", token, NULL); + if (token_parameter == NULL) return NULL; + + if (msr->r->args == NULL) { /* No other parameters. */ + new_uri = apr_pstrcat(msr->mp, msr->r->uri, "?", token_parameter, "#PDFP", NULL); + } else { /* Preserve existing paramters. */ + new_uri = apr_pstrcat(msr->mp, msr->r->uri, "?", msr->r->args, "&", + token_parameter, "#PDFP", NULL); + } + + return (char *)new_uri; +} + +/** + * + */ +static char *extract_token(modsec_rec *msr) { + char *search_string = NULL; + char *p = NULL, *t = NULL; + const char *token_name = DEFAULT_TOKEN_NAME; + + if ((msr->r == NULL)||(msr->r->args == NULL)) { + return NULL; + } + + if (msr->txcfg->pdfp_token_name != NULL) { + token_name = msr->txcfg->pdfp_token_name; + } + + search_string = apr_pstrcat(msr->mp, msr->txcfg->pdfp_token_name, "=", NULL); + if (search_string == NULL) return NULL; + + p = strstr(msr->r->args, search_string); + if (p == NULL) return NULL; + + t = p = p + strlen(search_string); + while ((*t != '\0')&&(*t != '&')) t++; + + return apr_pstrmemdup(msr->mp, p, t - p); +} + +/** + * + */ +static int validate_time_string(const char *time_string) { + char *p = (char *)time_string; + + while(*p != '\0') { + if (!isdigit(*p)) return 0; + p++; + } + + return 1; +} + +/** + * + */ +static int verify_token(modsec_rec *msr, const char *token, char **error_msg) { + unsigned int current_time, expiry_time; + const char *time_string = NULL; + const char *given_hash = NULL; + const char *hash = NULL; + const char *p = NULL; + + if (error_msg == NULL) return 0; + *error_msg = NULL; + + /* Split token into its parts - hash and expiry time. */ + p = strstr(token, "|"); + if (p == NULL) return 0; + + given_hash = apr_pstrmemdup(msr->mp, token, p - token); + time_string = p + 1; + if (!validate_time_string(time_string)) { + *error_msg = apr_psprintf(msr->mp, "PdfProtect: Invalid time string: %s", + log_escape_nq(msr->mp, time_string)); + return 0; + } + expiry_time = atoi(time_string); + + /* Check the hash. */ + hash = create_hash(msr, time_string); + if (strcmp(given_hash, hash) != 0) { + *error_msg = apr_psprintf(msr->mp, "PdfProtect: Invalid hash: %s (expected %s)", + log_escape_nq(msr->mp, given_hash), log_escape_nq(msr->mp, hash)); + return 0; + } + + /* Check time. */ + current_time = apr_time_sec(apr_time_now()); + if (current_time > expiry_time) { + *error_msg = apr_psprintf(msr->mp, "PdfProtect: Token has expired."); + return 0; + } + + return 1; +} + +/** + * + */ +apr_status_t pdfp_output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) { + modsec_rec *msr = (modsec_rec *)f->ctx; + + if (msr == NULL) { + ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, f->r->server, + "ModSecurity: Internal Error: Unable to retrieve context in PDF output filter."); + + ap_remove_output_filter(f); + + return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR); + } + + if (msr->txcfg->pdfp_enabled == 1) { + // TODO Should we look at err_headers_out too? + const char *h_content_type = apr_table_get(f->r->headers_out, "Content-Type"); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "PdfProtect: r->content_type=%s, header C-T=%s", + log_escape_nq(msr->mp, f->r->content_type), + log_escape_nq(msr->mp, h_content_type)); + } + + /* Have we been asked to tweak the headers? */ + if (apr_table_get(f->r->notes, NOTE_TWEAK_HEADERS) != NULL) { + /* Yes! */ + apr_table_set(f->r->headers_out, "Content-Disposition", DISPOSITION_VALUE); + f->r->content_type = ATTACHMENT_MIME_TYPE; + } + + /* Check if we've already done the necessary work in + * the first phase. + */ + if (apr_table_get(f->r->notes, NOTE_DONE) != NULL) { + /* We have, so return straight away. */ + ap_remove_output_filter(f); + return ap_pass_brigade(f->next, bb_in); + } + + /* Proceed to detect dynamically-generated PDF files. */ + + // TODO application/x-pdf, application/vnd.fdf, application/vnd.adobe.xfdf, + // application/vnd.adobe.xdp+xml, application/vnd.adobe.xfd+xml, application/vnd.pdf + // application/acrobat, text/pdf, text/x-pdf ??? + if (((f->r->content_type != NULL)&&(strcasecmp(f->r->content_type, "application/pdf") == 0)) + || ((h_content_type != NULL)&&(strcasecmp(h_content_type, "application/pdf") == 0))) + { + request_rec *r = f->r; + const char *token = NULL; + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "PdfProtect: Detected a dynamically-generated PDF in %s", + log_escape_nq(msr->mp, r->uri)); + } + + /* If we are configured with ForcedDownload protection method then we + * can do our thing here and finish early. + */ + if (msr->txcfg->pdfp_method == PDF_PROTECT_METHOD_FORCED_DOWNLOAD) { + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "PdfProtect: Forcing download of a dynamically " + "generated PDF file."); + } + + apr_table_set(f->r->headers_out, "Content-Disposition", DISPOSITION_VALUE); + f->r->content_type = ATTACHMENT_MIME_TYPE; + + ap_remove_output_filter(f); + + return ap_pass_brigade(f->next, bb_in); + } + + /* If we are here that means TokenRedirection is the desired protection method. */ + + /* Is this a non-GET request? */ + if ((f->r->method_number != M_GET)&& + ((msr->txcfg->pdfp_only_get == 1)||(msr->txcfg->pdfp_only_get == -1)) + ) { + /* This is a non-GET request and we have been configured + * not to intercept it. So we are going to tweak the headers + * to force download. + */ + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "PdfProtect: Forcing download of a dynamically " + "generated PDF file and non-GET method."); + } + + apr_table_set(f->r->headers_out, "Content-Disposition", DISPOSITION_VALUE); + f->r->content_type = ATTACHMENT_MIME_TYPE; + + ap_remove_output_filter(f); + + return ap_pass_brigade(f->next, bb_in); + } + + /* Locate the protection token. */ + token = extract_token(msr); + + if (token == NULL) { /* No token. */ + char *new_uri = NULL; + + /* Create a new URI with the protection token inside. */ + new_uri = construct_new_uri(msr); + if (new_uri != NULL) { + /* Redirect user to the new URI. */ + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "PdfProtect: PDF request without a token - " + "redirecting to %s.", log_escape_nq(msr->mp, new_uri)); + } + + apr_table_set(r->headers_out, "Location", new_uri); + + ap_remove_output_filter(f); + + return send_error_bucket(msr, f, REDIRECT_STATUS); + } + } else { /* Token found. */ + char *my_error_msg = NULL; + + /* Verify the token is valid. */ + + if (verify_token(msr, token, &my_error_msg)) { /* Valid. */ + /* Do nothing - serve the PDF file. */ + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "PdfProtect: PDF request with a valid token " + "- serving PDF file normally."); + } + + /* Fall through. */ + } else { /* Not valid. */ + /* The token is not valid. We will tweak the response + * to prevent the PDF file from opening in the browser. + */ + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 9, "PdfProtect: PDF request with an invalid token " + "- serving file as attachment."); + } + + apr_table_set(r->headers_out, "Content-Disposition", DISPOSITION_VALUE); + r->content_type = ATTACHMENT_MIME_TYPE; + + /* Fall through. */ + } + } + } + } + + ap_remove_output_filter(f); + + return ap_pass_brigade(f->next, bb_in); +} + +/** + * + */ +int pdfp_check(modsec_rec *msr) { + const char *token = NULL; + char *uri = NULL; + char *p = NULL; + + if (msr->txcfg->pdfp_enabled != 1) { + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "PdfProtect: Not enabled here."); + } + + return 0; + } + + if (msr->txcfg->pdfp_method != PDF_PROTECT_METHOD_TOKEN_REDIRECTION) { + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "PdfProtect: Configured with ForcedDownload as protection method, " + "skipping detection on the inbound."); + } + + return 0; + } + + /* Then determine whether we need to act at + * all. If the request is not for a PDF file + * return straight away. + */ + + if (msr->r->uri == NULL) { + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "PdfProtect: Unable to inspect URI because it is NULL."); + } + + return -1; /* Error. */ + } + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "PdfProtect: URI=%s, filename=%s, QUERY_STRING=%s.", + log_escape_nq(msr->mp, msr->r->uri), log_escape_nq(msr->mp, msr->r->filename), + log_escape_nq(msr->mp, msr->r->args)); + } + + uri = apr_pstrdup(msr->mp, msr->r->uri); + if (uri == NULL) return -1; /* Error. */ + ap_str_tolower(uri); + + /* Attempt to figure out if this is a request for a PDF file. We are + * going to be liberal and look for the extension anywhere in the URI, + * not just at the end. + */ + p = strstr(uri, ".pdf"); + if (p == NULL) { + /* We do not think this is a PDF file. */ + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "PdfProtect: No indication in the URI this is a " + "request for a PDF file."); + } + + return 0; + } + + /* Ignore request methods other than GET and HEAD if + * configured to do so. + * + * TODO: Code here is only GET, not GET|HEAD as comment states + */ + if ((msr->r->method_number != M_GET)&&(msr->txcfg->pdfp_only_get != 0)) { + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "PdfProtect: Not intercepting request " + "(method=%s/%d).", log_escape_nq(msr->mp, msr->r->method), msr->r->method_number); + } + + return 0; + } + + /* We make a note for ourselves that we've already handled + * the request. + */ + apr_table_set(msr->r->notes, NOTE_DONE, "1"); + + /* Locate the protection token. */ + token = extract_token(msr); + + if (token == NULL) { /* No token. */ + char *new_uri = NULL; + + /* Create a new URI with the protection token inside. */ + new_uri = construct_new_uri(msr); + if (new_uri == NULL) return DECLINED; + + /* Redirect user to the new URI. */ + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "PdfProtect: PDF request without a token - redirecting to %s.", + log_escape_nq(msr->mp, new_uri)); + } + + apr_table_set(msr->r->headers_out, "Location", new_uri); + + return REDIRECT_STATUS; + } else { /* Token found. */ + char *my_error_msg = NULL; + + /* Verify the token is valid. */ + if (verify_token(msr, token, &my_error_msg)) { /* Valid. */ + /* Do nothing - serve the PDF file. */ + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "PdfProtect: PDF request with a valid token - " + "serving PDF file normally."); + } + + return 0; + } else { /* Not valid. */ + /* The token is not valid. We will tweak the response + * to prevent the PDF file from opening in the browser. + */ + + // TODO Log alert + + /* Changing response headers before response generation phase takes + * place is not really reliable. Although we do this we also make + * a note for ourselves (in the output filter) to check the headers + * again just before they are sent back to the end user. + */ + apr_table_set(msr->r->headers_out, "Content-Disposition", DISPOSITION_VALUE); + msr->r->content_type = ATTACHMENT_MIME_TYPE; + apr_table_set(msr->r->notes, NOTE_TWEAK_HEADERS, "1"); + + /* Proceed with response (PDF) generation. */ + return 0; + } + } + + return 0; +} diff --git a/apache2/pdf_protect.h b/apache2/pdf_protect.h new file mode 100644 index 0000000..97d632a --- /dev/null +++ b/apache2/pdf_protect.h @@ -0,0 +1,29 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ +#ifndef _PDF_PROTECT_H_ +#define _PDF_PROTECT_H_ + +#define PDF_PROTECT_METHOD_TOKEN_REDIRECTION 1 +#define PDF_PROTECT_METHOD_FORCED_DOWNLOAD 2 + +apr_status_t DSOLOCAL pdfp_output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in); + +int DSOLOCAL pdfp_check(modsec_rec *msr); + +#endif diff --git a/apache2/persist_dbm.c b/apache2/persist_dbm.c new file mode 100644 index 0000000..f794674 --- /dev/null +++ b/apache2/persist_dbm.c @@ -0,0 +1,671 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ +#include "persist_dbm.h" +#include "apr_sdbm.h" + +/** + * + */ +static apr_table_t *collection_unpack(modsec_rec *msr, const unsigned char *blob, unsigned int blob_size, + int log_vars) +{ + apr_table_t *col = NULL; + unsigned int blob_offset; + + col = apr_table_make(msr->mp, 32); + if (col == NULL) return NULL; + + /* ENH verify the first 3 bytes (header) */ + + blob_offset = 3; + while (blob_offset + 1 < blob_size) { + msc_string *var = apr_pcalloc(msr->mp, sizeof(msc_string)); + + var->name_len = (blob[blob_offset] << 8) + blob[blob_offset + 1]; + if (var->name_len == 0) { + /* Is the length a name length, or just the end of the blob? */ + if (blob_offset < blob_size - 2) { + /* This should never happen as the name length + * includes the terminating NUL and should be 1 for "" + */ + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "BLOB[%d]: %s", blob_offset, log_escape_hex(msr->mp, blob + blob_offset, blob_size - blob_offset)); + } + msr_log(msr, 4, "Possibly corrupted database: var name length = 0 at blob offset %u-%u.", blob_offset, blob_offset + 1); + } + break; + } + else if (var->name_len > 65536) { + /* This should never happen as the length is restricted on store + * to 65536. + */ + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "BLOB[%d]: %s", blob_offset, log_escape_hex(msr->mp, blob + blob_offset, blob_size - blob_offset)); + } + msr_log(msr, 4, "Possibly corrupted database: var name length > 65536 (0x%04x) at blob offset %u-%u.", var->name_len, blob_offset, blob_offset + 1); + break; + } + + blob_offset += 2; + if (blob_offset + var->name_len > blob_size) return NULL; + var->name = apr_pstrmemdup(msr->mp, (const char *)blob + blob_offset, var->name_len - 1); + blob_offset += var->name_len; + var->name_len--; + + var->value_len = (blob[blob_offset] << 8) + blob[blob_offset + 1]; + blob_offset += 2; + + if (blob_offset + var->value_len > blob_size) return NULL; + var->value = apr_pstrmemdup(msr->mp, (const char *)blob + blob_offset, var->value_len - 1); + blob_offset += var->value_len; + var->value_len--; + + if (log_vars && (msr->txcfg->debuglog_level >= 9)) { + msr_log(msr, 9, "Read variable: name \"%s\", value \"%s\".", + log_escape_ex(msr->mp, var->name, var->name_len), + log_escape_ex(msr->mp, var->value, var->value_len)); + } + + apr_table_addn(col, var->name, (void *)var); + } + + return col; +} + +/** + * + */ +static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec *msr, const char *col_name, + const char *col_key, int col_key_len) +{ + char *dbm_filename = NULL; + apr_status_t rc; + apr_sdbm_datum_t key; + apr_sdbm_datum_t *value = NULL; + apr_sdbm_t *dbm = NULL; + apr_table_t *col = NULL; + const apr_array_header_t *arr; + apr_table_entry_t *te; + int expired = 0; + int i; + + if (msr->txcfg->data_dir == NULL) { + msr_log(msr, 1, "Unable to retrieve collection (name \"%s\", key \"%s\"). Use " + "SecDataDir to define data directory first.", log_escape(msr->mp, col_name), + log_escape_ex(msr->mp, col_key, col_key_len)); + goto cleanup; + } + + dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", col_name, NULL); + + key.dptr = (char *)col_key; + key.dsize = col_key_len + 1; + + if (existing_dbm == NULL) { + rc = apr_sdbm_open(&dbm, dbm_filename, APR_READ | APR_SHARELOCK, + CREATEMODE, msr->mp); + if (rc != APR_SUCCESS) { + dbm = NULL; + goto cleanup; + } + } + else { + dbm = existing_dbm; + } + + value = (apr_sdbm_datum_t *)apr_pcalloc(msr->mp, sizeof(apr_sdbm_datum_t)); + rc = apr_sdbm_fetch(dbm, value, key); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "Failed to read from DBM file \"%s\": %s", log_escape(msr->mp, + dbm_filename), get_apr_error(msr->mp, rc)); + goto cleanup; + } + + if (value->dptr == NULL) { /* Key not found in DBM file. */ + goto cleanup; + } + + /* ENH Need expiration (and perhaps other metadata) accessible in blob + * form to determine if converting to a table is needed. This will + * save some cycles. + */ + + /* Transform raw data into a table. */ + col = collection_unpack(msr, (const unsigned char *)value->dptr, value->dsize, 1); + if (col == NULL) { + goto cleanup; + } + + /* Close after "value" used from fetch or memory may be overwritten. */ + if (existing_dbm == NULL) { + apr_sdbm_close(dbm); + dbm = NULL; + } + + /* Remove expired variables. */ + do { + arr = apr_table_elts(col); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + if (strncmp(te[i].key, "__expire_", 9) == 0) { + msc_string *var = (msc_string *)te[i].val; + int expiry_time = atoi(var->value); + + if (expiry_time <= apr_time_sec(msr->request_time)) { + char *key_to_expire = te[i].key; + + /* Done early if the col expired */ + if (strcmp(key_to_expire, "__expire_KEY") == 0) { + expired = 1; + } + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Removing key \"%s\" from collection.", key_to_expire + 9); + msr_log(msr, 9, "Removing key \"%s\" from collection.", key_to_expire); + } + apr_table_unset(col, key_to_expire + 9); + apr_table_unset(col, key_to_expire); + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Removed expired variable \"%s\".", key_to_expire + 9); + } + break; + } + } + } + } while(!expired && (i != arr->nelts)); + + /* Delete the collection if the variable "KEY" does not exist. + * + * ENH It would probably be more efficient to hold the DBM + * open until determined if it needs deleted than to open a second + * time. + */ + if (apr_table_get(col, "KEY") == NULL) { + if (existing_dbm == NULL) { + rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, + CREATEMODE, msr->mp); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "Failed to access DBM file \"%s\": %s", + log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc)); + dbm = NULL; + goto cleanup; + } + } + else { + dbm = existing_dbm; + } + + rc = apr_sdbm_delete(dbm, key); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "Failed deleting collection (name \"%s\", " + "key \"%s\"): %s", log_escape(msr->mp, col_name), + log_escape_ex(msr->mp, col_key, col_key_len), get_apr_error(msr->mp, rc)); + goto cleanup; + } + + + if (existing_dbm == NULL) { + apr_sdbm_close(dbm); + dbm = NULL; + } + + if (expired && (msr->txcfg->debuglog_level >= 9)) { + msr_log(msr, 9, "Collection expired (name \"%s\", key \"%s\").", col_name, log_escape_ex(msr->mp, col_key, col_key_len)); + } + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Deleted collection (name \"%s\", key \"%s\").", + log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len)); + } + goto cleanup; + } + + /* Update UPDATE_RATE */ + { + msc_string *var; + int create_time, counter; + + var = (msc_string *)apr_table_get(col, "CREATE_TIME"); + if (var == NULL) { + /* Error. */ + } else { + create_time = atoi(var->value); + var = (msc_string *)apr_table_get(col, "UPDATE_COUNTER"); + if (var == NULL) { + /* Error. */ + } else { + apr_time_t td; + counter = atoi(var->value); + + /* UPDATE_RATE is removed on store, so add it back here */ + var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + var->name = "UPDATE_RATE"; + var->name_len = strlen(var->name); + apr_table_setn(col, var->name, (void *)var); + + /* NOTE: No rate if there has been no time elapsed */ + td = (apr_time_sec(apr_time_now()) - create_time); + if (td == 0) { + var->value = apr_psprintf(msr->mp, "%d", 0); + } + else { + var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, + (apr_time_t)((60 * counter)/td)); + } + var->value_len = strlen(var->value); + } + } + } + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Retrieved collection (name \"%s\", key \"%s\").", + log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len)); + } + + if ((existing_dbm == NULL) && dbm) { + /* Should not ever get here */ + msr_log(msr, 1, "Internal Error: Collection remained open (name \"%s\", key \"%s\").", + log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len)); + + apr_sdbm_close(dbm); + } + + return col; + +cleanup: + + if ((existing_dbm == NULL) && dbm) { + apr_sdbm_close(dbm); + } + + return NULL; +} + +/** + * + */ +apr_table_t *collection_retrieve(modsec_rec *msr, const char *col_name, + const char *col_key, int col_key_len) { + return collection_retrieve_ex(NULL, msr, col_name, col_key, col_key_len); +} + + +/** + * + */ +int collection_store(modsec_rec *msr, apr_table_t *col) { + char *dbm_filename = NULL; + msc_string *var_name = NULL, *var_key = NULL; + unsigned char *blob = NULL; + unsigned int blob_size, blob_offset; + apr_status_t rc; + apr_sdbm_datum_t key; + apr_sdbm_datum_t value; + apr_sdbm_t *dbm = NULL; + const apr_array_header_t *arr; + apr_table_entry_t *te; + int i; + const apr_table_t *stored_col = NULL; + const apr_table_t *orig_col = NULL; + + var_name = (msc_string *)apr_table_get(col, "__name"); + if (var_name == NULL) { + goto error; + } + + var_key = (msc_string *)apr_table_get(col, "__key"); + if (var_key == NULL) { + goto error; + } + + if (msr->txcfg->data_dir == NULL) { + msr_log(msr, 1, "Unable to store collection (name \"%s\", key \"%s\"). Use " + "SecDataDir to define data directory first.", + log_escape_ex(msr->mp, var_name->value, var_name->value_len), log_escape_ex(msr->mp, var_key->value, var_key->value_len)); + goto error; + } + + // ENH: lowercase the var name in the filename + dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", var_name->value, NULL); + + /* Delete IS_NEW on store. */ + apr_table_unset(col, "IS_NEW"); + + /* Delete UPDATE_RATE on store to save space as it is calculated */ + apr_table_unset(col, "UPDATE_RATE"); + + /* Update the timeout value. */ + { + msc_string *var = (msc_string *)apr_table_get(col, "TIMEOUT"); + if (var != NULL) { + int timeout = atoi(var->value); + var = (msc_string *)apr_table_get(col, "__expire_KEY"); + if (var != NULL) { + var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, (apr_time_t)(apr_time_sec(apr_time_now()) + timeout)); + var->value_len = strlen(var->value); + } + } + } + + /* LAST_UPDATE_TIME */ + { + msc_string *var = (msc_string *)apr_table_get(col, "LAST_UPDATE_TIME"); + if (var == NULL) { + var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + var->name = "LAST_UPDATE_TIME"; + var->name_len = strlen(var->name); + apr_table_setn(col, var->name, (void *)var); + } + var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, (apr_time_t)(apr_time_sec(apr_time_now()))); + var->value_len = strlen(var->value); + } + + /* UPDATE_COUNTER */ + { + msc_string *var = (msc_string *)apr_table_get(col, "UPDATE_COUNTER"); + int counter = 0; + if (var == NULL) { + var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + var->name = "UPDATE_COUNTER"; + var->name_len = strlen(var->name); + apr_table_setn(col, var->name, (void *)var); + } else { + counter = atoi(var->value); + } + var->value = apr_psprintf(msr->mp, "%d", counter + 1); + var->value_len = strlen(var->value); + } + + /* ENH Make the expiration timestamp accessible in blob form so that + * it is easier/faster to determine expiration without having to + * convert back to table form + */ + + rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, + CREATEMODE, msr->mp); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "Failed to access DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), + get_apr_error(msr->mp, rc)); + dbm = NULL; + goto error; + } + + /* Need to lock to pull in the stored data again and apply deltas. */ + rc = apr_sdbm_lock(dbm, APR_FLOCK_EXCLUSIVE); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "Failed to exclusivly lock DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), + get_apr_error(msr->mp, rc)); + goto error; + } + + /* If there is an original value, then create a delta and + * apply the delta to the current value */ + orig_col = (const apr_table_t *)apr_table_get(msr->collections_original, var_name->value); + if (orig_col != NULL) { + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Re-retrieving collection prior to store: %s", apr_psprintf(msr->mp, "%.*s", var_name->value_len, var_name->value)); + } + + stored_col = (const apr_table_t *)collection_retrieve_ex(dbm, msr, var_name->value, var_key->value, var_key->value_len); + } + + /* Merge deltas and calculate the size first. */ + blob_size = 3 + 2; + arr = apr_table_elts(col); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + msc_string *var = (msc_string *)te[i].val; + int len; + + /* If there is an original value, then apply the delta + * to the latest stored value */ + if (stored_col != NULL) { + const msc_string *orig_var = (const msc_string *)apr_table_get(orig_col, var->name); + if (orig_var != NULL) { + const msc_string *stored_var = (const msc_string *)apr_table_get(stored_col, var->name); + if (stored_var != NULL) { + int origval = atoi(orig_var->value); + int ourval = atoi(var->value); + int storedval = atoi(stored_var->value); + int delta = ourval - origval; + int newval = storedval + delta; + + if (newval < 0) newval = 0; /* Counters never go below zero. */ + + var->value = apr_psprintf(msr->mp, "%d", newval); + var->value_len = strlen(var->value); + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Delta applied for %s.%s %d->%d (%d): %d + (%d) = %d [%s,%d]", + log_escape_ex(msr->mp, var_name->value, var_name->value_len), + log_escape_ex(msr->mp, var->name, var->name_len), + origval, ourval, delta, storedval, delta, newval, var->value, var->value_len); + } + } + } + } + + len = var->name_len + 1; + if (len >= 65536) len = 65536; + blob_size += len + 2; + + len = var->value_len + 1; + if (len >= 65536) len = 65536; + blob_size += len + 2; + } + + /* Now generate the binary object. */ + blob = apr_pcalloc(msr->mp, blob_size); + if (blob == NULL) { + goto error; + } + + blob[0] = 0x49; + blob[1] = 0x52; + blob[2] = 0x01; + + blob_offset = 3; + arr = apr_table_elts(col); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + msc_string *var = (msc_string *)te[i].val; + int len; + + len = var->name_len + 1; + if (len >= 65536) len = 65536; + + blob[blob_offset + 0] = (len & 0xff00) >> 8; + blob[blob_offset + 1] = len & 0x00ff; + memcpy(blob + blob_offset + 2, var->name, len - 1); + blob[blob_offset + 2 + len - 1] = '\0'; + blob_offset += 2 + len; + + len = var->value_len + 1; + if (len >= 65536) len = 65536; + + blob[blob_offset + 0] = (len & 0xff00) >> 8; + blob[blob_offset + 1] = len & 0x00ff; + memcpy(blob + blob_offset + 2, var->value, len - 1); + blob[blob_offset + 2 + len - 1] = '\0'; + blob_offset += 2 + len; + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Wrote variable: name \"%s\", value \"%s\".", + log_escape_ex(msr->mp, var->name, var->name_len), + log_escape_ex(msr->mp, var->value, var->value_len)); + } + } + + blob[blob_offset] = 0; + blob[blob_offset + 1] = 0; + + /* And, finally, store it. */ + key.dptr = var_key->value; + key.dsize = var_key->value_len + 1; + + value.dptr = (char *)blob; + value.dsize = blob_size; + + rc = apr_sdbm_store(dbm, key, value, APR_SDBM_REPLACE); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "Failed to write to DBM file \"%s\": %s", dbm_filename, + get_apr_error(msr->mp, rc)); + goto error; + } + + apr_sdbm_close(dbm); + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Persisted collection (name \"%s\", key \"%s\").", + log_escape_ex(msr->mp, var_name->value, var_name->value_len), log_escape_ex(msr->mp, var_key->value, var_key->value_len)); + } + + return 0; + +error: + + if (dbm) { + apr_sdbm_close(dbm); + } + + return -1; +} + +/** + * + */ +int collections_remove_stale(modsec_rec *msr, const char *col_name) { + char *dbm_filename = NULL; + apr_sdbm_datum_t key, value; + apr_sdbm_t *dbm = NULL; + apr_status_t rc; + apr_array_header_t *keys_arr; + char **keys; + apr_time_t now = apr_time_sec(msr->request_time); + int i; + + if (msr->txcfg->data_dir == NULL) { + /* The user has been warned about this problem enough times already by now. + * msr_log(msr, 1, "Unable to access collection file (name \"%s\"). Use SecDataDir to " + * "define data directory first.", log_escape(msr->mp, col_name)); + */ + goto error; + } + + dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", col_name, NULL); + + rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, + CREATEMODE, msr->mp); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "Failed to access DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), + get_apr_error(msr->mp, rc)); + dbm = NULL; + goto error; + } + + /* First get a list of all keys. */ + keys_arr = apr_array_make(msr->mp, 256, sizeof(char *)); + rc = apr_sdbm_lock(dbm, APR_FLOCK_SHARED); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "Failed to lock DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), + get_apr_error(msr->mp, rc)); + goto error; + } + + /* No one can write to the file while doing this so + * do it as fast as possible. + */ + rc = apr_sdbm_firstkey(dbm, &key); + while(rc == APR_SUCCESS) { + char *s = apr_pstrmemdup(msr->mp, key.dptr, key.dsize - 1); + *(char **)apr_array_push(keys_arr) = s; + rc = apr_sdbm_nextkey(dbm, &key); + } + apr_sdbm_unlock(dbm); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Found %d record(s) in file \"%s\".", keys_arr->nelts, + log_escape(msr->mp, dbm_filename)); + } + + /* Now retrieve the entires one by one. */ + keys = (char **)keys_arr->elts; + for (i = 0; i < keys_arr->nelts; i++) { + key.dptr = keys[i]; + key.dsize = strlen(key.dptr) + 1; + + rc = apr_sdbm_fetch(dbm, &value, key); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "Failed reading DBM file \"%s\": %s", + log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc)); + goto error; + } + + if (value.dptr != NULL) { + apr_table_t *col = NULL; + msc_string *var = NULL; + + col = collection_unpack(msr, (const unsigned char *)value.dptr, value.dsize, 0); + if (col == NULL) { + goto error; + } + + var = (msc_string *)apr_table_get(col, "__expire_KEY"); + if (var == NULL) { + msr_log(msr, 1, "Collection cleanup discovered entry with no " + "__expire_KEY (name \"%s\", key \"%s\").", + log_escape(msr->mp, col_name), log_escape_ex(msr->mp, key.dptr, key.dsize - 1)); + } else { + unsigned int expiry_time = atoi(var->value); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Record (name \"%s\", key \"%s\") set to expire in %" APR_TIME_T_FMT " seconds.", + log_escape(msr->mp, col_name), log_escape_ex(msr->mp, key.dptr, key.dsize - 1), + expiry_time - now); + } + + if (expiry_time <= now) { + rc = apr_sdbm_delete(dbm, key); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "Failed deleting collection (name \"%s\", " + "key \"%s\"): %s", log_escape(msr->mp, col_name), + log_escape_ex(msr->mp, key.dptr, key.dsize - 1), get_apr_error(msr->mp, rc)); + goto error; + } + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Removed stale collection (name \"%s\", " + "key \"%s\").", log_escape(msr->mp, col_name), + log_escape_ex(msr->mp, key.dptr, key.dsize - 1)); + } + } + } + } else { + /* Ignore entry not found - it may have been removed in the meantime. */ + } + } + + apr_sdbm_close(dbm); + + return 1; + +error: + + if (dbm) { + apr_sdbm_close(dbm); + } + + return -1; +} diff --git a/apache2/persist_dbm.h b/apache2/persist_dbm.h new file mode 100644 index 0000000..94ab1ba --- /dev/null +++ b/apache2/persist_dbm.h @@ -0,0 +1,32 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ +#ifndef _PERSIST_DBM_H_ +#define _PERSIST_DBM_H_ + +#include "apr_general.h" +#include "modsecurity.h" + +apr_table_t DSOLOCAL *collection_retrieve(modsec_rec *msr, const char *col_name, + const char *col_value, int col_value_length); + +int DSOLOCAL collection_store(modsec_rec *msr, apr_table_t *collection); + +int DSOLOCAL collections_remove_stale(modsec_rec *msr, const char *col_name); + +#endif diff --git a/apache2/re.c b/apache2/re.c new file mode 100644 index 0000000..4b5e2ae --- /dev/null +++ b/apache2/re.c @@ -0,0 +1,2456 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ +#include + +#include "re.h" + +#if defined(WITH_LUA) +#include "msc_lua.h" +#endif + +static const char *const severities[] = { + "EMERGENCY", + "ALERT", + "CRITICAL", + "ERROR", + "WARNING", + "NOTICE", + "INFO", + "DEBUG", + NULL, +}; + +/* -- Actions, variables, functions and operator functions ----------------- */ + +/** + * Remove actions with the same cardinality group from the actionset. + */ +static void msre_actionset_cardinality_fixup(msre_actionset *actionset, msre_action *action) { + const apr_array_header_t *tarr = NULL; + const apr_table_entry_t *telts = NULL; + int i; + + if ((actionset == NULL) || (action == NULL)) return; + + tarr = apr_table_elts(actionset->actions); + telts = (const apr_table_entry_t*)tarr->elts; + + for (i = 0; i < tarr->nelts; i++) { + msre_action *target = (msre_action *)telts[i].val; + if (target->metadata->cardinality_group == action->metadata->cardinality_group) { + + apr_table_unset(actionset->actions, target->metadata->name); + } + } +} + +/** + * Generate an action string from an actionset. + */ +char *msre_actionset_generate_action_string(apr_pool_t *pool, const msre_actionset *actionset) +{ + const apr_array_header_t *tarr = NULL; + const apr_table_entry_t *telts = NULL; + char *actions = NULL; + int chain; + int i; + + if (actionset == NULL) return NULL; + + chain = ((actionset->rule != NOT_SET_P) && actionset->rule->chain_starter) ? 1 : 0; + + tarr = apr_table_elts(actionset->actions); + telts = (const apr_table_entry_t*)tarr->elts; + + for (i = 0; i < tarr->nelts; i++) { + msre_action *action = (msre_action *)telts[i].val; + int use_quotes = 0; + + if (chain) { + /* Skip some actions that are not used in a chain. */ + if ( (action->metadata->type == ACTION_DISRUPTIVE) + || (action->metadata->type == ACTION_METADATA) + || (strcmp("log", action->metadata->name) == 0) + || (strcmp("auditlog", action->metadata->name) == 0) + || (strcmp("nolog", action->metadata->name) == 0) + || (strcmp("noauditlog", action->metadata->name) == 0) + || (strcmp("severity", action->metadata->name) == 0) + || (strcmp("tag", action->metadata->name) == 0) + || (strcmp("phase", action->metadata->name) == 0)) + { + continue; + } + } + + /* Check if we need any quotes */ + if (action->param != NULL) { + int j; + for(j = 0; action->param[j] != '\0'; j++) { + if (isspace(action->param[j])) { + use_quotes = 1; + break; + } + } + if (j == 0) use_quotes = 1; + } + + actions = apr_pstrcat(pool, + (actions == NULL) ? "" : actions, + (actions == NULL) ? "" : ",", + action->metadata->name, + (action->param == NULL) ? "" : ":", + (use_quotes) ? "'" : "", + (action->param == NULL) ? "" : action->param, + (use_quotes) ? "'" : "", + NULL); + } + + return actions; +} + +/** + * Add an action to an actionset. + */ +static void msre_actionset_action_add(msre_actionset *actionset, msre_action *action) +{ + msre_action *add_action = action; + + if ((actionset == NULL)) return; + + /** + * The "block" action is just a placeholder for the parent action. + */ + if ((actionset->parent_intercept_action_rec != NULL) && (actionset->parent_intercept_action_rec != NOT_SET_P) && (strcmp("block", action->metadata->name) == 0) && (strcmp("block", action->metadata->name) == 0)) { + /* revert back to parent */ + actionset->intercept_action = actionset->parent_intercept_action; + add_action = actionset->parent_intercept_action_rec; + } + + if ((add_action == NULL)) return; + + if (add_action->metadata->cardinality_group != ACTION_CGROUP_NONE) { + msre_actionset_cardinality_fixup(actionset, add_action); + } + + if (add_action->metadata->cardinality == ACTION_CARDINALITY_ONE) { + /* One action per actionlist. */ + apr_table_setn(actionset->actions, add_action->metadata->name, (void *)add_action); + } else { + /* Multiple actions per actionlist. */ + apr_table_addn(actionset->actions, add_action->metadata->name, (void *)add_action); + } +} + +/** + * Creates msre_var instances (rule variables) out of the + * given text string and places them into the supplied table. + */ +apr_status_t msre_parse_targets(msre_ruleset *ruleset, const char *text, + apr_array_header_t *arr, char **error_msg) +{ + const apr_array_header_t *tarr; + const apr_table_entry_t *telts; + apr_table_t *vartable; + unsigned int count = 0; + apr_status_t rc; + msre_var *var; + int i; + + if (text == NULL) return -1; + + /* Extract name & value pairs first */ + vartable = apr_table_make(ruleset->mp, 10); + if (vartable == NULL) return -1; + rc = msre_parse_generic(ruleset->mp, text, vartable, error_msg); + if (rc < 0) return rc; + + /* Loop through the table and create variables */ + tarr = apr_table_elts(vartable); + telts = (const apr_table_entry_t*)tarr->elts; + for (i = 0; i < tarr->nelts; i++) { + var = msre_create_var(ruleset, telts[i].key, telts[i].val, NULL, error_msg); + if (var == NULL) return -1; + *(msre_var **)apr_array_push(arr) = var; + count++; + } + + return count; +} + +/** + * Creates msre_action instances by parsing the given string, placing + * them into the supplied array. + */ +apr_status_t msre_parse_actions(msre_engine *engine, msre_actionset *actionset, + const char *text, char **error_msg) +{ + const apr_array_header_t *tarr; + const apr_table_entry_t *telts; + apr_table_t *vartable; + unsigned int count = 0; + apr_status_t rc; + msre_action *action; + int i; + + if (text == NULL) return -1; + + /* Extract name & value pairs first */ + vartable = apr_table_make(engine->mp, 10); + if (vartable == NULL) return -1; + rc = msre_parse_generic(engine->mp, text, vartable, error_msg); + if (rc < 0) return rc; + + /* Loop through the table and create actions */ + tarr = apr_table_elts(vartable); + telts = (const apr_table_entry_t*)tarr->elts; + for (i = 0; i < tarr->nelts; i++) { + /* Create action. */ + action = msre_create_action(engine, telts[i].key, telts[i].val, error_msg); + if (action == NULL) return -1; + + /* Initialise action (option). */ + if (action->metadata->init != NULL) { + action->metadata->init(engine, actionset, action); + } + + msre_actionset_action_add(actionset, action); + + count++; + } + + return count; +} + +/** + * Locates variable metadata given the variable name. + */ +msre_var_metadata *msre_resolve_var(msre_engine *engine, const char *name) { + return (msre_var_metadata *)apr_table_get(engine->variables, name); +} + +/** + * Locates action metadata given the action name. + */ +msre_action_metadata *msre_resolve_action(msre_engine *engine, const char *name) { + return (msre_action_metadata *)apr_table_get(engine->actions, name); +} + +/** + * Creates a new variable instance given the variable name + * and an (optional) parameter. + */ +msre_var *msre_create_var_ex(apr_pool_t *pool, msre_engine *engine, const char *name, const char *param, + modsec_rec *msr, char **error_msg) +{ + const char *varparam = param; + msre_var *var = apr_pcalloc(pool, sizeof(msre_var)); + if (var == NULL) return NULL; + + if (error_msg == NULL) return NULL; + *error_msg = NULL; + + /* Handle negation and member counting */ + if (name[0] == '!') { + var->is_negated = 1; + var->name = name + 1; + } + else + if (name[0] == '&') { + var->is_counting = 1; + var->name = name + 1; + } + else { + var->name = name; + } + + /* Treat HTTP_* targets as an alias for REQUEST_HEADERS:* */ + if ( (var->name != NULL) + && (strlen(var->name) > 5) + && (strncmp("HTTP_", var->name, 5) == 0)) + { + const char *oldname = var->name; + var->name = apr_pstrdup(pool, "REQUEST_HEADERS"); + varparam = apr_pstrdup(pool, oldname + 5); + } + + + /* Resolve variable */ + var->metadata = msre_resolve_var(engine, var->name); + if (var->metadata == NULL) { + *error_msg = apr_psprintf(engine->mp, "Unknown variable: %s", name); + return NULL; + } + + /* The counting operator "&" can only be used against collections. */ + if (var->is_counting) { + if (var->metadata->type == VAR_SIMPLE) { + *error_msg = apr_psprintf(engine->mp, "The & modificator does not apply to " + "non-collection variables."); + return NULL; + } + } + + /* Check the parameter. */ + if (varparam == NULL) { + if (var->metadata->argc_min > 0) { + *error_msg = apr_psprintf(engine->mp, "Missing mandatory parameter for variable %s.", + name); + return NULL; + } + } else { /* Parameter present */ + + /* Do we allow a parameter? */ + if (var->metadata->argc_max == 0) { + *error_msg = apr_psprintf(engine->mp, "Variable %s does not support parameters.", + name); + return NULL; + } + + var->param = varparam; + } + + return var; +} + +/** + * Create a new variable object from the provided name and value. + * + * NOTE: this allocates out of the global pool and should not be used + * per-request + */ +msre_var *msre_create_var(msre_ruleset *ruleset, const char *name, const char *param, + modsec_rec *msr, char **error_msg) +{ + msre_var *var = msre_create_var_ex(ruleset->engine->mp, ruleset->engine, name, param, msr, error_msg); + if (var == NULL) return NULL; + + /* Validate & initialise variable */ + if (var->metadata->validate != NULL) { + *error_msg = var->metadata->validate(ruleset, var); + if (*error_msg != NULL) { + return NULL; + } + } + + return var; +} + +/** + * Creates a new action instance given its name and an (optional) parameter. + */ +msre_action *msre_create_action(msre_engine *engine, const char *name, const char *param, + char **error_msg) +{ + msre_action *action = apr_pcalloc(engine->mp, sizeof(msre_action)); + if (action == NULL) return NULL; + + if (error_msg == NULL) return NULL; + *error_msg = NULL; + + /* Resolve action */ + action->metadata = msre_resolve_action(engine, name); + if (action->metadata == NULL) { + *error_msg = apr_psprintf(engine->mp, "Unknown action: %s", name); + return NULL; + } + + if (param == NULL) { /* Parameter not present */ + if (action->metadata->argc_min > 0) { + *error_msg = apr_psprintf(engine->mp, "Missing mandatory parameter for action %s", + name); + return NULL; + } + } else { /* Parameter present */ + + /* Should we allow the parameter? */ + if (action->metadata->argc_max == 0) { + *error_msg = apr_psprintf(engine->mp, "Extra parameter provided to action %s", name); + return NULL; + } + + /* Handle +/- modificators */ + if ((param[0] == '+')||(param[0] == '-')) { + if (action->metadata->allow_param_plusminus == 0) { + *error_msg = apr_psprintf(engine->mp, + "Action %s does not allow +/- modificators.", name); + return NULL; + } + else { /* Modificators allowed. */ + if (param[0] == '+') { + action->param = param + 1; + action->param_plusminus = POSITIVE_VALUE; + } else + if (param[0] == '-') { + action->param = param + 1; + action->param_plusminus = NEGATIVE_VALUE; + } + } + } else { + action->param = param; + } + + /* Validate parameter */ + if (action->metadata->validate != NULL) { + *error_msg = action->metadata->validate(engine, action); + if (*error_msg != NULL) return NULL; + } + } + + return action; +} + +/** + * Generic parser that is used as basis for target and action parsing. + * It breaks up the input string into name-parameter pairs and places + * them into the given table. + */ +int msre_parse_generic(apr_pool_t *mp, const char *text, apr_table_t *vartable, + char **error_msg) +{ + char *p = (char *)text; + int count = 0; + + if (error_msg == NULL) return -1; + *error_msg = NULL; + + count = 0; + while(*p != '\0') { + char *name = NULL, *value = NULL; + + /* ignore whitespace */ + while(isspace(*p)) p++; + if (*p == '\0') return count; + + /* we are at the beginning of the name */ + name = p; + while((*p != '\0')&&(*p != '|')&&(*p != ':')&&(*p != ',')&&(!isspace(*p))) p++; /* ENH replace with isvarnamechar() */ + + /* get the name */ + name = apr_pstrmemdup(mp, name, p - name); + + if (*p != ':') { /* we don't have a parameter */ + /* add to the table with no value */ + apr_table_addn(vartable, name, NULL); + count++; + + /* go over any whitespace present */ + while(isspace(*p)) p++; + + /* we're done */ + if (*p == '\0') { + return count; + } + + /* skip over the separator character and continue */ + if ((*p == ',')||(*p == '|')) { + p++; + continue; + } + + *error_msg = apr_psprintf(mp, "Unexpected character at position %d: %s", + (int)(p - text), text); + return -1; + } + + /* we have a parameter */ + + p++; /* move over the colon */ + + /* we'll allow empty values */ + if (*p == '\0') { + apr_table_addn(vartable, name, NULL); + count++; + return count; + } + + if ((*p == ',')||(*p == '|')) { + apr_table_addn(vartable, name, NULL); + count++; + /* move over the separator char and continue */ + p++; + continue; + } + + /* we really have a parameter */ + + if (*p == '\'') { /* quoted value */ + char *d = NULL; + + p++; /* go over the openning quote */ + value = d = strdup(p); + if (d == NULL) return -1; + + for(;;) { + if (*p == '\0') { + *error_msg = apr_psprintf(mp, "Missing closing quote at position %d: %s", + (int)(p - text), text); + free(value); + return -1; + } else + if (*p == '\\') { + if ( (*(p + 1) == '\0') || ((*(p + 1) != '\'')&&(*(p + 1) != '\\')) ) { + *error_msg = apr_psprintf(mp, "Invalid quoted pair at position %d: %s", + (int)(p - text), text); + free(value); + return -1; + } + p++; + *(d++) = *(p++); + } else + if (*p == '\'') { + *d = '\0'; + p++; + break; + } + else { + *(d++) = *(p++); + } + } + + d = value; + value = apr_pstrdup(mp, d); + free(d); + } else { /* non-quoted value */ + value = p; + while((*p != '\0')&&(*p != ',')&&(*p != '|')&&(!isspace(*p))) p++; + value = apr_pstrmemdup(mp, value, p - value); + } + + /* add to table */ + apr_table_addn(vartable, name, value); + count++; + + /* move to the first character of the next name-value pair */ + while(isspace(*p)||(*p == ',')||(*p == '|')) p++; + } + + return count; +} + + +/* -- Actionset functions -------------------------------------------------- */ + +/** + * Creates an actionset instance and (as an option) populates it by + * parsing the given string which contains a list of actions. + */ +msre_actionset *msre_actionset_create(msre_engine *engine, const char *text, + char **error_msg) +{ + msre_actionset *actionset = (msre_actionset *)apr_pcalloc(engine->mp, + sizeof(msre_actionset)); + if (actionset == NULL) return NULL; + + actionset->actions = apr_table_make(engine->mp, 25); + if (actionset->actions == NULL) return NULL; + + /* Metadata */ + actionset->id = NOT_SET_P; + actionset->rev = NOT_SET_P; + actionset->msg = NOT_SET_P; + actionset->logdata = NOT_SET_P; + actionset->phase = NOT_SET; + actionset->severity = -1; + actionset->rule = NOT_SET_P; + + /* Flow */ + actionset->is_chained = NOT_SET; + actionset->skip_count = NOT_SET; + actionset->skip_after = NOT_SET_P; + + /* Disruptive */ + actionset->parent_intercept_action_rec = NOT_SET_P; + actionset->intercept_action_rec = NOT_SET_P; + actionset->parent_intercept_action = NOT_SET; + actionset->intercept_action = NOT_SET; + actionset->intercept_uri = NOT_SET_P; + actionset->intercept_status = NOT_SET; + actionset->intercept_pause = NOT_SET; + + /* Other */ + actionset->auditlog = NOT_SET; + actionset->log = NOT_SET; + + /* Parse the list of actions, if it's present */ + if (text != NULL) { + if (msre_parse_actions(engine, actionset, text, error_msg) < 0) { + return NULL; + } + } + + return actionset; +} + +/** + * Create a (shallow) copy of the supplied actionset. + */ +static msre_actionset *msre_actionset_copy(apr_pool_t *mp, msre_actionset *orig) { + msre_actionset *copy = NULL; + + if (orig == NULL) return NULL; + copy = (msre_actionset *)apr_pmemdup(mp, orig, sizeof(msre_actionset)); + if (copy == NULL) return NULL; + copy->actions = apr_table_copy(mp, orig->actions); + + return copy; +} + +/** + * Merges two actionsets into one. + */ +msre_actionset *msre_actionset_merge(msre_engine *engine, msre_actionset *parent, + msre_actionset *child, int inherit_by_default) +{ + msre_actionset *merged = NULL; + const apr_array_header_t *tarr; + const apr_table_entry_t *telts; + int i; + + if (inherit_by_default == 0) { + /* There is nothing to merge in this case. */ + return msre_actionset_copy(engine->mp, child); + } + + /* Start with a copy of the parent configuration. */ + merged = msre_actionset_copy(engine->mp, parent); + if (merged == NULL) return NULL; + + if (child == NULL) { + /* The child actionset does not exist, hence + * go with the parent one. + */ + return merged; + } + + /* First merge the hard-coded stuff. */ + + /* Metadata */ + if (child->id != NOT_SET_P) merged->id = child->id; + if (child->rev != NOT_SET_P) merged->rev = child->rev; + if (child->msg != NOT_SET_P) merged->msg = child->msg; + if (child->logdata != NOT_SET_P) merged->logdata = child->logdata; + if (child->severity != NOT_SET) merged->severity = child->severity; + if (child->phase != NOT_SET) merged->phase = child->phase; + if (child->rule != NOT_SET_P) merged->rule = child->rule; + + /* Flow */ + merged->is_chained = child->is_chained; + if (child->skip_count != NOT_SET) merged->skip_count = child->skip_count; + if (child->skip_after != NOT_SET_P) merged->skip_after = child->skip_after; + + /* Disruptive */ + if (child->intercept_action != NOT_SET) { + merged->intercept_action_rec = child->intercept_action_rec; + merged->intercept_action = child->intercept_action; + merged->intercept_uri = child->intercept_uri; + } + + if (child->intercept_status != NOT_SET) merged->intercept_status = child->intercept_status; + if (child->intercept_pause != NOT_SET) merged->intercept_pause = child->intercept_pause; + + /* Other */ + if (child->auditlog != NOT_SET) merged->auditlog = child->auditlog; + if (child->log != NOT_SET) merged->log = child->log; + + + /* Now merge the actions. */ + + tarr = apr_table_elts(child->actions); + telts = (const apr_table_entry_t*)tarr->elts; + for (i = 0; i < tarr->nelts; i++) { + msre_actionset_action_add(merged, (msre_action *)telts[i].val); + } + + return merged; +} + +/** + * Creates an actionset that contains a default list of actions. + */ +msre_actionset *msre_actionset_create_default(msre_engine *engine) { + char *my_error_msg = NULL; + return msre_actionset_create(engine, + "phase:2,log,auditlog,pass", + &my_error_msg); +} + +/** + * Sets the default values for the hard-coded actionset configuration. + */ +void msre_actionset_set_defaults(msre_actionset *actionset) { + /* Metadata */ + if (actionset->id == NOT_SET_P) actionset->id = NULL; + if (actionset->rev == NOT_SET_P) actionset->rev = NULL; + if (actionset->msg == NOT_SET_P) actionset->msg = NULL; + if (actionset->logdata == NOT_SET_P) actionset->logdata = NULL; + if (actionset->phase == NOT_SET) actionset->phase = 2; + if (actionset->severity == -1) {} /* leave at -1 */ + if (actionset->rule == NOT_SET_P) actionset->rule = NULL; + + /* Flow */ + if (actionset->is_chained == NOT_SET) actionset->is_chained = 0; + if (actionset->skip_count == NOT_SET) actionset->skip_count = 0; + if (actionset->skip_after == NOT_SET_P) actionset->skip_after = NULL; + + /* Disruptive */ + if (actionset->parent_intercept_action_rec == NOT_SET_P) actionset->parent_intercept_action_rec = NULL; + if (actionset->intercept_action_rec == NOT_SET_P) actionset->intercept_action_rec = NULL; + if (actionset->parent_intercept_action == NOT_SET) actionset->parent_intercept_action = ACTION_NONE; + if (actionset->intercept_action == NOT_SET) actionset->intercept_action = ACTION_NONE; + if (actionset->intercept_uri == NOT_SET_P) actionset->intercept_uri = NULL; + if (actionset->intercept_status == NOT_SET) actionset->intercept_status = 403; + if (actionset->intercept_pause == NOT_SET) actionset->intercept_pause = 0; + + /* Other */ + if (actionset->auditlog == NOT_SET) actionset->auditlog = 1; + if (actionset->log == NOT_SET) actionset->log = 1; +} + +/* -- Engine functions ----------------------------------------------------- */ + +/** + * Creates a new engine instance. + */ +msre_engine *msre_engine_create(apr_pool_t *parent_pool) { + msre_engine *engine; + apr_pool_t *mp; + + /* Create new memory pool */ + if (apr_pool_create(&mp, parent_pool) != APR_SUCCESS) return NULL; + + /* Init fields */ + engine = apr_pcalloc(mp, sizeof(msre_engine)); + if (engine == NULL) return NULL; + engine->mp = mp; + engine->tfns = apr_table_make(mp, 25); + if (engine->tfns == NULL) return NULL; + engine->operators = apr_table_make(mp, 25); + if (engine->operators == NULL) return NULL; + engine->variables = apr_table_make(mp, 25); + if (engine->variables == NULL) return NULL; + engine->actions = apr_table_make(mp, 25); + if (engine->actions == NULL) return NULL; + + return engine; +} + +/** + * Destroys an engine instance, releasing the consumed memory. + */ +void msre_engine_destroy(msre_engine *engine) { + /* Destroyed automatically by the parent pool. + * apr_pool_destroy(engine->mp); + */ +} + + +/* -- Recipe functions ----------------------------------------------------- */ + +#define NEXT_CHAIN 1 +#define NEXT_RULE 2 +#define SKIP_RULES 3 + + + +/** + * Default implementation of the ruleset phase processing; it processes + * the rules in the ruleset attached to the currently active + * transaction phase. + */ +#if defined(PERFORMANCE_MEASUREMENT) + +#define PERFORMANCE_MEASUREMENT_LOOP 1000 + +static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_rec *msr); + +apr_status_t msre_ruleset_process_phase(msre_ruleset *ruleset, modsec_rec *msr) { + apr_array_header_t *arr = NULL; + msre_rule **rules = NULL; + apr_status_t rc; + int i; + + switch (msr->phase) { + case PHASE_REQUEST_HEADERS : + arr = ruleset->phase_request_headers; + break; + case PHASE_REQUEST_BODY : + arr = ruleset->phase_request_body; + break; + case PHASE_RESPONSE_HEADERS : + arr = ruleset->phase_response_headers; + break; + case PHASE_RESPONSE_BODY : + arr = ruleset->phase_response_body; + break; + case PHASE_LOGGING : + arr = ruleset->phase_logging; + break; + default : + msr_log(msr, 1, "Internal Error: Invalid phase %d", msr->phase); + return -1; + } + + rules = (msre_rule **)arr->elts; + for (i = 0; i < arr->nelts; i++) { + msre_rule *rule = rules[i]; + rule->execution_time = 0; + } + + for (i = 0; i < PERFORMANCE_MEASUREMENT_LOOP; i++) { + rc = msre_ruleset_process_phase_(ruleset, msr); + } + + msr_log(msr, 1, "Phase %d", msr->phase); + + rules = (msre_rule **)arr->elts; + for (i = 0; i < arr->nelts; i++) { + msre_rule *rule = rules[i]; + + /* Ignore markers, which are never processed. */ + if (rule->placeholder == RULE_PH_MARKER) continue; + + msr_log(msr, 1, "Rule %pp [id \"%s\"][file \"%s\"][line \"%d\"]: %u usec", rule, + ((rule->actionset != NULL)&&(rule->actionset->id != NULL)) ? rule->actionset->id : "-", + rule->filename != NULL ? rule->filename : "-", + rule->line_num, + (rule->execution_time / PERFORMANCE_MEASUREMENT_LOOP)); + } + + return rc; +} + +static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_rec *msr) { +#else +apr_status_t msre_ruleset_process_phase(msre_ruleset *ruleset, modsec_rec *msr) { +#endif + apr_array_header_t *arr = NULL; + msre_rule **rules; + apr_status_t rc; + const char *skip_after = NULL; + int i, mode, skip; + + /* First determine which set of rules we need to use. */ + switch (msr->phase) { + case PHASE_REQUEST_HEADERS : + arr = ruleset->phase_request_headers; + break; + case PHASE_REQUEST_BODY : + arr = ruleset->phase_request_body; + break; + case PHASE_RESPONSE_HEADERS : + arr = ruleset->phase_response_headers; + break; + case PHASE_RESPONSE_BODY : + arr = ruleset->phase_response_body; + break; + case PHASE_LOGGING : + arr = ruleset->phase_logging; + break; + default : + msr_log(msr, 1, "Internal Error: Invalid phase %d", msr->phase); + return -1; + } + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "This phase consists of %d rule(s).", arr->nelts); + } + + /* Loop through the rules in the selected set. */ + skip = 0; + mode = NEXT_RULE; + rules = (msre_rule **)arr->elts; + for (i = 0; i < arr->nelts; i++) { + msre_rule *rule = rules[i]; + #if defined(PERFORMANCE_MEASUREMENT) + apr_time_t time1 = 0; + #endif + + /* Reset the rule interception flag */ + msr->rule_was_intercepted = 0; + + /* SKIP_RULES is used to skip all rules until we hit a placeholder + * with the specified rule ID and then resume execution after that. + */ + if (mode == SKIP_RULES) { + /* Go to the next rule if we have not yet hit the skip_after ID */ + if ((rule->placeholder == RULE_PH_NONE) || (rule->actionset->id == NULL) || (strcmp(skip_after, rule->actionset->id) != 0)) { + if (msr->txcfg->debuglog_level >= 9) { + if (rule->chain_starter != NULL) { + msr_log(msr, 9, "Skipping chain rule %pp id=\"%s\" until after id=\"%s\"", rule, (rule->chain_starter->actionset->id ? rule->chain_starter->actionset->id : "(none)"), skip_after); + + } + else { + msr_log(msr, 9, "Skipping rule %pp id=\"%s\" until after id=\"%s\"", rule, (rule->actionset->id ? rule->actionset->id : "(none)"), skip_after); + + } + } + continue; + } + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Found rule %pp id=\"%s\".", rule, skip_after); + } + + /* Go to the rule *after* this one to continue execution. */ + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Continuing execution after rule id=\"%s\".", skip_after); + } + + skip_after = NULL; + mode = NEXT_RULE; + continue; + } + + /* Skip any rule marked as a placeholder */ + if (rule->placeholder != RULE_PH_NONE) { + continue; + } + + /* NEXT_CHAIN is used when one of the rules in a chain + * fails to match and then we need to skip the remaining + * rules in that chain in order to get to the next + * rule that can execute. + */ + if (mode == NEXT_CHAIN) { + if (rule->actionset->is_chained == 0) { + mode = NEXT_RULE; + } + + /* Go to the next rule. */ + continue; + } + + /* If we are here that means the mode is NEXT_RULE, which + * then means we have done processing any chains. However, + * if the "skip" parameter is set we need to skip over. + */ + if ((mode == NEXT_RULE)&&(skip > 0)) { + /* Decrement the skip counter by one. */ + skip--; + + /* If the current rule is part of a chain then + * we need to skip over the entire chain. Thus + * we change the mode to NEXT_CHAIN. The skip + * counter will not decrement as we are moving + * over the rules belonging to the chain. + */ + if (rule->actionset->is_chained) { + mode = NEXT_CHAIN; + } + + /* Go to the next rule. */ + continue; + } + + /* Check if this rule was removed at runtime */ + if ((rule->actionset->id !=NULL) && (! apr_is_empty_array(msr->removed_rules))) { + int j; + int do_process = 1; + const char *range; + + for(j = 0; j < msr->removed_rules->nelts; j++) { + range = ((const char**)msr->removed_rules->elts)[j]; + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Checking removal of rule id=\"%s\" against: %s", rule->actionset->id, range); + } + + if (rule_id_in_range(atoi(rule->actionset->id), range)) { + do_process = 0; + break; + } + } + + /* Go to the next rule if this one has been removed. */ + if (do_process == 0) { + if (msr->txcfg->debuglog_level >= 5) { + msr_log(msr, 5, "Not processing %srule id=\"%s\": " + "removed by ctl action", + rule->actionset->is_chained ? "chained " : "", + rule->actionset->id); + } + + /* Skip the whole chain, if this is a chained rule */ + if (rule->actionset->is_chained) { + mode = NEXT_CHAIN; + } + + continue; + } + } + + if (msr->txcfg->debuglog_level >= 4) { + apr_pool_t *p = msr->mp; + const char *fn = NULL; + const char *id = NULL; + const char *rev = NULL; + + if (rule->filename != NULL) { + fn = apr_psprintf(p, " [file \"%s\"] [line \"%d\"]", rule->filename, rule->line_num); + } + + if (rule->actionset != NULL && rule->actionset->id != NULL) { + id = apr_psprintf(p, " [id \"%s\"]", rule->actionset->id); + } + + if (rule->actionset != NULL && rule->actionset->rev != NULL) { + rev = apr_psprintf(p, " [rev \"%s\"]", rule->actionset->rev); + } + + msr_log(msr, 4, "Recipe: Invoking rule %pp;%s%s%s.", + rule, (fn ? fn : ""), (id ? id : ""), (rev ? rev : "")); + msr_log(msr, 5, "Rule %pp: %s", rule, rule->unparsed); + } + + #if defined(PERFORMANCE_MEASUREMENT) + time1 = apr_time_now(); + #endif + + rc = msre_rule_process(rule, msr); + + #if defined(PERFORMANCE_MEASUREMENT) + rule->execution_time += (apr_time_now() - time1); + #endif + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Rule returned %d.", rc); + } + + if (rc == RULE_NO_MATCH) { + if (rule->actionset->is_chained) { + /* If the current rule is part of a chain then + * we need to skip over all the rules in the chain. + */ + mode = NEXT_CHAIN; + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "No match, chained -> mode NEXT_CHAIN."); + } + } else { + /* This rule is not part of a chain so we simply + * move to the next rule. + */ + mode = NEXT_RULE; + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "No match, not chained -> mode NEXT_RULE."); + } + } + } + else + if (rc == RULE_MATCH) { + if (msr->rule_was_intercepted) { + /* If the transaction was intercepted by this rule we will + * go back. Do note that we are relying on the + * rule to know if it is a part of a chain and + * not intercept if it is. + */ + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Match, intercepted -> returning."); + } + return 1; + } + + if (rule->actionset->skip_after != NULL) { + skip_after = rule->actionset->skip_after; + mode = SKIP_RULES; + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Skipping after rule %pp id=\"%s\" -> mode SKIP_RULES.", rule, skip_after); + } + + continue; + } + + /* We had a match but the transaction was not + * intercepted. In that case we proceed with the + * next rule... + */ + mode = NEXT_RULE; + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Match -> mode NEXT_RULE."); + } + + /* ...unless we need to skip, in which case we + * determine how many rules/chains we need to + * skip and configure the counter accordingly. + */ + if (rule->actionset->is_chained == 0) { + if (rule->chain_starter != NULL) { + if (rule->chain_starter->actionset->skip_count > 0) { + skip = rule->chain_starter->actionset->skip_count; + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Skipping %d rules/chains (from a chain).", skip); + } + } + } + else if (rule->actionset->skip_count > 0) { + skip = rule->actionset->skip_count; + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Skipping %d rules/chains.", skip); + } + } + } + } + else if (rc < 0) { + msr_log(msr, 1, "Rule processing failed."); + return -1; + } + else { + msr_log(msr, 1, "Rule processing failed with unknown return code: %d.", rc); + return -1; + } + } + + /* ENH warn if chained rules are missing. */ + + return 0; +} + +/** + * Creates a ruleset that will be handled by the default + * implementation. + */ +msre_ruleset *msre_ruleset_create(msre_engine *engine, apr_pool_t *mp) { + msre_ruleset *ruleset; + + ruleset = apr_pcalloc(mp, sizeof(msre_ruleset)); + if (ruleset == NULL) return NULL; + ruleset->mp = mp; + ruleset->engine = engine; + + ruleset->phase_request_headers = apr_array_make(ruleset->mp, 25, sizeof(const msre_rule *)); + ruleset->phase_request_body = apr_array_make(ruleset->mp, 25, sizeof(const msre_rule *)); + ruleset->phase_response_headers = apr_array_make(ruleset->mp, 25, sizeof(const msre_rule *)); + ruleset->phase_response_body = apr_array_make(ruleset->mp, 25, sizeof(const msre_rule *)); + ruleset->phase_logging = apr_array_make(ruleset->mp, 25, sizeof(const msre_rule *)); + + return ruleset; +} + +/** + * Adds one rule to the given phase of the ruleset. + */ +int msre_ruleset_rule_add(msre_ruleset *ruleset, msre_rule *rule, int phase) { + apr_array_header_t *arr = NULL; + + switch (phase) { + case PHASE_REQUEST_HEADERS : + arr = ruleset->phase_request_headers; + break; + case PHASE_REQUEST_BODY : + arr = ruleset->phase_request_body; + break; + case PHASE_RESPONSE_HEADERS : + arr = ruleset->phase_response_headers; + break; + case PHASE_RESPONSE_BODY : + arr = ruleset->phase_response_body; + break; + case PHASE_LOGGING : + arr = ruleset->phase_logging; + break; + default : + return -1; + } + + /* ENH verify the rule's use of targets is consistent with + * the phase it selected to run at. + */ + + msre_actionset_set_defaults(rule->actionset); + rule->actionset->rule = rule; + + *(const msre_rule **)apr_array_push(arr) = rule; + + return 1; +} + +static msre_rule * msre_ruleset_fetch_phase_rule(const msre_ruleset *ruleset, const char *id, + const apr_array_header_t *phase_arr) +{ + msre_rule **rules = (msre_rule **)phase_arr->elts; + int i; + + for (i = 0; i < phase_arr->nelts; i++) { + msre_rule *rule = (msre_rule *)rules[i]; + + /* Rule with an action, not a sub-rule (chain) and a matching id */ + if ( (rule->actionset != NULL) + && (!rule->actionset->is_chained || !rule->chain_starter) + && (rule->actionset->id != NULL) + && (strcmp(rule->actionset->id, id) == 0)) + { + /* Return rule that matched unless it is a placeholder */ + return (rule->placeholder == RULE_PH_NONE) ? rule : NULL; + } + } + + return NULL; +} + +/** + * Fetches rule from the ruleset all rules that match the given exception. + */ +msre_rule * msre_ruleset_fetch_rule(msre_ruleset *ruleset, const char *id) { + msre_rule *rule = NULL; + + if (ruleset == NULL) return NULL; + + rule = msre_ruleset_fetch_phase_rule(ruleset, id, ruleset->phase_request_headers); + if (rule != NULL) return rule; + + rule = msre_ruleset_fetch_phase_rule(ruleset, id, ruleset->phase_request_body); + if (rule != NULL) return rule; + + rule = msre_ruleset_fetch_phase_rule(ruleset, id, ruleset->phase_response_headers); + if (rule != NULL) return rule; + + rule = msre_ruleset_fetch_phase_rule(ruleset, id, ruleset->phase_response_body); + if (rule != NULL) return rule; + + rule = msre_ruleset_fetch_phase_rule(ruleset, id, ruleset->phase_logging); + + return rule; +} + +static int msre_ruleset_phase_rule_remove_with_exception(msre_ruleset *ruleset, rule_exception *re, + apr_array_header_t *phase_arr) +{ + msre_rule **rules; + int i, j, mode, removed_count; + + j = 0; + mode = 0; + removed_count = 0; + rules = (msre_rule **)phase_arr->elts; + for (i = 0; i < phase_arr->nelts; i++) { + msre_rule *rule = (msre_rule *)rules[i]; + + if (mode == 0) { /* Looking for next rule. */ + int remove_rule = 0; + + /* Only remove non-placeholder rules */ + if (rule->placeholder == RULE_PH_NONE) { + switch(re->type) { + case RULE_EXCEPTION_REMOVE_ID : + if ((rule->actionset != NULL)&&(rule->actionset->id != NULL)) { + int ruleid = atoi(rule->actionset->id); + + if (rule_id_in_range(ruleid, re->param)) { + remove_rule = 1; + } + } + + break; + + case RULE_EXCEPTION_REMOVE_MSG : + if ((rule->actionset != NULL)&&(rule->actionset->msg != NULL)) { + char *my_error_msg = NULL; + + int rc = msc_regexec(re->param_data, + rule->actionset->msg, strlen(rule->actionset->msg), + &my_error_msg); + if (rc >= 0) { + remove_rule = 1; + } + } + + break; + } + } + + if (remove_rule) { + /* Do not increment j. */ + removed_count++; + if (rule->actionset->is_chained) mode = 2; /* Remove rules in this chain. */ + } else { + if (rule->actionset->is_chained) mode = 1; /* Keep rules in this chain. */ + rules[j++] = rules[i]; + } + } else { /* Handling rule that is part of a chain. */ + if (mode == 2) { /* We want to remove the rule. */ + /* Do not increment j. */ + removed_count++; + } else { + rules[j++] = rules[i]; + } + + if ((rule->actionset == NULL)||(rule->actionset->is_chained == 0)) mode = 0; + } + } + + /* Update the number of rules in the array. */ + phase_arr->nelts -= removed_count; + + return 0; +} + +/** + * Removes from the ruleset all rules that match the given exception. + */ +int msre_ruleset_rule_remove_with_exception(msre_ruleset *ruleset, rule_exception *re) { + int count = 0; + + if (ruleset == NULL) return 0; + + count += msre_ruleset_phase_rule_remove_with_exception(ruleset, re, ruleset->phase_request_headers); + count += msre_ruleset_phase_rule_remove_with_exception(ruleset, re, ruleset->phase_request_body); + count += msre_ruleset_phase_rule_remove_with_exception(ruleset, re, ruleset->phase_response_headers); + count += msre_ruleset_phase_rule_remove_with_exception(ruleset, re, ruleset->phase_response_body); + count += msre_ruleset_phase_rule_remove_with_exception(ruleset, re, ruleset->phase_logging); + + return count; +} + + +/* -- Rule functions ------------------------------------------------------- */ + +/** + * Returns the name of the supplied severity level. + */ +static const char *msre_format_severity(int severity) { + if ((severity >= 0)&&(severity <= 7)) { + return severities[severity]; + } + else { + return "(invalid value)"; + } +} + +/** + * Creates a string containing the metadata of the supplied rule. + */ +char *msre_format_metadata(modsec_rec *msr, msre_actionset *actionset) { + const apr_array_header_t *tarr; + const apr_table_entry_t *telts; + char *id = ""; + char *rev = ""; + char *msg = ""; + char *logdata = ""; + char *severity = ""; + char *tags = ""; + char *fn = ""; + int k; + + if (actionset == NULL) return ""; + + if ((actionset->rule != NULL) && (actionset->rule->filename != NULL)) { + fn = apr_psprintf(msr->mp, " [file \"%s\"] [line \"%d\"]", + actionset->rule->filename, actionset->rule->line_num); + } + if (actionset->id != NULL) { + id = apr_psprintf(msr->mp, " [id \"%s\"]", + log_escape(msr->mp, actionset->id)); + } + if (actionset->rev != NULL) { + rev = apr_psprintf(msr->mp, " [rev \"%s\"]", + log_escape(msr->mp, actionset->rev)); + } + if (actionset->msg != NULL) { + /* Expand variables in the message string. */ + msc_string *var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + var->value = (char *)actionset->msg; + var->value_len = strlen(actionset->msg); + expand_macros(msr, var, NULL, msr->mp); + + msg = apr_psprintf(msr->mp, " [msg \"%s\"]", + log_escape_ex(msr->mp, var->value, var->value_len)); + } + if (actionset->logdata != NULL) { + /* Expand variables in the message string. */ + msc_string *var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + var->value = (char *)actionset->logdata; + var->value_len = strlen(actionset->logdata); + expand_macros(msr, var, NULL, msr->mp); + + logdata = apr_psprintf(msr->mp, " [data \"%s\"]", + log_escape_hex(msr->mp, (unsigned char *)var->value, var->value_len)); + + /* If it is > 512 bytes, then truncate at 512 with ellipsis. + * NOTE: 512 actual data + 9 bytes of label = 521 + */ + if (strlen(logdata) > 521) { + logdata[517] = '.'; + logdata[518] = '.'; + logdata[519] = '.'; + logdata[520] = '"'; + logdata[521] = ']'; + logdata[522] = '\0'; + } + } + if ((actionset->severity >= 0)&&(actionset->severity <= 7)) { + severity = apr_psprintf(msr->mp, " [severity \"%s\"]", + msre_format_severity(actionset->severity)); + } + + /* Extract rule tags from the action list. */ + tarr = apr_table_elts(actionset->actions); + telts = (const apr_table_entry_t*)tarr->elts; + + for (k = 0; k < tarr->nelts; k++) { + msre_action *action = (msre_action *)telts[k].val; + if (strcmp(telts[k].key, "tag") == 0) { + tags = apr_psprintf(msr->mp, "%s [tag \"%s\"]", tags, + log_escape(msr->mp, action->param)); + } + } + + return apr_pstrcat(msr->mp, fn, id, rev, msg, logdata, severity, tags, NULL); +} + +char * msre_rule_generate_unparsed(apr_pool_t *pool, const msre_rule *rule, const char *targets, + const char *args, const char *actions) +{ + char *unparsed = NULL; + const char *r_targets = targets; + const char *r_args = args; + const char *r_actions = actions; + + if (r_targets == NULL) { + r_targets = rule->p1; + } + if (r_args == NULL) { + r_args = apr_pstrcat(pool, (rule->op_negated ? "!" : ""), "@", rule->op_name, " ", rule->op_param, NULL); + } + if (r_actions == NULL) { + r_actions = msre_actionset_generate_action_string(pool, rule->actionset); + } + + switch (rule->type) { + case RULE_TYPE_NORMAL: + if (r_actions == NULL) { + unparsed = apr_psprintf(pool, "SecRule \"%s\" \"%s\"", + log_escape(pool, r_targets), log_escape(pool, r_args)); + } + else { + unparsed = apr_psprintf(pool, "SecRule \"%s\" \"%s\" \"%s\"", + log_escape(pool, r_targets), log_escape(pool, r_args), + log_escape(pool, r_actions)); + } + break; + case RULE_TYPE_ACTION: + unparsed = apr_psprintf(pool, "SecAction \"%s\"", + log_escape(pool, r_actions)); + break; + case RULE_TYPE_MARKER: + unparsed = apr_psprintf(pool, "SecMarker \"%s\"", rule->actionset->id); + break; + #if defined(WITH_LUA) + case RULE_TYPE_LUA: + /* SecRuleScript */ + if (r_actions == NULL) { + unparsed = apr_psprintf(pool, "SecRuleScript \"%s\"", r_args); + } + else { + unparsed = apr_psprintf(pool, "SecRuleScript \"%s\" \"%s\"", + r_args, log_escape(pool, r_actions)); + } + break; + #endif + } + + return unparsed; +} + +/** + * Assembles a new rule using the strings that contain a list + * of targets (variables), arguments, and actions. + */ +msre_rule *msre_rule_create(msre_ruleset *ruleset, int type, + const char *fn, int line, const char *targets, + const char *args, const char *actions, char **error_msg) +{ + msre_rule *rule; + char *my_error_msg; + const char *argsp; + int rc; + + if (error_msg == NULL) return NULL; + *error_msg = NULL; + + rule = (msre_rule *)apr_pcalloc(ruleset->mp, sizeof(msre_rule)); + if (rule == NULL) return NULL; + + rule->type = type; + rule->ruleset = ruleset; + rule->targets = apr_array_make(ruleset->mp, 10, sizeof(const msre_var *)); + rule->p1 = apr_pstrdup(ruleset->mp, targets); + rule->filename = apr_pstrdup(ruleset->mp, fn); + rule->line_num = line; + + /* Parse targets */ + rc = msre_parse_targets(ruleset, targets, rule->targets, &my_error_msg); + if (rc < 0) { + *error_msg = apr_psprintf(ruleset->mp, "Error creating rule: %s", my_error_msg); + return NULL; + } + + /* Parse args */ + argsp = args; + + /* Is negation used? */ + if (*argsp == '!') { + rule->op_negated = 1; + argsp++; + while((isspace(*argsp))&&(*argsp != '\0')) argsp++; + } + + /* Is the operator explicitly selected? */ + if (*argsp != '@') { + /* Go with a regular expression. */ + rule->op_name = "rx"; + rule->op_param = argsp; + } else { + /* Explicitly selected operator. */ + char *p = (char *)(argsp + 1); + while((!isspace(*p))&&(*p != '\0')) p++; + rule->op_name = apr_pstrmemdup(ruleset->mp, argsp + 1, p - (argsp + 1)); + while(isspace(*p)) p++; /* skip over the whitespace at the end*/ + rule->op_param = p; /* IMP1 So we always have a parameter even when it's empty? */ + } + + /* Find the operator. */ + rule->op_metadata = msre_engine_op_resolve(ruleset->engine, rule->op_name); + if (rule->op_metadata == NULL) { + *error_msg = apr_psprintf(ruleset->mp, + "Error creating rule: Failed to resolve operator: %s", rule->op_name); + return NULL; + } + + /* Initialise & validate parameter */ + if (rule->op_metadata->param_init != NULL) { + if (rule->op_metadata->param_init(rule, &my_error_msg) <= 0) { + *error_msg = apr_psprintf(ruleset->mp, "Error creating rule: %s", my_error_msg); + return NULL; + } + } + + /* Parse actions */ + if (actions != NULL) { + /* Create per-rule actionset */ + rule->actionset = msre_actionset_create(ruleset->engine, actions, &my_error_msg); + if (rule->actionset == NULL) { + *error_msg = apr_psprintf(ruleset->mp, "Error parsing actions: %s", my_error_msg); + return NULL; + } + } + + /* Add the unparsed rule */ + rule->unparsed = msre_rule_generate_unparsed(ruleset->mp, rule, targets, args, NULL); + + return rule; +} + +#if defined(WITH_LUA) +/** + * + */ +msre_rule *msre_rule_lua_create(msre_ruleset *ruleset, + const char *fn, int line, const char *script_filename, + const char *actions, char **error_msg) +{ + msre_rule *rule; + char *my_error_msg; + + if (error_msg == NULL) return NULL; + *error_msg = NULL; + + rule = (msre_rule *)apr_pcalloc(ruleset->mp, sizeof(msre_rule)); + if (rule == NULL) return NULL; + + rule->type = RULE_TYPE_LUA; + rule->ruleset = ruleset; + rule->filename = apr_pstrdup(ruleset->mp, fn); + rule->line_num = line; + + /* Compile script. */ + *error_msg = lua_compile(&rule->script, script_filename, ruleset->mp); + if (*error_msg != NULL) { + return NULL; + } + + /* Parse actions */ + if (actions != NULL) { + /* Create per-rule actionset */ + rule->actionset = msre_actionset_create(ruleset->engine, actions, &my_error_msg); + if (rule->actionset == NULL) { + *error_msg = apr_psprintf(ruleset->mp, "Error parsing actions: %s", my_error_msg); + return NULL; + } + } + + /* Add the unparsed rule */ + rule->unparsed = msre_rule_generate_unparsed(ruleset->mp, rule, NULL, script_filename, NULL); + + return rule; +} +#endif + +/** + * Perform non-disruptive actions associated with the provided actionset. + */ +static void msre_perform_nondisruptive_actions(modsec_rec *msr, msre_rule *rule, + msre_actionset *actionset, apr_pool_t *mptmp) +{ + const apr_array_header_t *tarr; + const apr_table_entry_t *telts; + int i; + + tarr = apr_table_elts(actionset->actions); + telts = (const apr_table_entry_t*)tarr->elts; + for (i = 0; i < tarr->nelts; i++) { + msre_action *action = (msre_action *)telts[i].val; + if (action->metadata->type == ACTION_NON_DISRUPTIVE) { + if (action->metadata->execute != NULL) { + action->metadata->execute(msr, mptmp, rule, action); + } + } + } +} + +/** + * Perform the disruptive actions associated with the given actionset. + */ +static void msre_perform_disruptive_actions(modsec_rec *msr, msre_rule *rule, + msre_actionset *actionset, apr_pool_t *mptmp, const char *message) +{ + const apr_array_header_t *tarr; + const apr_table_entry_t *telts; + int i; + + /* Execute the disruptive actions. Do note that this does + * not mean the request will be interrupted straight away. All + * disruptive actions need to do here is update the information + * that will be used to act later. + */ + tarr = apr_table_elts(actionset->actions); + telts = (const apr_table_entry_t*)tarr->elts; + for (i = 0; i < tarr->nelts; i++) { + msre_action *action = (msre_action *)telts[i].val; + if (action->metadata->type == ACTION_DISRUPTIVE) { + if (action->metadata->execute != NULL) { + action->metadata->execute(msr, mptmp, rule, action); + } + } + } + + /* If "noauditlog" was used do not mark the transaction relevant. */ + if (actionset->auditlog != 0) { + msr->is_relevant++; + } + + /* We only do stuff when in ONLINE mode. In all other + * cases we only emit warnings. + */ + if ((msr->phase == PHASE_LOGGING) + || (msr->txcfg->is_enabled == MODSEC_DETECTION_ONLY) + || (msr->modsecurity->processing_mode == MODSEC_OFFLINE) + || (actionset->intercept_action == ACTION_NONE)) + { + int log_level; + + /* If "nolog" was used log at a higher level to prevent an "alert". */ + if (actionset->log == 0) { + log_level = 4; + + /* But, if "auditlog" is enabled, then still add the message. */ + if (actionset->auditlog != 0) { + *(const char **)apr_array_push(msr->alerts) = msc_alert_message(msr, actionset, NULL, message); + } + + } + else { + log_level = 2; + } + + msc_alert(msr, log_level, actionset, "Warning.", message); + + /* However, this will mark the txn relevant again if it is <= 3, + * which will mess up noauditlog. We need to compensate for this + * so that we do not increment twice when auditlog is enabled and + * prevent incrementing when auditlog is disabled. + */ + if (log_level <= 3) { + msr->is_relevant--; + } + + return; + } + + /* Signal to the engine we need to intercept this + * transaction, and rememer the rule that caused it. + */ + msr->was_intercepted = 1; + msr->rule_was_intercepted = 1; + msr->intercept_phase = msr->phase; + msr->intercept_actionset = actionset; + msr->intercept_message = message; +} + +/** + * Invokes the rule operator against the given value. + */ +static int execute_operator(msre_var *var, msre_rule *rule, modsec_rec *msr, + msre_actionset *acting_actionset, apr_pool_t *mptmp) +{ + apr_time_t time_before_op = 0; + char *my_error_msg = NULL; + const char *full_varname = NULL; + int rc; + + /* determine the full var name if not already resolved + * + * NOTE: this can happen if the var does not match but it is + * being tested for non-existance as in: + * @REQUEST_HEADERS:Foo "@eq 0" + * @REQUEST_HEADERS:Foo "!@eq 1" + */ + if ((var->param != NULL) && (var->name != NULL) && (strchr(var->name,':') == NULL)) { + full_varname = apr_psprintf(mptmp, "%s%s:%s", + (var->is_counting ? "&" : ""), + var->name, var->param); + } + else if ((var->name != NULL) && var->is_counting && (*var->name != '&')) { + full_varname = apr_pstrcat(mptmp, "&", var->name, NULL); + } + else { + full_varname = var->name; + } + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Executing operator \"%s%s\" with param \"%s\" against %s.", + (rule->op_negated ? "!" : ""), rule->op_name, + log_escape(msr->mp, rule->op_param), full_varname); + } + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Target value: \"%s\"", log_escape_nq_ex(msr->mp, var->value, + var->value_len)); + } + + #if defined(PERFORMANCE_MEASUREMENT) + time_before_op = apr_time_now(); + #else + if (msr->txcfg->debuglog_level >= 4) { + time_before_op = apr_time_now(); + } + #endif + + rc = rule->op_metadata->execute(msr, rule, var, &my_error_msg); + + #if defined(PERFORMANCE_MEASUREMENT) + { + /* Record performance but do not log anything. */ + apr_time_t t1 = apr_time_now(); + rule->op_time += (t1 - time_before_op); + } + #else + if (msr->txcfg->debuglog_level >= 4) { + apr_time_t t1 = apr_time_now(); + msr_log(msr, 4, "Operator completed in %" APR_TIME_T_FMT " usec.", (t1 - time_before_op)); + } + #endif + + if (rc < 0) { + msr_log(msr, 4, "Operator error: %s", my_error_msg); + return -1; + } + + if (((rc == 0)&&(rule->op_negated == 0))||((rc == 1)&&(rule->op_negated == 1))) { + /* No match, do nothing. */ + return RULE_NO_MATCH; + } + else { + /* Match. */ + if (rc == 0) { + char *op_param = log_escape(msr->mp, rule->op_param); + + /* Truncate op parameter. */ + if (strlen(op_param) > 252) { + op_param = apr_psprintf(msr->mp, "%.252s ...", op_param); + } + + /* Operator did not match so we need to provide a message. */ + my_error_msg = apr_psprintf(msr->mp, "Match of \"%s %s\" against \"%s\" required.", + log_escape(msr->mp, rule->op_name), op_param, + log_escape(msr->mp, full_varname)); + } + + /* Save the rules that match */ + *(const msre_rule **)apr_array_push(msr->matched_rules) = rule; + + /* Save the last matched var data */ + msr->matched_var->name = apr_pstrdup(msr->mp, var->name); + msr->matched_var->name_len = strlen(msr->matched_var->name); + msr->matched_var->value = apr_pmemdup(msr->mp, var->value, var->value_len); + msr->matched_var->value_len = var->value_len; + + /* Keep track of the highest severity matched so far */ + if ((acting_actionset->severity > 0) && (acting_actionset->severity < msr->highest_severity)) + { + msr->highest_severity = acting_actionset->severity; + } + + + /* Perform non-disruptive actions. */ + msre_perform_nondisruptive_actions(msr, rule, rule->actionset, mptmp); + + /* Perform disruptive actions, but only if + * this rule is not part of a chain. + */ + if (rule->actionset->is_chained == 0) { + msre_perform_disruptive_actions(msr, rule, acting_actionset, mptmp, my_error_msg); + } + + return RULE_MATCH; + } +} + +/** + * Executes rule against the given transaction. + */ +static apr_status_t msre_rule_process_normal(msre_rule *rule, modsec_rec *msr) { + const apr_array_header_t *arr = NULL; + const apr_table_entry_t *te = NULL; + msre_actionset *acting_actionset = NULL; + msre_var **targets = NULL; + apr_pool_t *mptmp = msr->msc_rule_mptmp; + apr_table_t *tartab = NULL; + apr_table_t *vartab = NULL; + int i, rc = 0, match_count = 0; + int invocations = 0; + int multi_match = 0; + + /* Choose the correct metadata/disruptive action actionset. */ + acting_actionset = rule->actionset; + if (rule->chain_starter != NULL) { + acting_actionset = rule->chain_starter->actionset; + } + + /* Configure recursive matching. */ + if (apr_table_get(rule->actionset->actions, "multiMatch") != NULL) { + multi_match = 1; + } + + /* ENH: What is a good initial size? */ + tartab = apr_table_make(mptmp, 24); + if (tartab == NULL) return -1; + vartab = apr_table_make(mptmp, 24); + if (vartab == NULL) return -1; + + /* Expand variables to create a list of targets. */ + + targets = (msre_var **)rule->targets->elts; + for (i = 0; i < rule->targets->nelts; i++) { + int j, list_count; + + apr_table_clear(vartab); + + /* ENH Introduce a new variable hook that would allow the code + * behind the variable to return the size of the collection + * without having to generate the variables. + */ + + /* Expand individual variables first. */ + list_count = targets[i]->metadata->generate(msr, targets[i], rule, vartab, mptmp); + + if (targets[i]->is_counting) { + /* Count how many there are and just add the score to the target list. */ + msre_var *newvar = (msre_var *)apr_pmemdup(mptmp, targets[i], sizeof(msre_var)); + newvar->value = apr_psprintf(mptmp, "%d", list_count); + newvar->value_len = strlen(newvar->value); + apr_table_addn(tartab, newvar->name, (void *)newvar); + } else { + /* And either add them or remove from the final target list. */ + arr = apr_table_elts(vartab); + te = (apr_table_entry_t *)arr->elts; + for(j = 0; j < arr->nelts; j++) { + if (targets[i]->is_negated == 0) { + apr_table_addn(tartab, te[j].key, te[j].val); + } else { + apr_table_unset(tartab, te[j].key); + } + } + } + } + + /* Log the target variable expansion */ + if (msr->txcfg->debuglog_level >= 4) { + const char *expnames = NULL; + + arr = apr_table_elts(tartab); + if (arr->nelts > 1) { + te = (apr_table_entry_t *)arr->elts; + expnames = apr_pstrdup(mptmp, ((msre_var *)te[0].val)->name); + for(i = 1; i < arr->nelts; i++) { + expnames = apr_psprintf(mptmp, "%s|%s", expnames, ((msre_var *)te[i].val)->name); + } + if (strcmp(rule->p1, expnames) != 0) { + msr_log(msr, 4, "Expanded \"%s\" to \"%s\".", rule->p1, expnames); + } + } + } + + /* Loop through targets on the final target list, + * perform transformations as necessary, and invoke + * the operator. + */ + + arr = apr_table_elts(tartab); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + int changed; + int usecache = 0; + apr_table_t *cachetab = NULL; + apr_time_t time_before_trans = 0; + msre_var *var; + + /* Take one target. */ + var = (msre_var *)te[i].val; + + /* Is this var cacheable? */ + if (msr->txcfg->cache_trans != MODSEC_CACHE_DISABLED) { + usecache = 1; + + /* Counting vars are not cacheable due to them being created + * in a local per-rule pool. + */ + if (var->is_counting) { + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "CACHE: Disabled - &%s is dynamic", var->name); + } + + usecache = 0; + } + /* Only cache if if the variable is available in this phase */ + else if (msr->phase < var->metadata->availability) { + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "CACHE: Disabled - %s is not yet available in phase %d (requires phase %d or later)", var->name, msr->phase, var->metadata->availability); + } + + usecache = 0; + } + /* check the cache options */ + else if (var->value_len < msr->txcfg->cache_trans_min) { + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "CACHE: Disabled - %s value length=%u, smaller than minlen=%" APR_SIZE_T_FMT, var->name, var->value_len, msr->txcfg->cache_trans_min); + } + + usecache = 0; + } + else if ((msr->txcfg->cache_trans_max != 0) && (var->value_len > msr->txcfg->cache_trans_max)) { + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "CACHE: Disabled - %s value length=%u, larger than maxlen=%" APR_SIZE_T_FMT, var->name, var->value_len, msr->txcfg->cache_trans_max); + } + + usecache = 0; + } + + /* if cache is still enabled, check the VAR for cacheablity */ + if (usecache) { + if (var->metadata->is_cacheable == VAR_CACHE) { + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "CACHE: Enabled"); + } + + #ifdef CACHE_DEBUG + msr_log(msr, 9, "CACHE: Fetching cache entry from hash=%pp: %pp=%s", msr->tcache, var, var->name); + #endif + + /* Fetch cache table for this target */ + cachetab = (apr_table_t *)apr_hash_get(msr->tcache, var->value, sizeof(var->value)); + + /* Create an empty cache table if this is the first time */ + #ifdef CACHE_DEBUG + if (cachetab) { + msr_log(msr, 9, "CACHE: Using cache table %pp", cachetab); + } + else + #else + if (cachetab == NULL) + #endif + { + /* NOTE: We use the pointer to the var value as a hash + * key as it is unique. This pointer *must* + * remain valid through the entire phase. If + * it does not, then we will not receive a cache + * hit and just wasted RAM. So, it is important + * that any such vars be marked as VAR_DONT_CACHE. + * + * ENH: Only use pointer for non-scalar vars + */ + cachetab = apr_table_make(msr->mp, 3); + apr_hash_set(msr->tcache, var->value, sizeof(var->value), cachetab); + + #ifdef CACHE_DEBUG + msr_log(msr, 9, "CACHE: Created a new cache table %pp for %pp", cachetab, var->value); + #endif + } + + } + else { + usecache = 0; + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "CACHE: %s transformations are not cacheable", var->name); + } + } + } + } + + #if defined(PERFORMANCE_MEASUREMENT) + time_before_trans = apr_time_now(); + #else + if (msr->txcfg->debuglog_level >= 4) { + time_before_trans = apr_time_now(); + } + #endif + + /* Transform target. */ + { + const apr_array_header_t *tarr; + const apr_table_entry_t *telts; + const char *tfnspath = NULL; + char *tfnskey = NULL; + int tfnscount = 0; + int last_cached_tfn = 0; + msre_cache_rec *crec = NULL; + msre_cache_rec *last_crec = NULL; + int k; + msre_action *action; + msre_tfn_metadata *metadata; + apr_table_t *normtab; + const char *lastvarval = NULL; + apr_size_t lastvarlen = 0; + + changed = 0; + normtab = apr_table_make(mptmp, 10); + if (normtab == NULL) return -1; + tarr = apr_table_elts(rule->actionset->actions); + telts = (const apr_table_entry_t*)tarr->elts; + + /* Build the final list of transformation functions. */ + for (k = 0; k < tarr->nelts; k++) { + action = (msre_action *)telts[k].val; + + if (strcmp(telts[k].key, "t") == 0) { + if (strcmp(action->param, "none") == 0) { + apr_table_clear(normtab); + tfnspath = NULL; + tfnskey = NULL; + tfnscount = 0; + last_crec = NULL; + last_cached_tfn = 0; + continue; + } + + if (action->param_plusminus == NEGATIVE_VALUE) { + apr_table_unset(normtab, action->param); + } + else { + tfnscount++; + + apr_table_addn(normtab, action->param, (void *)action); + + /* Check the cache, saving the 'most complete' as a + * starting point + */ + if (usecache) { + tfnspath = apr_psprintf(mptmp, "%s%s%s", (tfnspath?tfnspath:""), (tfnspath?",":""), action->param); + tfnskey = apr_psprintf(mptmp, "%x;%s", tfnscount, tfnspath); + crec = (msre_cache_rec *)apr_table_get(cachetab, tfnskey); + + #ifdef CACHE_DEBUG + msr_log(msr, 9, "CACHE: %s %s cached=%d", var->name, tfnskey, (crec ? 1 : 0)); + #endif + + if (crec != NULL) { + last_crec = crec; + last_cached_tfn = tfnscount; + } + } + } + } + } + + /* If the last cached tfn is the last in the list + * then we can stop here and just execute the action immediatly + */ + if (usecache && !multi_match && + (crec != NULL) && (crec == last_crec)) + { + crec->hits++; + + if (crec->changed) { + var->value = apr_pmemdup(mptmp, crec->val, crec->val_len); + var->value_len = crec->val_len; + } + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "T (%d) %s: \"%s\" [fully cached hits=%d]", crec->changed, crec->path, + log_escape_nq_ex(mptmp, var->value, var->value_len), crec->hits); + } + + #if defined(PERFORMANCE_MEASUREMENT) + { + apr_time_t t1 = apr_time_now(); + rule->trans_time += (t1 - time_before_trans); + } + #else + if (msr->txcfg->debuglog_level >= 4) { + apr_time_t t1 = apr_time_now(); + + msr_log(msr, 4, "Transformation completed in %" APR_TIME_T_FMT " usec.", + (t1 - time_before_trans)); + } + #endif + + rc = execute_operator(var, rule, msr, acting_actionset, mptmp); + + if (rc < 0) { + return -1; + } + + if (rc == RULE_MATCH) { + match_count++; + + /* Return straight away if the transaction + * was intercepted - no need to process the remaining + * targets. + */ + if (msr->rule_was_intercepted) { + return RULE_MATCH; + } + } + + continue; /* next target */ + } + + + /* Perform transformations. */ + + tarr = apr_table_elts(normtab); + + /* Execute transformations in a loop. */ + + /* Start after the last known cached transformation if we can */ + if (!multi_match && (last_crec != NULL)) { + k = last_cached_tfn; + tfnspath = last_crec->path; + last_crec->hits++; + + if ((changed = last_crec->changed) > 0) { + var->value = last_crec->val; + var->value_len = last_crec->val_len; + } + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "T (%d) %s: \"%s\" [partially cached hits=%d]", last_crec->changed, + tfnspath, log_escape_nq_ex(mptmp, var->value, var->value_len), last_crec->hits); + } + } + else { + tfnspath = NULL; + k = 0; + } + + /* Make a copy of the value so that we can change it in-place. */ + if (tarr->nelts) { + var->value = apr_pstrmemdup(mptmp, var->value, var->value_len); + /* var->value_len remains the same */ + } + + telts = (const apr_table_entry_t*)tarr->elts; + for (; k < tarr->nelts; k++) { + char *rval = NULL; + long int rval_length = -1; + int tfnchanged = 0; + + /* In multi-match mode we execute the operator + * once at the beginning and then once every + * time the variable is changed by the transformation + * function. + */ + if (multi_match && (k == 0 || tfnchanged)) { + invocations++; + + #if defined(PERFORMANCE_MEASUREMENT) + { + apr_time_t t1 = apr_time_now(); + rule->trans_time += (t1 - time_before_trans); + } + #else + if (msr->txcfg->debuglog_level >= 4) { + apr_time_t t1 = apr_time_now(); + + msr_log(msr, 4, "Transformation completed in %" APR_TIME_T_FMT " usec.", + (t1 - time_before_trans)); + } + #endif + + rc = execute_operator(var, rule, msr, acting_actionset, mptmp); + + if (rc < 0) { + return -1; + } + + if (rc == RULE_MATCH) { + match_count++; + + /* Return straight away if the transaction + * was intercepted - no need to process the remaining + * targets. + */ + if (msr->rule_was_intercepted) { + return RULE_MATCH; + } + } + } + + /* Perform one transformation. */ + action = (msre_action *)telts[k].val; + metadata = (msre_tfn_metadata *)action->param_data; + tfnchanged = metadata->execute(mptmp, + (unsigned char *)var->value, var->value_len, + &rval, &rval_length); + + if (tfnchanged < 0) { + return -1; + } + + if (tfnchanged) { + changed++; + } + + /* Use the new values */ + var->value = rval; + var->value_len = rval_length; + + /* Cache the transformation */ + if (usecache) { + int tfnsnum = k + 1; + + /* Generate the cache key */ + tfnspath = apr_psprintf(msr->mp, "%s%s%s", (tfnspath ? tfnspath : ""), + (tfnspath ? "," : ""), action->param); + tfnskey = apr_psprintf(msr->mp, "%x;%s", tfnsnum, tfnspath); + + if ((msr->txcfg->cache_trans_maxitems != 0) && + (msr->tcache_items >= msr->txcfg->cache_trans_maxitems)) + { + /* Warn only once if we attempt to go over the cache limit. */ + if (msr->tcache_items == msr->txcfg->cache_trans_maxitems) { + msr->tcache_items++; + msr_log(msr, 4, "CACHE: Disabled - phase=%d" + " maxitems=%" APR_SIZE_T_FMT + " limit reached.", + msr->phase, + msr->txcfg->cache_trans_maxitems); + } + } + else if (msr->txcfg->cache_trans_incremental || + (tfnsnum == tarr->nelts)) + { + /* ENH1: Add flag to vars to tell which ones can change across phases store the rest in a global cache */ + crec = (msre_cache_rec *)apr_pcalloc(msr->mp, sizeof(msre_cache_rec)); + if (crec == NULL) return -1; + + crec->hits = 0; + crec->changed = changed; + crec->num = k + 1; + crec->path = tfnspath; + + /* We want to cache a copy if it changed otherwise + * we just want to use a pointer to the last changed value. + */ + crec->val = (!lastvarval || tfnchanged) ? apr_pmemdup(msr->mp, var->value, var->value_len) : lastvarval; + crec->val_len = changed ? ((!lastvarval || tfnchanged) ? var->value_len : lastvarlen) : 0; + + /* Keep track of the last changed var value */ + if (tfnchanged) { + lastvarval = crec->val; + lastvarlen = crec->val_len; + } + + #ifdef CACHE_DEBUG + if (changed) { + msr_log(msr, 9, "CACHE: Caching %s=\"%s\" (%pp)", + tfnskey, + log_escape_nq_ex(mptmp, + crec->val, + crec->val_len), + var); + } + else { + msr_log(msr, 9, "CACHE: Caching %s= (%pp)", + tfnskey, + var); + } + #endif + + msr->tcache_items++; + + apr_table_setn(cachetab, tfnskey, (void *)crec); + } + } + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "T (%d) %s: \"%s\"", rc, metadata->name, + log_escape_nq_ex(mptmp, var->value, var->value_len)); + } + } + } + + /* Execute operator if multi-matching is not enabled, + * or if it is and we need to process the result of the + * last transformation. + */ + if (!multi_match || changed) { + invocations++; + + #if defined(PERFORMANCE_MEASUREMENT) + { + apr_time_t t1 = apr_time_now(); + rule->trans_time += (t1 - time_before_trans); + } + #else + if (msr->txcfg->debuglog_level >= 4) { + apr_time_t t1 = apr_time_now(); + + msr_log(msr, 4, "Transformation completed in %" APR_TIME_T_FMT " usec.", + (t1 - time_before_trans)); + } + #endif + + rc = execute_operator(var, rule, msr, acting_actionset, mptmp); + + if (rc < 0) { + return -1; + } + + if (rc == RULE_MATCH) { + match_count++; + + /* Return straight away if the transaction + * was intercepted - no need to process the remaining + * targets. + */ + if (msr->rule_was_intercepted) { + return RULE_MATCH; + } + } + } + } + + + return (match_count ? RULE_MATCH : RULE_NO_MATCH); +} + +#if defined(WITH_LUA) +/** + * + */ +static apr_status_t msre_rule_process_lua(msre_rule *rule, modsec_rec *msr) { + msre_actionset *acting_actionset = NULL; + char *my_error_msg = NULL; + int rc; + + /* Choose the correct metadata/disruptive action actionset. */ + acting_actionset = rule->actionset; + if (rule->chain_starter != NULL) { + acting_actionset = rule->chain_starter->actionset; + } + + rc = lua_execute(rule->script, NULL, msr, rule, &my_error_msg); + if (rc < 0) { + msr_log(msr, 1, "%s", my_error_msg); + return -1; + } + + /* A non-NULL error message means the rule matched. */ + if (my_error_msg != NULL) { + /* Perform non-disruptive actions. */ + msre_perform_nondisruptive_actions(msr, rule, rule->actionset, msr->msc_rule_mptmp); + + /* Perform disruptive actions, but only if + * this rule is not part of a chain. + */ + if (rule->actionset->is_chained == 0) { + msre_perform_disruptive_actions(msr, rule, acting_actionset, msr->msc_rule_mptmp, my_error_msg); + } + } + + return rc; +} +#endif + +/** + * + */ +apr_status_t msre_rule_process(msre_rule *rule, modsec_rec *msr) { + /* Use a fresh memory sub-pool for processing each rule */ + if (msr->msc_rule_mptmp == NULL) { + if (apr_pool_create(&msr->msc_rule_mptmp, msr->mp) != APR_SUCCESS) { + return -1; + } + } else { + apr_pool_clear(msr->msc_rule_mptmp); + } + + #if defined(WITH_LUA) + if (rule->type == RULE_TYPE_LUA) { + return msre_rule_process_lua(rule, msr); + } + #endif + + return msre_rule_process_normal(rule, msr); +} + +/** + * Checks whether the given rule ID is in the given range. + */ +int rule_id_in_range(int ruleid, const char *range) { + char *p = NULL, *saveptr = NULL; + char *data = NULL; + + if (range == NULL) return 0; + data = strdup(range); + if (data == NULL) return 0; + + p = apr_strtok(data, ",", &saveptr); + while(p != NULL) { + char *s = strstr(p, "-"); + if (s == NULL) { + if (ruleid == atoi(p)) { + free(data); + return 1; + } + } else { + int start = atoi(p); + int end = atoi(s + 1); + if ((ruleid >= start)&&(ruleid <= end)) { + free(data); + return 1; + } + } + p = apr_strtok(NULL, ",", &saveptr); + } + + free(data); + + return 0; +} diff --git a/apache2/re.h b/apache2/re.h new file mode 100644 index 0000000..cdd5761 --- /dev/null +++ b/apache2/re.h @@ -0,0 +1,387 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ +#ifndef _MSC_RE_H_ +#define _MSC_RE_H_ + +#define ABSOLUTE_VALUE 0 +#define POSITIVE_VALUE 1 +#define NEGATIVE_VALUE 2 + +typedef struct msre_engine msre_engine; +typedef struct msre_ruleset msre_ruleset; +typedef struct msre_ruleset_internal msre_ruleset_internal; +typedef struct msre_rule msre_rule; +typedef struct msre_var_metadata msre_var_metadata; +typedef struct msre_var msre_var; +typedef struct msre_op_metadata msre_op_metadata; +typedef struct msre_tfn_metadata msre_tfn_metadata; +typedef struct msre_actionset msre_actionset; +typedef struct msre_action_metadata msre_action_metadata; +typedef struct msre_action msre_action; +typedef struct msre_cache_rec msre_cache_rec; + +#include "apr_general.h" +#include "apr_tables.h" +#include "modsecurity.h" +#include "msc_pcre.h" +#include "persist_dbm.h" +#include "apache2.h" + +#if defined(WITH_LUA) +#include "msc_lua.h" +#endif + +/* Actions, variables, functions and operator functions */ + +apr_status_t DSOLOCAL collection_original_setvar(modsec_rec *msr, const char *col_name, const msc_string *orig_var); + +int DSOLOCAL expand_macros(modsec_rec *msr, msc_string *var, msre_rule *rule, apr_pool_t *mptmp); + +apr_status_t DSOLOCAL msre_parse_targets(msre_ruleset *ruleset, const char *text, + apr_array_header_t *arr, char **error_msg); + +apr_status_t DSOLOCAL msre_parse_actions(msre_engine *engine, msre_actionset *actionset, + const char *text, char **error_msg); + +msre_var_metadata DSOLOCAL *msre_resolve_var(msre_engine *engine, const char *name); + +msre_action_metadata DSOLOCAL *msre_resolve_action(msre_engine *engine, const char *name); + +msre_var DSOLOCAL *msre_create_var(msre_ruleset *ruleset, const char *name, const char *param, + modsec_rec *msr, char **error_msg); + +msre_var DSOLOCAL *msre_create_var_ex(apr_pool_t *pool, msre_engine *engine, const char *name, const char *param, + modsec_rec *msr, char **error_msg); + +msre_action DSOLOCAL *msre_create_action(msre_engine *engine, const char *name, + const char *param, char **error_msg); + +int DSOLOCAL msre_parse_generic(apr_pool_t *pool, const char *text, apr_table_t *vartable, + char **error_msg); + +int DSOLOCAL rule_id_in_range(int ruleid, const char *range); + +msre_var DSOLOCAL *generate_single_var(modsec_rec *msr, msre_var *var, apr_array_header_t *tfn_arr, + msre_rule *rule, apr_pool_t *mptmp); + +apr_table_t DSOLOCAL *generate_multi_var(modsec_rec *msr, msre_var *var, apr_array_header_t *tfn_arr, + msre_rule *rule, apr_pool_t *mptmp); + +/* Structures with the corresponding functions */ + +struct msre_engine { + apr_pool_t *mp; + apr_table_t *variables; + apr_table_t *operators; + apr_table_t *actions; + apr_table_t *tfns; +}; + +msre_engine DSOLOCAL *msre_engine_create(apr_pool_t *parent_pool); + +void DSOLOCAL msre_engine_destroy(msre_engine *engine); + +msre_op_metadata DSOLOCAL *msre_engine_op_resolve(msre_engine *engine, const char *name); + +struct msre_ruleset { + apr_pool_t *mp; + msre_engine *engine; + + apr_array_header_t *phase_request_headers; + apr_array_header_t *phase_request_body; + apr_array_header_t *phase_response_headers; + apr_array_header_t *phase_response_body; + apr_array_header_t *phase_logging; +}; + +apr_status_t DSOLOCAL msre_ruleset_process_phase(msre_ruleset *ruleset, modsec_rec *msr); + +apr_status_t DSOLOCAL msre_ruleset_process_phase_internal(msre_ruleset *ruleset, modsec_rec *msr); + +msre_ruleset DSOLOCAL *msre_ruleset_create(msre_engine *engine, apr_pool_t *mp); + +int DSOLOCAL msre_ruleset_rule_add(msre_ruleset *ruleset, msre_rule *rule, int phase); + +msre_rule DSOLOCAL *msre_ruleset_fetch_rule(msre_ruleset *ruleset, const char *id); + +int DSOLOCAL msre_ruleset_rule_remove_with_exception(msre_ruleset *ruleset, rule_exception *re); + +/* +int DSOLOCAL msre_ruleset_phase_rule_remove_with_exception(msre_ruleset *ruleset, rule_exception *re, + apr_array_header_t *phase_arr); +*/ + +#define RULE_NO_MATCH 0 +#define RULE_MATCH 1 + +#define RULE_PH_NONE 0 /* Not a placeholder */ +#define RULE_PH_SKIPAFTER 1 /* Implicit placeholder for skipAfter */ +#define RULE_PH_MARKER 2 /* Explicit placeholder for SecMarker */ + +#define RULE_TYPE_NORMAL 0 /* SecRule */ +#define RULE_TYPE_ACTION 1 /* SecAction */ +#define RULE_TYPE_MARKER 2 /* SecMarker */ +#if defined(WITH_LUA) +#define RULE_TYPE_LUA 3 /* SecRuleScript */ +#endif + +struct msre_rule { + apr_array_header_t *targets; + const char *op_name; + const char *op_param; + void *op_param_data; + msre_op_metadata *op_metadata; + unsigned int op_negated; + msre_actionset *actionset; + const char *p1; + const char *unparsed; + const char *filename; + int line_num; + int placeholder; + int type; + + msre_ruleset *ruleset; + msre_rule *chain_starter; + #if defined(PERFORMANCE_MEASUREMENT) + unsigned int execution_time; + unsigned int trans_time; + unsigned int op_time; + #endif + + #if defined(WITH_LUA) + /* Compiled Lua script. */ + msc_script *script; + #endif +}; + +char DSOLOCAL *msre_rule_generate_unparsed(apr_pool_t *pool, const msre_rule *rule, const char *targets, const char *args, const char *actions); + +msre_rule DSOLOCAL *msre_rule_create(msre_ruleset *ruleset, int type, + const char *fn, int line, const char *targets, + const char *args, const char *actions, char **error_msg); + +#if defined(WITH_LUA) +msre_rule DSOLOCAL *msre_rule_lua_create(msre_ruleset *ruleset, + const char *fn, int line, const char *script_filename, + const char *actions, char **error_msg); +#endif + +apr_status_t DSOLOCAL msre_rule_process(msre_rule *rule, modsec_rec *msr); + +#define VAR_SIMPLE 0 /* REQUEST_URI */ +#define VAR_LIST 1 + +#define PHASE_REQUEST_HEADERS 1 +#define PHASE_REQUEST_BODY 2 +#define PHASE_RESPONSE_HEADERS 3 +#define PHASE_RESPONSE_BODY 4 +#define PHASE_LOGGING 5 + +typedef int (*fn_op_param_init_t)(msre_rule *rule, char **error_msg); +typedef int (*fn_op_execute_t)(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg); + +struct msre_op_metadata { + const char *name; + fn_op_param_init_t param_init; + fn_op_execute_t execute; +}; + +typedef int (*fn_tfn_execute_t)(apr_pool_t *pool, unsigned char *input, long int input_length, char **rval, long int *rval_length); + +struct msre_tfn_metadata { + const char *name; + + /* Functions should populate *rval and return 1 on + * success, or return -1 on failure (in which case *rval + * should contain the error message. Strict functions + * (those that validate in + * addition to transforming) can return 0 when input + * fails validation. Functions are free to perform + * in-place transformation, or to allocate a new buffer + * from the provideded temporary (per-rule) memory pool. + * + * NOTE Strict transformation functions not supported yet. + */ + fn_tfn_execute_t execute; +}; + +void DSOLOCAL msre_engine_tfn_register(msre_engine *engine, const char *name, + fn_tfn_execute_t execute); + +void DSOLOCAL msre_engine_op_register(msre_engine *engine, const char *name, + fn_op_param_init_t fn1, fn_op_execute_t fn2); + +void DSOLOCAL msre_engine_register_default_tfns(msre_engine *engine); + +void DSOLOCAL msre_engine_register_default_variables(msre_engine *engine); + +void DSOLOCAL msre_engine_register_default_operators(msre_engine *engine); + +void DSOLOCAL msre_engine_register_default_actions(msre_engine *engine); + +msre_tfn_metadata DSOLOCAL *msre_engine_tfn_resolve(msre_engine *engine, const char *name); + +#define VAR_DONT_CACHE 0 +#define VAR_CACHE 1 + +typedef char *(*fn_var_validate_t)(msre_ruleset *ruleset, msre_var *var); +typedef int (*fn_var_generate_t)(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *table, apr_pool_t *mptmp); + +struct msre_var_metadata { + const char *name; + unsigned int type; /* VAR_TYPE_ constants */ + unsigned int argc_min; + unsigned int argc_max; + fn_var_validate_t validate; + fn_var_generate_t generate; + unsigned int is_cacheable; /* 0 - no, 1 - yes */ + unsigned int availability; /* when does this variable become available? */ +}; + +struct msre_var { + const char *name; + const char *value; + unsigned int value_len; + const char *param; + const void *param_data; + msre_var_metadata *metadata; + msc_regex_t *param_regex; + unsigned int is_negated; + unsigned int is_counting; +}; + + +struct msre_actionset { + apr_table_t *actions; + + /* Metadata */ + const char *id; + const char *rev; + const char *msg; + const char *logdata; + int severity; + int phase; + msre_rule *rule; + + /* Flow */ + int is_chained; + int skip_count; + const char *skip_after; + + /* Disruptive */ + int intercept_action; + const char *intercept_uri; + int intercept_status; + int intercept_pause; + + /* "block" needs parent action to reset it */ + msre_action *parent_intercept_action_rec; + msre_action *intercept_action_rec; + int parent_intercept_action; + + /* Other */ + int log; + int auditlog; + int block; +}; + +char DSOLOCAL *msre_actionset_generate_action_string(apr_pool_t *pool, const msre_actionset *actionset); + +void DSOLOCAL msre_engine_variable_register(msre_engine *engine, const char *name, + unsigned int type, unsigned int argc_min, unsigned int argc_max, + fn_var_validate_t validate, fn_var_generate_t generate, + unsigned int is_cacheable, unsigned int availability); + +msre_actionset DSOLOCAL *msre_actionset_create(msre_engine *engine, const char *text, + char **error_msg); + +msre_actionset DSOLOCAL *msre_actionset_merge(msre_engine *engine, msre_actionset *parent, + msre_actionset *child, int inherit_by_default); + +msre_actionset DSOLOCAL *msre_actionset_create_default(msre_engine *engine); + +void DSOLOCAL msre_actionset_set_defaults(msre_actionset *actionset); + +void DSOLOCAL msre_actionset_init(msre_actionset *actionset, msre_rule *rule); + +typedef char *(*fn_action_validate_t)(msre_engine *engine, msre_action *action); +typedef apr_status_t (*fn_action_init_t)(msre_engine *engine, msre_actionset *actionset, msre_action *action); +typedef apr_status_t (*fn_action_execute_t)(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, msre_action *action); + +#define ACTION_DISRUPTIVE 1 +#define ACTION_NON_DISRUPTIVE 2 +#define ACTION_METADATA 3 +#define ACTION_FLOW 4 + +#define NO_PLUS_MINUS 0 +#define ALLOW_PLUS_MINUS 1 + +#define ACTION_CARDINALITY_ONE 1 +#define ACTION_CARDINALITY_MANY 2 + +#define ACTION_CGROUP_NONE 0 +#define ACTION_CGROUP_DISRUPTIVE 1 +#define ACTION_CGROUP_LOG 2 +#define ACTION_CGROUP_AUDITLOG 3 + +struct msre_action_metadata { + const char *name; + unsigned int type; + unsigned int argc_min; + unsigned int argc_max; + unsigned int allow_param_plusminus; + unsigned int cardinality; + unsigned int cardinality_group; + fn_action_validate_t validate; + fn_action_init_t init; + fn_action_execute_t execute; +}; + +struct msre_action { + msre_action_metadata *metadata; + const char *param; + const void *param_data; + unsigned int param_plusminus; /* ABSOLUTE_VALUE, POSITIVE_VALUE, NEGATIVE_VALUE */ +}; + +/* -- MSRE Function Prototypes ---------------------------------------------- */ + +msre_var_metadata DSOLOCAL *msre_resolve_var(msre_engine *engine, const char *name); + +int DSOLOCAL msre_parse_generic(apr_pool_t *pool, const char *text, apr_table_t *vartable, + char **error_msg); + +apr_status_t DSOLOCAL msre_parse_vars(msre_ruleset *ruleset, const char *text, + apr_array_header_t *arr, char **error_msg); + +char DSOLOCAL *msre_format_metadata(modsec_rec *msr, msre_actionset *actionset); + + +/* -- Data Cache -- */ + +struct msre_cache_rec { + int hits; + int changed; + int num; + const char *path; + const char *val; + apr_size_t val_len; +}; + +#endif diff --git a/apache2/re_actions.c b/apache2/re_actions.c new file mode 100644 index 0000000..e6de329 --- /dev/null +++ b/apache2/re_actions.c @@ -0,0 +1,2400 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2008 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ +#include "re.h" +#include + +/** + * Register action with the engine. + */ +static void msre_engine_action_register(msre_engine *engine, const char *name, + unsigned int type, unsigned int argc_min, unsigned int argc_max, + unsigned int allow_param_plusminus, unsigned int cardinality, + unsigned int cardinality_group, fn_action_validate_t validate, + fn_action_init_t init, fn_action_execute_t execute) +{ + msre_action_metadata *metadata = (msre_action_metadata *)apr_pcalloc(engine->mp, + sizeof(msre_action_metadata)); + if (metadata == NULL) return; + + metadata->name = name; + metadata->type = type; + metadata->argc_min = argc_min; + metadata->argc_max = argc_max; + metadata->allow_param_plusminus = allow_param_plusminus; + metadata->cardinality = cardinality; + metadata->cardinality_group = cardinality_group; + metadata->validate = validate; + metadata->init = init; + metadata->execute = execute; + + apr_table_setn(engine->actions, name, (void *)metadata); +} + +/** + * Generates a single variable (from the supplied metadata). + */ +msre_var *generate_single_var(modsec_rec *msr, msre_var *var, apr_array_header_t *tfn_arr, + msre_rule *rule, apr_pool_t *mptmp) +{ + apr_table_t *vartab = NULL; + const apr_table_entry_t *te = NULL; + const apr_array_header_t *arr = NULL; + msre_var *rvar = NULL; + int i; + + /* Sanity check. */ + if ((var == NULL)||(var->metadata == NULL)||(var->metadata->generate == NULL)) return NULL; + + vartab = apr_table_make(mptmp, 16); + var->metadata->generate(msr, var, rule, vartab, mptmp); + + arr = apr_table_elts(vartab); + if (arr->nelts == 0) return NULL; + te = (apr_table_entry_t *)arr->elts; + + rvar = (msre_var *)te[0].val; + + /* Return straight away if there were no + * transformation functions supplied. + */ + if ((tfn_arr == NULL)||(tfn_arr->nelts == 0)) { + return rvar; + } + + /* Copy the value so that we can transform it in place. */ + rvar->value = apr_pstrndup(mptmp, rvar->value, rvar->value_len); + + /* Transform rvar in a loop. */ + for (i = 0; i < tfn_arr->nelts; i++) { + msre_tfn_metadata *tfn = ((msre_tfn_metadata **)tfn_arr->elts)[i]; + char *rval; + int rc; + long int rval_len; + + rc = tfn->execute(mptmp, (unsigned char *)rvar->value, + rvar->value_len, &rval, &rval_len); + + rvar->value = rval; + rvar->value_len = rval_len; + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "T (%d) %s: \"%s\"", rc, tfn->name, + log_escape_nq_ex(mptmp, rvar->value, rvar->value_len)); + } + } + + return rvar; +} + +/** + * + */ +apr_table_t *generate_multi_var(modsec_rec *msr, msre_var *var, apr_array_header_t *tfn_arr, + msre_rule *rule, apr_pool_t *mptmp) +{ + const apr_array_header_t *tarr; + const apr_table_entry_t *telts; + apr_table_t *vartab = NULL, *tvartab = NULL; + msre_var *rvar = NULL; + int i, j; + + /* Sanity check. */ + if ((var == NULL)||(var->metadata == NULL)||(var->metadata->generate == NULL)) return NULL; + + /* Generate variables. */ + vartab = apr_table_make(mptmp, 16); + var->metadata->generate(msr, var, rule, vartab, mptmp); + + /* Return straight away if there were no + * transformation functions supplied. + */ + if ((tfn_arr == NULL)||(tfn_arr->nelts == 0)) { + return vartab; + } + + tvartab = apr_table_make(mptmp, 16); + + tarr = apr_table_elts(vartab); + telts = (const apr_table_entry_t*)tarr->elts; + for (j = 0; j < tarr->nelts; j++) { + rvar = (msre_var *)telts[j].val; + + /* Copy the value so that we can transform it in place. */ + rvar->value = apr_pstrndup(mptmp, rvar->value, rvar->value_len); + + /* Transform rvar in a loop. */ + for (i = 0; i < tfn_arr->nelts; i++) { + msre_tfn_metadata *tfn = ((msre_tfn_metadata **)tfn_arr->elts)[i]; + char *rval; + int rc; + long int rval_len; + + rc = tfn->execute(mptmp, (unsigned char *)rvar->value, + rvar->value_len, &rval, &rval_len); + + rvar->value = rval; + rvar->value_len = rval_len; + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "T (%d) %s: \"%s\"", rc, tfn->name, + log_escape_nq_ex(mptmp, rvar->value, rvar->value_len)); + } + } + + apr_table_addn(tvartab, rvar->name, (void *)rvar); + } + + return tvartab; +} + +/** + * Expands macros ("%{NAME}" entities) if present + * in the given variable. + */ +int expand_macros(modsec_rec *msr, msc_string *var, msre_rule *rule, apr_pool_t *mptmp) { + char *data = NULL; + apr_array_header_t *arr = NULL; + char *p = NULL, *q = NULL, *t = NULL; + char *text_start = NULL, *next_text_start = NULL; + msc_string *part = NULL; + int i, offset = 0; + + if (var->value == NULL) return 0; + + /* IMP1 Duplicate the string and create the array on + * demand, thus not having to do it if there are + * no macros in the input data. + */ + + data = apr_pstrdup(mptmp, var->value); /* IMP1 Are we modifying data anywhere? */ + arr = apr_array_make(mptmp, 16, sizeof(msc_string *)); + if ((data == NULL)||(arr == NULL)) return -1; + + text_start = next_text_start = data; + do { + text_start = next_text_start; + p = strstr(text_start, "%"); + if (p != NULL) { + char *var_name = NULL; + char *var_value = NULL; + + if ((*(p + 1) == '{')&&(*(p + 2) != '\0')) { + char *var_start = p + 2; + + t = var_start; + while((*t != '\0')&&(*t != '}')) t++; + if (*t == '}') { + /* Named variable. */ + + var_name = apr_pstrmemdup(mptmp, var_start, t - var_start); + q = strstr(var_name, "."); + if (q != NULL) { + var_value = q + 1; + *q = '\0'; + } + + next_text_start = t + 1; /* *t was '}' */ + } else { + /* Warn about a possiblly forgotten '}' */ + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Warning: Possibly unterminated macro: \"%s\"", + log_escape_ex(mptmp, var_start - 2, t - var_start + 2)); + } + + next_text_start = t; /* *t was '\0' */ + } + } + + if (var_name != NULL) { + char *my_error_msg = NULL; + msre_var *var_generated = NULL; + msre_var *var_resolved = NULL; + + /* Add the text part before the macro to the array. */ + part = (msc_string *)apr_pcalloc(mptmp, sizeof(msc_string)); + if (part == NULL) return -1; + part->value_len = p - text_start; + part->value = apr_pstrmemdup(mptmp, text_start, part->value_len); + *(msc_string **)apr_array_push(arr) = part; + + /* Resolve the macro and add that to the array. */ + var_resolved = msre_create_var_ex(mptmp, msr->modsecurity->msre, var_name, var_value, + msr, &my_error_msg); + if (var_resolved != NULL) { + var_generated = generate_single_var(msr, var_resolved, NULL, rule, mptmp); + if (var_generated != NULL) { + part = (msc_string *)apr_pcalloc(mptmp, sizeof(msc_string)); + if (part == NULL) return -1; + part->value_len = var_generated->value_len; + part->value = (char *)var_generated->value; + *(msc_string **)apr_array_push(arr) = part; + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Resolved macro %%{%s%s%s} to \"%s\"", + var_name, + (var_value ? "." : ""), + (var_value ? var_value : ""), + log_escape_ex(mptmp, part->value, part->value_len)); + } + } + } else { + msr_log(msr, 4, "Failed to resolve macro %%{%s%s%s}: %s", + var_name, + (var_value ? "." : ""), + (var_value ? var_value : ""), + my_error_msg); + } + } else { + /* We could not identify a valid macro so add it as text. */ + part = (msc_string *)apr_pcalloc(mptmp, sizeof(msc_string)); + if (part == NULL) return -1; + part->value_len = p - text_start + 1; /* len(text)+len("%") */ + part->value = apr_pstrmemdup(mptmp, text_start, part->value_len); + *(msc_string **)apr_array_push(arr) = part; + + next_text_start = p + 1; + } + } else { + /* Text part. */ + part = (msc_string *)apr_pcalloc(mptmp, sizeof(msc_string)); + part->value = apr_pstrdup(mptmp, text_start); + part->value_len = strlen(part->value); + *(msc_string **)apr_array_push(arr) = part; + } + } while (p != NULL); + + /* If there's more than one member of the array that + * means there was at least one macro present. Combine + * text parts into a single string now. + */ + if (arr->nelts > 1) { + /* Figure out the required size for the string. */ + var->value_len = 0; + for(i = 0; i < arr->nelts; i++) { + part = ((msc_string **)arr->elts)[i]; + var->value_len += part->value_len; + } + + /* Allocate the string. */ + var->value = apr_palloc(msr->mp, var->value_len + 1); + if (var->value == NULL) return -1; + + /* Combine the parts. */ + offset = 0; + for(i = 0; i < arr->nelts; i++) { + part = ((msc_string **)arr->elts)[i]; + memcpy((char *)(var->value + offset), part->value, part->value_len); + offset += part->value_len; + } + var->value[offset] = '\0'; + } + + return 1; +} + +/** + * Record the original collection values to use to calculate deltas. + * This can be called multiple times and will not overwrite the first + * value that is set. + */ +apr_status_t collection_original_setvar(modsec_rec *msr, const char *col_name, const msc_string *orig_var) { + apr_table_t *table = NULL; + msc_string *var = NULL; + const char *var_name = NULL; + + if (orig_var == NULL) { + msr_log(msr, 1, "Internal Error: Attempt to record NULL original variable."); + return -1; + } + + var_name = orig_var->name; + table = (apr_table_t *)apr_table_get(msr->collections_original, col_name); + + /* Does the collection exist already? */ + if (table == NULL) { + table = apr_table_make(msr->mp, 24); + if (table == NULL) { + msr_log(msr, 1, "Failed to allocate space for original collection."); + return -1; + } + apr_table_setn(msr->collections_original, apr_pstrdup(msr->mp, col_name), (void *)table); + } + else { + /* Does the variable exist already? */ + var = (msc_string *)apr_table_get(table, var_name); + if (var != NULL) { + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Original collection variable: %s.%s = \"%s\"", col_name, var_name, log_escape_ex(msr->mp, orig_var->value, orig_var->value_len)); + } + return 1; + } + } + + var = (msc_string *)apr_palloc(msr->mp, sizeof(msc_string)); + if (var == NULL) { + msr_log(msr, 1, "Failed to allocate space for original collection variable."); + return -1; + } + + /* Copy the original var and add to collection. */ + var->name = orig_var->name ? apr_pstrmemdup(msr->mp, orig_var->name, orig_var->name_len) : NULL; + var->name_len = orig_var->name_len; + var->value = orig_var->value ? apr_pstrmemdup(msr->mp, orig_var->value, orig_var->value_len) : NULL; + var->value_len = orig_var->value_len; + apr_table_setn(table, apr_pstrmemdup(msr->mp, var->name, var->name_len), (void *)var); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Recorded original collection variable: %s.%s = \"%s\"", col_name, var_name, log_escape_ex(msr->mp, var->value, var->value_len)); + } + + return 0; +} + +/* id */ + +static apr_status_t msre_action_id_init(msre_engine *engine, msre_actionset *actionset, + msre_action *action) +{ + actionset->id = action->param; + return 1; +} + +/* rev */ + +static apr_status_t msre_action_rev_init(msre_engine *engine, msre_actionset *actionset, + msre_action *action) +{ + actionset->rev = action->param; + return 1; +} + +/* msg */ + +static apr_status_t msre_action_msg_init(msre_engine *engine, msre_actionset *actionset, + msre_action *action) +{ + actionset->msg = action->param; + return 1; +} + +/* logdata */ + +static apr_status_t msre_action_logdata_init(msre_engine *engine, msre_actionset *actionset, + msre_action *action) +{ + actionset->logdata = action->param; + return 1; +} + +/* severity */ + +static apr_status_t msre_action_severity_init(msre_engine *engine, + msre_actionset *actionset, msre_action *action) +{ + actionset->severity = atoi(action->param); + return 1; +} + +/* chain */ + +static apr_status_t msre_action_chain_init(msre_engine *engine, msre_actionset *actionset, + msre_action *action) +{ + actionset->is_chained = 1; + return 1; +} + +/* log */ +static apr_status_t msre_action_log_init(msre_engine *engine, msre_actionset *actionset, + msre_action *action) +{ + actionset->log = 1; + return 1; +} + +/* nolog */ +static apr_status_t msre_action_nolog_init(msre_engine *engine, msre_actionset *actionset, + msre_action *action) +{ + actionset->log = 0; + actionset->auditlog = 0; + return 1; +} + +/* auditlog */ +static apr_status_t msre_action_auditlog_init(msre_engine *engine, msre_actionset *actionset, + msre_action *action) +{ + actionset->auditlog = 1; + return 1; +} + +/* noauditlog */ +static apr_status_t msre_action_noauditlog_init(msre_engine *engine, msre_actionset *actionset, + msre_action *action) +{ + actionset->auditlog = 0; + return 1; +} + +/* block */ +static apr_status_t msre_action_block_init(msre_engine *engine, msre_actionset *actionset, + msre_action *action) +{ + /* Right now we just set a flag and inherit the real disruptive action */ + actionset->block = 1; + return 1; +} + +/* deny */ +static apr_status_t msre_action_deny_init(msre_engine *engine, msre_actionset *actionset, + msre_action *action) +{ + actionset->intercept_action = ACTION_DENY; + actionset->intercept_action_rec = action; + return 1; +} + +/* status */ +static char *msre_action_status_validate(msre_engine *engine, msre_action *action) { + /* ENH action->param must be a valid HTTP status code. */ + return NULL; +} + +static apr_status_t msre_action_status_init(msre_engine *engine, msre_actionset *actionset, + msre_action *action) +{ + actionset->intercept_status = atoi(action->param); + return 1; +} + +/* drop */ +static apr_status_t msre_action_drop_init(msre_engine *engine, msre_actionset *actionset, + msre_action *action) +{ + actionset->intercept_action = ACTION_DROP; + actionset->intercept_action_rec = action; + return 1; +} + +/* pause */ +static char *msre_action_pause_validate(msre_engine *engine, msre_action *action) { + /* ENH Validate a positive number. */ + return NULL; +} + +static apr_status_t msre_action_pause_init(msre_engine *engine, msre_actionset *actionset, + msre_action *action) +{ + actionset->intercept_pause = atoi(action->param); + return 1; +} + +/* redirect */ + +static char *msre_action_redirect_validate(msre_engine *engine, msre_action *action) { + /* ENH Add validation. */ + return NULL; +} + +static apr_status_t msre_action_redirect_init(msre_engine *engine, msre_actionset *actionset, + msre_action *action) +{ + actionset->intercept_action = ACTION_REDIRECT; + actionset->intercept_uri = action->param; + actionset->intercept_action_rec = action; + return 1; +} + +static apr_status_t msre_action_redirect_execute(modsec_rec *msr, apr_pool_t *mptmp, + msre_rule *rule, msre_action *action) +{ + msc_string *var = NULL; + + var = apr_pcalloc(mptmp, sizeof(msc_string)); + if (var == NULL) return -1; + var->value = (char *)action->param; + var->value_len = strlen(var->value); + expand_macros(msr, var, rule, mptmp); + + rule->actionset->intercept_uri = apr_pstrmemdup(msr->mp, var->value, var->value_len); + + return 1; +} + +/* proxy */ + +static char *msre_action_proxy_validate(msre_engine *engine, msre_action *action) { + /* ENH Add validation. */ + return NULL; +} + +static apr_status_t msre_action_proxy_init(msre_engine *engine, msre_actionset *actionset, + msre_action *action) +{ + actionset->intercept_action = ACTION_PROXY; + actionset->intercept_uri = action->param; + actionset->intercept_action_rec = action; + return 1; +} + +static apr_status_t msre_action_proxy_execute(modsec_rec *msr, apr_pool_t *mptmp, + msre_rule *rule, msre_action *action) +{ + msc_string *var = NULL; + + var = apr_pcalloc(mptmp, sizeof(msc_string)); + if (var == NULL) return -1; + var->value = (char *)action->param; + var->value_len = strlen(var->value); + expand_macros(msr, var, rule, mptmp); + + rule->actionset->intercept_uri = apr_pstrmemdup(msr->mp, var->value, var->value_len); + + return 1; +} + +/* pass */ + +static apr_status_t msre_action_pass_init(msre_engine *engine, msre_actionset *actionset, + msre_action *action) +{ + actionset->intercept_action = ACTION_NONE; + actionset->intercept_action_rec = action; + return 1; +} + +/* skip */ + +static char *msre_action_skip_validate(msre_engine *engine, msre_action *action) { + /* ENH Add validation. */ + return NULL; +} + +static apr_status_t msre_action_skip_init(msre_engine *engine, msre_actionset *actionset, + msre_action *action) +{ + actionset->skip_count = atoi(action->param); + if (actionset->skip_count <= 0) actionset->skip_count = 1; + return 1; +} + +/* skipAfter */ + +static char *msre_action_skipAfter_validate(msre_engine *engine, msre_action *action) { + /* ENH Add validation. */ + return NULL; +} + +static apr_status_t msre_action_skipAfter_init(msre_engine *engine, msre_actionset *actionset, + msre_action *action) +{ + actionset->skip_after = action->param; + return 1; +} + +/* allow */ + +static apr_status_t msre_action_allow_init(msre_engine *engine, msre_actionset *actionset, + msre_action *action) +{ + actionset->intercept_action = ACTION_ALLOW; + actionset->intercept_action_rec = action; + + if (action->param != NULL) { + if (strcasecmp(action->param, "phase") == 0) { + actionset->intercept_action = ACTION_ALLOW_PHASE; + } else + if (strcasecmp(action->param, "request") == 0) { + actionset->intercept_action = ACTION_ALLOW_REQUEST; + } + } + + return 1; +} + +static char *msre_action_allow_validate(msre_engine *engine, msre_action *action) { + if (action->param != NULL) { + if (strcasecmp(action->param, "phase") == 0) { + return NULL; + } else + if (strcasecmp(action->param, "request") == 0) { + return NULL; + } else { + return apr_psprintf(engine->mp, "Invalid parameter for allow: %s", action->param); + } + } + + return NULL; +} + +/* phase */ + +static char *msre_action_phase_validate(msre_engine *engine, msre_action *action) { + /* ENH Add validation. */ + return NULL; +} + +static apr_status_t msre_action_phase_init(msre_engine *engine, msre_actionset *actionset, + msre_action *action) +{ + actionset->phase = atoi(action->param); + return 1; +} + +/* t */ + +static char *msre_action_t_validate(msre_engine *engine, msre_action *action) { + msre_tfn_metadata *metadata = NULL; + metadata = msre_engine_tfn_resolve(engine, action->param); + if (metadata == NULL) return apr_psprintf(engine->mp, "Invalid transformation function: %s", + action->param); + action->param_data = metadata; + return NULL; +} + +static apr_status_t msre_action_t_init(msre_engine *engine, msre_actionset *actionset, + msre_action *action) +{ + msre_tfn_metadata *metadata = (msre_tfn_metadata *)action->param_data; + action->param_data = metadata; + return 1; +} + +/* ctl */ +static char *msre_action_ctl_validate(msre_engine *engine, msre_action *action) { + char *name = NULL; + char *value = NULL; + + /* Parse first. */ + if (parse_name_eq_value(engine->mp, action->param, &name, &value) < 0) { + return FATAL_ERROR; + } + if (value == NULL) { + return apr_psprintf(engine->mp, "Missing ctl value for name: %s", name); + } + + /* Validate value. */ + if (strcasecmp(name, "ruleEngine") == 0) { + if (strcasecmp(value, "on") == 0) return NULL; + if (strcasecmp(value, "off") == 0) return NULL; + if (strcasecmp(value, "detectiononly") == 0) return NULL; + return apr_psprintf(engine->mp, "Invalid setting for ctl name ruleEngine: %s", value); + } else + if (strcasecmp(name, "ruleRemoveById") == 0) { + /* ENH nothing yet */ + return NULL; + } else + if (strcasecmp(name, "requestBodyAccess") == 0) { + if (parse_boolean(value) == -1) { + return apr_psprintf(engine->mp, "Invalid setting for ctl name " + " requestBodyAccess: %s", value); + } + return NULL; + } else + if (strcasecmp(name, "requestBodyProcessor") == 0) { + /* ENH We will accept anything for now but it'd be nice + * to add a check here that the processor name is a valid one. + */ + return NULL; + } else + if (strcasecmp(name, "forceRequestBodyVariable") == 0) { + if (strcasecmp(value, "on") == 0) return NULL; + if (strcasecmp(value, "off") == 0) return NULL; + return apr_psprintf(engine->mp, "Invalid setting for ctl name " + " forceRequestBodyVariable: %s", value); + } else + if (strcasecmp(name, "responseBodyAccess") == 0) { + if (parse_boolean(value) == -1) { + return apr_psprintf(engine->mp, "Invalid setting for ctl name " + " responseBodyAccess: %s", value); + } + return NULL; + } else + if (strcasecmp(name, "auditEngine") == 0) { + if (strcasecmp(value, "on") == 0) return NULL; + if (strcasecmp(value, "off") == 0) return NULL; + if (strcasecmp(value, "relevantonly") == 0) return NULL; + return apr_psprintf(engine->mp, "Invalid setting for ctl name " + " auditEngine: %s", value); + } else + if (strcasecmp(name, "auditLogParts") == 0) { + if ((value[0] == '+')||(value[0] == '-')) { + if (is_valid_parts_specification(value + 1) != 1) { + return apr_psprintf(engine->mp, "Invalid setting for ctl name " + "auditLogParts: %s", value); + } + } + else + if (is_valid_parts_specification(value) != 1) { + return apr_psprintf(engine->mp, "Invalid setting for ctl name " + "auditLogParts: %s", value); + } + return NULL; + } else + if (strcasecmp(name, "debugLogLevel") == 0) { + if ((atoi(value) >= 0)&&(atoi(value) <= 9)) return NULL; + return apr_psprintf(engine->mp, "Invalid setting for ctl name " + "debugLogLevel: %s", value); + } else + if (strcasecmp(name, "requestBodyLimit") == 0) { + long int limit = strtol(value, NULL, 10); + + if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) { + return apr_psprintf(engine->mp, "Invalid setting for ctl name " + "requestBodyLimit: %s", value); + } + + if (limit > REQUEST_BODY_HARD_LIMIT) { + return apr_psprintf(engine->mp, "Request size limit cannot exceed " + "the hard limit: %ld", RESPONSE_BODY_HARD_LIMIT); + } + + return NULL; + } else + if (strcasecmp(name, "responseBodyLimit") == 0) { + long int limit = strtol(value, NULL, 10); + + if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) { + return apr_psprintf(engine->mp, "Invalid setting for ctl name " + "responseBodyLimit: %s", value); + } + + if (limit > RESPONSE_BODY_HARD_LIMIT) { + return apr_psprintf(engine->mp, "Response size limit cannot exceed " + "the hard limit: %ld", RESPONSE_BODY_HARD_LIMIT); + } + + return NULL; + } + else { + return apr_psprintf(engine->mp, "Invalid ctl name setting: %s", name); + } +} + +static apr_status_t msre_action_ctl_init(msre_engine *engine, msre_actionset *actionset, + msre_action *action) +{ + /* Do nothing. */ + return 1; +} + +static apr_status_t msre_action_ctl_execute(modsec_rec *msr, apr_pool_t *mptmp, + msre_rule *rule, msre_action *action) +{ + char *name = NULL; + char *value = NULL; + + /* Parse first. */ + if (parse_name_eq_value(msr->mp, action->param, &name, &value) < 0) return -1; + if (value == NULL) return -1; + + /* Validate value. */ + if (strcasecmp(name, "ruleEngine") == 0) { + if (strcasecmp(value, "on") == 0) { + msr->txcfg->is_enabled = MODSEC_ENABLED; + msr->usercfg->is_enabled = MODSEC_ENABLED; + } + else + if (strcasecmp(value, "off") == 0) { + msr->txcfg->is_enabled = MODSEC_DISABLED; + msr->usercfg->is_enabled = MODSEC_DISABLED; + } + else + if (strcasecmp(value, "detectiononly") == 0) { + msr->txcfg->is_enabled = MODSEC_DETECTION_ONLY; + msr->usercfg->is_enabled = MODSEC_DETECTION_ONLY; + } + + return 1; + } else + if (strcasecmp(name, "ruleRemoveById") == 0) { + *(const char **)apr_array_push(msr->removed_rules) = (const char *)apr_pstrdup(msr->mp, value); + return 1; + } else + if (strcasecmp(name, "requestBodyAccess") == 0) { + int pv = parse_boolean(value); + + if (pv == -1) return -1; + msr->txcfg->reqbody_access = pv; + msr->usercfg->reqbody_access = pv; + msr_log(msr, 4, "Ctl: Set requestBodyAccess to %d.", pv); + + return 1; + } else + if (strcasecmp(name, "forceRequestBodyVariable") == 0) { + if (strcasecmp(value, "on") == 0) { + msr->txcfg->reqbody_buffering = REQUEST_BODY_FORCEBUF_ON; + msr->usercfg->reqbody_buffering = REQUEST_BODY_FORCEBUF_ON; + } + else + if (strcasecmp(value, "off") == 0) { + msr->txcfg->reqbody_buffering = REQUEST_BODY_FORCEBUF_OFF; + msr->usercfg->reqbody_buffering = REQUEST_BODY_FORCEBUF_OFF; + } + + msr_log(msr, 4, "Ctl: Set requestBodyAccess to %d.", msr->txcfg->reqbody_buffering); + + return 1; + } else + if (strcasecmp(name, "requestBodyProcessor") == 0) { + msr->msc_reqbody_processor = value; + msr_log(msr, 4, "Ctl: Set requestBodyProcessor to %s.", value); + + return 1; + } else + if (strcasecmp(name, "responseBodyAccess") == 0) { + int pv = parse_boolean(value); + + if (pv == -1) return -1; + msr->txcfg->resbody_access = pv; + msr->usercfg->resbody_access = pv; + msr_log(msr, 4, "Ctl: Set responseBodyAccess to %d.", pv); + + return 1; + } else + if (strcasecmp(name, "auditEngine") == 0) { + if (strcasecmp(value, "on") == 0) { + msr->txcfg->auditlog_flag = AUDITLOG_ON; + msr->usercfg->auditlog_flag = AUDITLOG_ON; + } + else + if (strcasecmp(value, "off") == 0) { + msr->txcfg->auditlog_flag = AUDITLOG_OFF; + msr->usercfg->auditlog_flag = AUDITLOG_OFF; + } + else + if (strcasecmp(value, "relevantonly") == 0) { + msr->txcfg->auditlog_flag = AUDITLOG_RELEVANT; + msr->usercfg->auditlog_flag = AUDITLOG_RELEVANT; + } + + msr_log(msr, 4, "Ctl: Set auditEngine to %d.", msr->txcfg->auditlog_flag); + + return 1; + } else + if (strcasecmp(name, "auditLogParts") == 0) { + char *new_value = value; + + if (value[0] == '+') { + /* Add the listed parts. */ + new_value = apr_pstrcat(msr->mp, msr->txcfg->auditlog_parts, value + 1, NULL); + } + else + if (value[0] == '-') { /* Remove the listed parts. */ + char c, *t = value + 1; + + /* Start with the current value. */ + new_value = apr_pstrdup(msr->mp, msr->txcfg->auditlog_parts); + + while((c = *t++) != '\0') { + char *s = new_value; + char *d = new_value; + + while(*s != '\0') { + if (*s != c) { + *(d++) = *(s++); + } else { + s++; + } + } + *d = '\0'; + } + } + + /* Set the new value. */ + msr->txcfg->auditlog_parts = new_value; + msr->usercfg->auditlog_parts = new_value; + msr_log(msr, 4, "Ctl: Set auditLogParts to %s.", msr->txcfg->auditlog_parts); + + return 1; + } else + if (strcasecmp(name, "debugLogLevel") == 0) { + msr->txcfg->debuglog_level = atoi(value); + msr->usercfg->debuglog_level = atoi(value); + msr_log(msr, 4, "Ctl: Set debugLogLevel to %d.", msr->txcfg->debuglog_level); + + return 1; + } else + if (strcasecmp(name, "requestBodyLimit") == 0) { + long int limit = strtol(value, NULL, 10); + + /* ENH Accept only in correct phase warn otherwise. */ + msr->txcfg->reqbody_limit = limit; + msr->usercfg->reqbody_limit = limit; + + return 1; + } else + if (strcasecmp(name, "responseBodyLimit") == 0) { + long int limit = strtol(value, NULL, 10); + + /* ENH Accept only in correct phase warn otherwise. */ + msr->txcfg->of_limit = limit; + msr->usercfg->of_limit = limit; + + return 1; + } + else { + /* Should never happen, but log if it does. */ + msr_log(msr, 1, "Internal Error: Unknown ctl action \"%s\".", name); + return -1; + } +} + +/* xmlns */ +static char *msre_action_xmlns_validate(msre_engine *engine, msre_action *action) { + char *name = NULL; + char *value = NULL; + + /* Parse first. */ + if (parse_name_eq_value(engine->mp, action->param, &name, &value) < 0) { + return FATAL_ERROR; + } + if (value == NULL) { + return apr_psprintf(engine->mp, "Missing xmlns href for prefix: %s", name); + } + + /* Don't do anything else right now, we are just storing + * the value for the variable, which is the real consumer + * for the namespace information. + */ + + return NULL; +} + +/* sanitiseArg */ +static apr_status_t msre_action_sanitiseArg_execute(modsec_rec *msr, apr_pool_t *mptmp, + msre_rule *rule, msre_action *action) +{ + const char *sargname = NULL; + const apr_array_header_t *tarr; + const apr_table_entry_t *telts; + int i; + + sargname = action->param; + + tarr = apr_table_elts(msr->arguments); + telts = (const apr_table_entry_t*)tarr->elts; + for (i = 0; i < tarr->nelts; i++) { + msc_arg *arg = (msc_arg *)telts[i].val; + + if (strcasecmp(sargname, arg->name) == 0) { + apr_table_addn(msr->arguments_to_sanitise, arg->name, (void *)arg); + } + } + + return 1; +} + +#define SANITISE_ARG 1 +#define SANITISE_REQUEST_HEADER 2 +#define SANITISE_RESPONSE_HEADER 3 + +/* sanitiseMatched */ +static apr_status_t msre_action_sanitiseMatched_execute(modsec_rec *msr, apr_pool_t *mptmp, + msre_rule *rule, msre_action *action) +{ + const char *sargname = NULL; + const apr_array_header_t *tarr; + const apr_table_entry_t *telts; + int i, type = 0; + msc_string *mvar = msr->matched_var; + + if (mvar->name_len == 0) return 0; + + /* IMP1 We need to extract the variable name properly here, + * taking into account it may have been escaped. + */ + if ((mvar->name_len > 5) && (strncmp(mvar->name, "ARGS:", 5) == 0)) { + sargname = apr_pstrdup(msr->mp, mvar->name + 5); + type = SANITISE_ARG; + } else + if ((mvar->name_len > 11) && (strncmp(mvar->name, "ARGS_NAMES:", 11) == 0)) { + sargname = apr_pstrdup(msr->mp, mvar->name + 11); + type = SANITISE_ARG; + } else + if ((mvar->name_len > 16) && (strncmp(mvar->name, "REQUEST_HEADERS:", 16) == 0)) { + sargname = apr_pstrdup(msr->mp, mvar->name + 16); + type = SANITISE_REQUEST_HEADER; + } else + if ((mvar->name_len > 22) && (strncmp(mvar->name, "REQUEST_HEADERS_NAMES:", 22) == 0)) { + sargname = apr_pstrdup(msr->mp, mvar->name + 22); + type = SANITISE_REQUEST_HEADER; + } else + if ((mvar->name_len > 17) && (strncmp(mvar->name, "RESPONSE_HEADERS:", 17) == 0)) { + sargname = apr_pstrdup(msr->mp, mvar->name + 17); + type = SANITISE_RESPONSE_HEADER; + } else + if ((mvar->name_len > 23) && (strncmp(mvar->name, "RESPONSE_HEADERS_NAMES:", 23) == 0)) { + sargname = apr_pstrdup(msr->mp, mvar->name + 23); + type = SANITISE_RESPONSE_HEADER; + } + else { + msr_log(msr, 3, "sanitiseMatched: Don't know how to handle variable: %s", + mvar->name); + return 0; + } + + switch(type) { + case SANITISE_ARG : + tarr = apr_table_elts(msr->arguments); + telts = (const apr_table_entry_t*)tarr->elts; + for (i = 0; i < tarr->nelts; i++) { + msc_arg *arg = (msc_arg *)telts[i].val; + if (strcasecmp(sargname, arg->name) == 0) { + apr_table_addn(msr->arguments_to_sanitise, arg->name, (void *)arg); + } + } + break; + + case SANITISE_REQUEST_HEADER : + apr_table_set(msr->request_headers_to_sanitise, sargname, "1"); + break; + + case SANITISE_RESPONSE_HEADER : + apr_table_set(msr->response_headers_to_sanitise, sargname, "1"); + break; + + default : + /* do nothing */ + break; + } + + return 1; +} + +/* sanitiseRequestHeader */ +static apr_status_t msre_action_sanitiseRequestHeader_execute(modsec_rec *msr, apr_pool_t *mptmp, + msre_rule *rule, msre_action *action) +{ + apr_table_set(msr->request_headers_to_sanitise, action->param, "1"); + return 1; +} + +/* sanitiseResponseHeader */ +static apr_status_t msre_action_sanitiseResponseHeader_execute(modsec_rec *msr, apr_pool_t *mptmp, + msre_rule *rule, msre_action *action) +{ + apr_table_set(msr->response_headers_to_sanitise, action->param, "1"); + return 1; +} + +/* setenv */ +static apr_status_t msre_action_setenv_execute(modsec_rec *msr, apr_pool_t *mptmp, + msre_rule *rule, msre_action *action) +{ + char *data = apr_pstrdup(mptmp, action->param); + char *env_name = NULL, *env_value = NULL; + char *s = NULL; + msc_string *env = NULL; + + /* Extract the name and the value. */ + /* IMP1 We have a function for this now, parse_name_eq_value? */ + s = strstr(data, "="); + if (s == NULL) { + env_name = data; + env_value = "1"; + } else { + env_name = data; + env_value = s + 1; + *s = '\0'; + } + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Setting env variable: %s=%s", env_name, env_value); + } + + /* Expand and escape any macros in the name */ + env = apr_palloc(msr->mp, sizeof(msc_string)); + if (env == NULL) { + msr_log(msr, 1, "Failed to allocate space to expand name macros"); + return -1; + } + env->value = env_name; + env->value_len = strlen(env->value); + expand_macros(msr, env, rule, mptmp); + env_name = log_escape_ex(msr->mp, env->value, env->value_len); + + /* Execute the requested action. */ + if (env_name[0] == '!') { + /* Delete */ + apr_table_unset(msr->r->subprocess_env, env_name + 1); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Unset env variable \"%s\".", env_name); + } + } else { + /* Set */ + char * val_value = NULL; + msc_string *val = apr_palloc(msr->mp, sizeof(msc_string)); + if (val == NULL) { + msr_log(msr, 1, "Failed to allocate space to expand value macros"); + return -1; + } + + /* Expand values in value */ + val->value = env_value; + val->value_len = strlen(val->value); + expand_macros(msr, val, rule, mptmp); + + /* To be safe, we escape the value as it goes in subprocess_env. */ + val_value = log_escape_ex(msr->mp, val->value, val->value_len); + + apr_table_set(msr->r->subprocess_env, env_name, val_value); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Set env variable \"%s\" to \"%s\".", + env_name, + log_escape(mptmp, val_value)); + } + } + + return 1; +} + +/* setvar */ +static apr_status_t msre_action_setvar_execute(modsec_rec *msr, apr_pool_t *mptmp, + msre_rule *rule, msre_action *action) +{ + char *data = apr_pstrdup(mptmp, action->param); + char *col_name = NULL, *var_name = NULL, *var_value = NULL; + char *s = NULL; + apr_table_t *target_col = NULL; + int is_negated = 0; + msc_string *var = NULL; + + /* Extract the name and the value. */ + /* IMP1 We have a function for this now, parse_name_eq_value? */ + s = strstr(data, "="); + if (s == NULL) { + var_name = data; + var_value = "1"; + } else { + var_name = data; + var_value = s + 1; + *s = '\0'; + + while ((*var_value != '\0')&&(isspace(*var_value))) var_value++; + } + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Setting variable: %s=%s", var_name, var_value); + } + + + /* Expand and escape any macros in the name */ + var = apr_palloc(msr->mp, sizeof(msc_string)); + if (var == NULL) { + msr_log(msr, 1, "Failed to allocate space to expand name macros"); + return -1; + } + var->value = var_name; + var->value_len = strlen(var->value); + expand_macros(msr, var, rule, mptmp); + var_name = log_escape_ex(msr->mp, var->value, var->value_len); + + /* Handle the exclamation mark. */ + if (var_name[0] == '!') { + var_name = var_name + 1; + is_negated = 1; + } + + /* ENH Not possible to use ! and = at the same time. */ + /* ENH Not possible to change variable "KEY". */ + + /* Figure out the collection name. */ + target_col = msr->tx_vars; + s = strstr(var_name, "."); + if (s == NULL) { + msr_log(msr, 3, "Asked to set variable \"%s\", but no collection name specified. ", + log_escape(msr->mp, var_name)); + return 0; + } + col_name = var_name; + var_name = s + 1; + *s = '\0'; + + /* Locate the collection. */ + if (strcasecmp(col_name, "tx") == 0) { /* Special case for TX variables. */ + target_col = msr->tx_vars; + } else { + target_col = (apr_table_t *)apr_table_get(msr->collections, col_name); + if (target_col == NULL) { + msr_log(msr, 3, "Could not set variable \"%s.%s\" as the collection does not exist.", + log_escape(msr->mp, col_name), log_escape(msr->mp, var_name)); + return 0; + } + } + + if (is_negated) { + /* Unset variable. */ + + /* ENH Refuse to remove certain variables, e.g. TIMEOUT, internal variables, etc... */ + + apr_table_unset(target_col, var_name); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Unset variable \"%s.%s\".", col_name, var_name); + } + } + else { + /* Set or change variable. */ + + if ((var_value[0] == '+')||(var_value[0] == '-')) { + /* Relative change. */ + msc_string *rec = NULL; + msc_string *val = apr_palloc(msr->mp, sizeof(msc_string)); + int value = 0; + + if (val == NULL) { + msr_log(msr, 1, "Failed to allocate space to expand value macros"); + return -1; + } + + /* Retrieve variable or generate (if it does not exist). */ + rec = (msc_string *)apr_table_get(target_col, var_name); + if (rec == NULL) { + rec = var; /* use the already allocated space for var */ + rec->name = apr_pstrdup(msr->mp, var_name); + rec->name_len = strlen(rec->name); + value = 0; + rec->value = apr_psprintf(msr->mp, "%d", value); + rec->value_len = strlen(rec->value); + } + else { + value = atoi(rec->value); + } + + /* Record the original value before we change it */ + collection_original_setvar(msr, col_name, rec); + + /* Expand values in value */ + val->value = var_value; + val->value_len = strlen(val->value); + expand_macros(msr, val, rule, mptmp); + var_value = val->value; + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Relative change: %s=%d%s", var_name, value, var_value); + } + + /* Change value. */ + value += atoi(var_value); + if (value < 0) value = 0; /* Counters never go below zero. */ + + /* Put the variable back. */ + rec->value = apr_psprintf(msr->mp, "%d", value); + rec->value_len = strlen(rec->value); + apr_table_setn(target_col, rec->name, (void *)rec); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Set variable \"%s.%s\" to \"%s\".", + col_name, rec->name, + log_escape_ex(mptmp, rec->value, rec->value_len)); + } + } + else { + /* Absolute change. */ + + var->name = apr_pstrdup(msr->mp, var_name); + var->name_len = strlen(var->name); + var->value = apr_pstrdup(msr->mp, var_value); + var->value_len = strlen(var->value); + expand_macros(msr, var, rule, mptmp); + apr_table_setn(target_col, var->name, (void *)var); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Set variable \"%s.%s\" to \"%s\".", + log_escape(mptmp, col_name), + log_escape_ex(mptmp, var->name, var->name_len), + log_escape_ex(mptmp, var->value, var->value_len)); + } + } + } + + /* Make note of the change so that we know later + * we need to persist the collection. + */ + apr_table_set(msr->collections_dirty, col_name, "1"); + + return 1; +} + +/* expirevar */ +static apr_status_t msre_action_expirevar_execute(modsec_rec *msr, apr_pool_t *mptmp, + msre_rule *rule, msre_action *action) +{ + char *data = apr_pstrdup(mptmp, action->param); + char *col_name = NULL, *var_name = NULL, *var_value = NULL; + char *s = NULL; + apr_table_t *target_col = NULL; + msc_string *var = NULL; + + /* Extract the name and the value. */ + /* IMP1 We have a function for this now, parse_name_eq_value? */ + s = strstr(data, "="); + if (s == NULL) { + var_name = data; + var_value = "1"; + } else { + var_name = data; + var_value = s + 1; + *s = '\0'; + } + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Expiring variable: %s=%s", var_name, var_value); + } + + /* Expand and escape any macros in the name */ + var = apr_palloc(msr->mp, sizeof(msc_string)); + if (var == NULL) { + msr_log(msr, 1, "Failed to allocate space to expand name macros"); + return -1; + } + var->value = var_name; + var->value_len = strlen(var->value); + expand_macros(msr, var, rule, mptmp); + var_name = log_escape_ex(msr->mp, var->value, var->value_len); + + /* Choose the collection to work with. */ + s = strstr(var_name, "."); + if (s != NULL) { + col_name = var_name; + var_name = s + 1; + *s = '\0'; + + /* IMP1 No need to handle TX here because TX variables cannot expire, + * but we definitely need to have a better error message. + */ + + target_col = (apr_table_t *)apr_table_get(msr->collections, col_name); + if (target_col == NULL) { + msr_log(msr, 3, "Could not expire variable \"%s.%s\" as the collection does not exist.", + log_escape(msr->mp, col_name), log_escape(msr->mp, var_name)); + return 0; + } + } else { + msr_log(msr, 3, "Asked to expire variable \"%s\", but no collection name specified. ", + log_escape(msr->mp, var_name)); + return 0; + } + + /* To expire a variable we just place a special variable into + * the collection. Expiry actually happens when the collection + * is retrieved from storage the next time. + */ + var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + var->name = apr_psprintf(msr->mp, "__expire_%s", var_name); + var->name_len = strlen(var->name); + + /* Expand macros in value */ + var->value = var_value; + var->value_len = strlen(var->value); + expand_macros(msr, var, rule, msr->mp); + var_value = var->value; + + /* Calculate with the expanded value */ + var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, (apr_time_t)(apr_time_sec(msr->request_time) + + atoi(var_value))); + var->value_len = strlen(var->value); + + apr_table_setn(target_col, var->name, (void *)var); + + msr_log(msr, 4, "Variable \"%s.%s\" set to expire in %s seconds.", col_name, + var_name, var_value); + + apr_table_set(msr->collections_dirty, col_name, "1"); + + return 1; +} + +/* deprecatevar */ +static apr_status_t msre_action_deprecatevar_execute(modsec_rec *msr, apr_pool_t *mptmp, + msre_rule *rule, msre_action *action) +{ + char *data = apr_pstrdup(mptmp, action->param); + char *col_name = NULL, *var_name = NULL, *var_value = NULL; + char *s = NULL; + apr_table_t *target_col = NULL; + msc_string *var = NULL, *var_last_update_time = NULL; + apr_time_t last_update_time, current_time; + long current_value, new_value; + + /* Extract the name and the value. */ + /* IMP1 We have a function for this now, parse_name_eq_value? */ + s = strstr(data, "="); + if (s == NULL) { + var_name = data; + var_value = "1"; + } else { + var_name = data; + var_value = s + 1; + *s = '\0'; + } + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Deprecating variable: %s=%s", var_name, var_value); + } + + /* Expand and escape any macros in the name */ + var = apr_palloc(msr->mp, sizeof(msc_string)); + if (var == NULL) { + msr_log(msr, 1, "Failed to allocate space to expand name macros"); + return -1; + } + var->value = var_name; + var->value_len = strlen(var->value); + expand_macros(msr, var, rule, mptmp); + var_name = log_escape_ex(msr->mp, var->value, var->value_len); + + /* Expand macros in value */ + var->value = var_value; + var->value_len = strlen(var->value); + expand_macros(msr, var, rule, msr->mp); + var_value = var->value; + + /* Choose the collection to work with. */ + s = strstr(var_name, "."); + if (s != NULL) { + col_name = var_name; + var_name = s + 1; + *s = '\0'; + + /* IMP1 Add message TX variables cannot deprecate in value. */ + + target_col = (apr_table_t *)apr_table_get(msr->collections, col_name); + if (target_col == NULL) { + msr_log(msr, 3, "Could not deprecate variable \"%s.%s\" as the collection does " + "not exist.", log_escape(msr->mp, col_name), log_escape(msr->mp, var_name)); + return 0; + } + } else { + msr_log(msr, 3, "Asked to deprecate variable \"%s\", but no collection name specified. ", + log_escape(msr->mp, var_name)); + return 0; + } + + /* Find the current value. */ + var = (msc_string *)apr_table_get(target_col, var_name); + if (var == NULL) { + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Asked to deprecate variable \"%s.%s\", but it does not exist.", + log_escape(msr->mp, col_name), log_escape(msr->mp, var_name)); + } + return 0; + } + current_value = atoi(var->value); + + /* Find the last update time (of the collection). */ + var_last_update_time = (msc_string *)apr_table_get(target_col, "LAST_UPDATE_TIME"); + if (var_last_update_time == NULL) { + /* This is all right. If collection was created (and not restored from + * storage) then it won't have LAST_UPDATE_TIME - it was never updated. + */ + return 0; + } + + current_time = apr_time_sec(apr_time_now()); + last_update_time = atoi(var_last_update_time->value); + + s = strstr(var_value, "/"); + if (s == NULL) { + msr_log(msr, 3, "Incorrect format for the deprecatevar argument: \"%s\"", + log_escape(msr->mp, var_value)); + return 0; + } + *s = '\0'; + s++; + + /* Deprecate the value using the given speed and the + * time elapsed since the last update. + */ + new_value = current_value - + (atol(var_value) * ((current_time - last_update_time) / atol(s))); + if (new_value < 0) new_value = 0; + + /* Only change the value if it differs. */ + if (new_value != current_value) { + var->value = apr_psprintf(msr->mp, "%ld", new_value); + var->value_len = strlen(var->value); + + msr_log(msr, 4, "Deprecated variable \"%s.%s\" from %ld to %ld (%" APR_TIME_T_FMT " seconds since " + "last update).", log_escape(msr->mp, col_name), log_escape(msr->mp, var_name), + current_value, new_value, (apr_time_t)(current_time - last_update_time)); + + apr_table_set(msr->collections_dirty, col_name, "1"); + } else { + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Not deprecating variable \"%s.%s\" because the new value (%ld) is " + "the same as the old one (%ld) (%" APR_TIME_T_FMT " seconds since last update).", + log_escape(msr->mp, col_name), log_escape(msr->mp, var_name), current_value, + new_value, (apr_time_t)(current_time - last_update_time)); + } + } + + return 1; +} + +static apr_status_t init_collection(modsec_rec *msr, const char *real_col_name, + const char *col_name, const char *col_key, unsigned int col_key_len) +{ + apr_table_t *table = NULL; + msc_string *var = NULL; + + /* IMP1 Cannot initialise the built-in collections this way. */ + + /* Does the collection exist already? */ + if (apr_table_get(msr->collections, col_name) != NULL) { + /* ENH Warn about this. */ + return 0; + } + + /* Init collection from storage. */ + table = collection_retrieve(msr, real_col_name, col_key, col_key_len); + + if (table == NULL) { + /* Does not exist yet - create new. */ + msr_log(msr, 4, "Creating collection (name \"%s\", key \"%s\").", + real_col_name, col_key); + + table = apr_table_make(msr->mp, 24); + if (table == NULL) return -1; + + /* IMP1 Is the timeout hard-coded to 3600? */ + + /* Add default timeout. */ + var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + var->name = "__expire_KEY"; + var->name_len = strlen(var->name); + var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, (apr_time_t)(apr_time_sec(msr->request_time) + 3600)); + var->value_len = strlen(var->value); + apr_table_setn(table, var->name, (void *)var); + + /* Remember the key. */ + var = apr_pcalloc(msr->mp, sizeof(msc_string)); + var->name = "KEY"; + var->name_len = strlen(var->name); + var->value = apr_pstrmemdup(msr->mp, col_key, col_key_len); + var->value_len = col_key_len; + apr_table_setn(table, var->name, (void *)var); + + /* The timeout. */ + var = apr_pcalloc(msr->mp, sizeof(msc_string)); + var->name = "TIMEOUT"; + var->name_len = strlen(var->name); + var->value = apr_psprintf(msr->mp, "%d", 3600); + var->value_len = strlen(var->value); + apr_table_setn(table, var->name, (void *)var); + + /* We may want to allow the user to unset KEY + * but we still need to preserve value to identify + * the collection in storage. + */ + + /* IMP1 Actually I want a better way to delete collections, + * perhaps a dedicated action. + */ + + var = apr_pcalloc(msr->mp, sizeof(msc_string)); + var->name = "__key"; + var->name_len = strlen(var->name); + var->value = apr_pstrmemdup(msr->mp, col_key, col_key_len); + var->value_len = col_key_len; + apr_table_setn(table, var->name, (void *)var); + + /* Peristence code will need to know the name of the collection. */ + var = apr_pcalloc(msr->mp, sizeof(msc_string)); + var->name = "__name"; + var->name_len = strlen(var->name); + var->value = apr_pstrdup(msr->mp, real_col_name); + var->value_len = strlen(var->value); + apr_table_setn(table, var->name, (void *)var); + + /* Create time. */ + var = apr_pcalloc(msr->mp, sizeof(msc_string)); + var->name = "CREATE_TIME"; + var->name_len = strlen(var->name); + var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, (apr_time_t)apr_time_sec(msr->request_time)); + var->value_len = strlen(var->value); + apr_table_setn(table, var->name, (void *)var); + + /* Update counter. */ + var = apr_pcalloc(msr->mp, sizeof(msc_string)); + var->name = "UPDATE_COUNTER"; + var->name_len = strlen(var->name); + var->value = "0"; + var->value_len = strlen(var->value); + apr_table_setn(table, var->name, (void *)var); + + /* This is a new collection. */ + var = apr_pcalloc(msr->mp, sizeof(msc_string)); + var->name = "IS_NEW"; + var->name_len = strlen(var->name); + var->value = "1"; + var->value_len = strlen(var->value); + apr_table_setn(table, var->name, (void *)var); + } + + /* Record the original counter value before we change it */ + var = (msc_string *)apr_table_get(table, "UPDATE_COUNTER"); + if (var != NULL) { + collection_original_setvar(msr, col_name, var); + } + + /* Add the collection to the list. */ + apr_table_setn(msr->collections, apr_pstrdup(msr->mp, col_name), (void *)table); + + if (strcmp(col_name, real_col_name) != 0) { + msr_log(msr, 4, "Added collection \"%s\" to the list as \"%s\".", + log_escape(msr->mp, real_col_name), log_escape(msr->mp, col_name)); + } else { + msr_log(msr, 4, "Added collection \"%s\" to the list.", + log_escape(msr->mp, real_col_name)); + } + + return 1; +} + +/* initcol */ +static apr_status_t msre_action_initcol_execute(modsec_rec *msr, apr_pool_t *mptmp, + msre_rule *rule, msre_action *action) +{ + char *data = apr_pstrdup(msr->mp, action->param); + char *col_name = NULL, *col_key = NULL; + unsigned int col_key_len; + + msc_string *var = NULL; + char *s = NULL; + + /* Extract the name and the value. */ + /* IMP1 We have a function for this now, parse_name_eq_value? */ + s = strstr(data, "="); + if (s == NULL) return 0; + col_name = data; + col_key = s + 1; + *s = '\0'; + + /* Expand the key and init collection from storage. */ + var = apr_pcalloc(mptmp, sizeof(msc_string)); + var->value = col_key; + var->value_len = strlen(var->value); + expand_macros(msr, var, rule, mptmp); + + col_key = var->value; + col_key_len = var->value_len; + + return init_collection(msr, col_name, col_name, col_key, col_key_len); +} + +/* setsid */ +static apr_status_t msre_action_setsid_execute(modsec_rec *msr, apr_pool_t *mptmp, + msre_rule *rule, msre_action *action) +{ + msc_string *var = NULL; + char *real_col_name = NULL, *col_key = NULL; + unsigned int col_key_len; + + /* Construct session ID. */ + var = apr_pcalloc(mptmp, sizeof(msc_string)); + var->value = (char *)action->param; + var->value_len = strlen(var->value); + expand_macros(msr, var, rule, mptmp); + msr->sessionid = apr_pstrdup(msr->mp, var->value); + + /* Construct collection name. */ + col_key = var->value; + col_key_len = var->value_len; + real_col_name = apr_psprintf(mptmp, "%s_SESSION", msr->txcfg->webappid); + + /* Initialise collection. */ + return init_collection(msr, real_col_name, "SESSION", col_key, col_key_len); +} + +/* setuid */ +static apr_status_t msre_action_setuid_execute(modsec_rec *msr, apr_pool_t *mptmp, + msre_rule *rule, msre_action *action) +{ + msc_string *var = NULL; + char *real_col_name = NULL, *col_key = NULL; + unsigned int col_key_len; + + /* Construct user ID. */ + var = apr_pcalloc(mptmp, sizeof(msc_string)); + var->value = (char *)action->param; + var->value_len = strlen(var->value); + expand_macros(msr, var, rule, mptmp); + msr->userid = apr_pstrdup(msr->mp, var->value); + + /* Construct collection name. */ + col_key = var->value; + col_key_len = var->value_len; + real_col_name = apr_psprintf(mptmp, "%s_USER", msr->txcfg->webappid); + + /* Initialise collection. */ + return init_collection(msr, real_col_name, "USER", col_key, col_key_len); +} + +/* exec */ +static char *msre_action_exec_validate(msre_engine *engine, msre_action *action) { + #if defined(WITH_LUA) + char *filename = (char *)action->param; + + /* TODO Support relative filenames. */ + + /* Process Lua scripts internally. */ + if (strlen(filename) > 4) { + char *p = filename + strlen(filename) - 4; + if ((p[0] == '.')&&(p[1] == 'l')&&(p[2] == 'u')&&(p[3] == 'a')) { + /* It's a Lua script. */ + msc_script *script = NULL; + + /* Compile script. */ + char *msg = lua_compile(&script, filename, engine->mp); + if (msg != NULL) return msg; + + action->param_data = script; + } + } + #endif + + return NULL; +} + +static apr_status_t msre_action_exec_execute(modsec_rec *msr, apr_pool_t *mptmp, + msre_rule *rule, msre_action *action) +{ + #if defined(WITH_LUA) + if (action->param_data != NULL) { /* Lua */ + msc_script *script = (msc_script *)action->param_data; + char *my_error_msg = NULL; + + if (lua_execute(script, NULL, msr, rule, &my_error_msg) < 0) { + msr_log(msr, 1, "%s", my_error_msg); + return 0; + } + } else + #endif + { /* Execute as shell script. */ + char *script_output = NULL; + + int rc = apache2_exec(msr, action->param, NULL, &script_output); + if (rc != 1) { + msr_log(msr, 1, "Failed to execute: %s", action->param); + return 0; + } + } + + return 1; +} + +/* prepend */ +static apr_status_t msre_action_prepend_execute(modsec_rec *msr, apr_pool_t *mptmp, + msre_rule *rule, msre_action *action) +{ + msc_string *var = NULL; + + /* Expand any macros in the text */ + var = apr_pcalloc(mptmp, sizeof(msc_string)); + if (var == NULL) return -1; + var->value = (char *)action->param; + var->value_len = strlen(var->value); + expand_macros(msr, var, rule, mptmp); + + /* ENH: Verify we really have to dup the data here. */ + msr->content_prepend = apr_pstrndup(msr->mp, var->value, var->value_len); + msr->content_prepend_len = var->value_len; + + return 1; +} + +/* append */ +static apr_status_t msre_action_append_execute(modsec_rec *msr, apr_pool_t *mptmp, + msre_rule *rule, msre_action *action) +{ + msc_string *var = NULL; + + /* Expand any macros in the text */ + var = apr_pcalloc(mptmp, sizeof(msc_string)); + if (var == NULL) return -1; + var->value = (char *)action->param; + var->value_len = strlen(var->value); + expand_macros(msr, var, rule, mptmp); + + /* ENH: Verify we really have to dup the data here. */ + msr->content_append = apr_pstrndup(msr->mp, var->value, var->value_len); + msr->content_append_len = var->value_len; + + return 1; +} + +/* -- */ + +/** + * + */ +void msre_engine_register_default_actions(msre_engine *engine) { + + /* id */ + msre_engine_action_register(engine, + "id", + ACTION_METADATA, + 1, 1, + NO_PLUS_MINUS, + ACTION_CARDINALITY_ONE, + ACTION_CGROUP_NONE, + NULL, + msre_action_id_init, + NULL + ); + + /* rev */ + msre_engine_action_register(engine, + "rev", + ACTION_METADATA, + 1, 1, + NO_PLUS_MINUS, + ACTION_CARDINALITY_ONE, + ACTION_CGROUP_NONE, + NULL, + msre_action_rev_init, + NULL + ); + + /* msg */ + msre_engine_action_register(engine, + "msg", + ACTION_METADATA, + 1, 1, + NO_PLUS_MINUS, + ACTION_CARDINALITY_ONE, + ACTION_CGROUP_NONE, + NULL, + msre_action_msg_init, + NULL + ); + + /* logdata */ + msre_engine_action_register(engine, + "logdata", + ACTION_METADATA, + 1, 1, + NO_PLUS_MINUS, + ACTION_CARDINALITY_ONE, + ACTION_CGROUP_NONE, + NULL, + msre_action_logdata_init, + NULL + ); + + /* severity */ + msre_engine_action_register(engine, + "severity", + ACTION_METADATA, + 1, 1, + NO_PLUS_MINUS, + ACTION_CARDINALITY_ONE, + ACTION_CGROUP_NONE, + NULL, + msre_action_severity_init, + NULL + ); + + /* chain */ + msre_engine_action_register(engine, + "chain", + ACTION_FLOW, + 0, 0, + NO_PLUS_MINUS, + ACTION_CARDINALITY_ONE, + ACTION_CGROUP_NONE, + NULL, + msre_action_chain_init, + NULL + ); + + /* log */ + msre_engine_action_register(engine, + "log", + ACTION_NON_DISRUPTIVE, + 0, 0, + NO_PLUS_MINUS, + ACTION_CARDINALITY_ONE, + ACTION_CGROUP_LOG, + NULL, + msre_action_log_init, + NULL + ); + + /* nolog */ + msre_engine_action_register(engine, + "nolog", + ACTION_NON_DISRUPTIVE, + 0, 0, + NO_PLUS_MINUS, + ACTION_CARDINALITY_ONE, + ACTION_CGROUP_LOG, + NULL, + msre_action_nolog_init, + NULL + ); + + /* auditlog */ + msre_engine_action_register(engine, + "auditlog", + ACTION_NON_DISRUPTIVE, + 0, 0, + NO_PLUS_MINUS, + ACTION_CARDINALITY_ONE, + ACTION_CGROUP_AUDITLOG, + NULL, + msre_action_auditlog_init, + NULL + ); + + /* noauditlog */ + msre_engine_action_register(engine, + "noauditlog", + ACTION_NON_DISRUPTIVE, + 0, 0, + NO_PLUS_MINUS, + ACTION_CARDINALITY_ONE, + ACTION_CGROUP_AUDITLOG, + NULL, + msre_action_noauditlog_init, + NULL + ); + + /* deny */ + msre_engine_action_register(engine, + "block", + ACTION_DISRUPTIVE, + 0, 0, + NO_PLUS_MINUS, + ACTION_CARDINALITY_ONE, + ACTION_CGROUP_DISRUPTIVE, + NULL, + msre_action_block_init, + NULL + ); + + /* deny */ + msre_engine_action_register(engine, + "deny", + ACTION_DISRUPTIVE, + 0, 0, + NO_PLUS_MINUS, + ACTION_CARDINALITY_ONE, + ACTION_CGROUP_DISRUPTIVE, + NULL, + msre_action_deny_init, + NULL + ); + + /* status */ + msre_engine_action_register(engine, + "status", + ACTION_DISRUPTIVE, + 1, 1, + NO_PLUS_MINUS, + ACTION_CARDINALITY_ONE, + ACTION_CGROUP_NONE, + msre_action_status_validate, + msre_action_status_init, + NULL + ); + + /* drop */ + msre_engine_action_register(engine, + "drop", + ACTION_DISRUPTIVE, + 0, 0, + NO_PLUS_MINUS, + ACTION_CARDINALITY_ONE, + ACTION_CGROUP_DISRUPTIVE, + NULL, + msre_action_drop_init, + NULL + ); + + /* pause */ + msre_engine_action_register(engine, + "pause", + ACTION_DISRUPTIVE, + 1, 1, + NO_PLUS_MINUS, + ACTION_CARDINALITY_ONE, + ACTION_CGROUP_NONE, + msre_action_pause_validate, + msre_action_pause_init, + NULL + ); + + /* redirect */ + msre_engine_action_register(engine, + "redirect", + ACTION_DISRUPTIVE, + 1, 1, + NO_PLUS_MINUS, + ACTION_CARDINALITY_ONE, + ACTION_CGROUP_DISRUPTIVE, + msre_action_redirect_validate, + msre_action_redirect_init, + msre_action_redirect_execute + ); + + /* proxy */ + msre_engine_action_register(engine, + "proxy", + ACTION_DISRUPTIVE, + 1, 1, + NO_PLUS_MINUS, + ACTION_CARDINALITY_ONE, + ACTION_CGROUP_DISRUPTIVE, + msre_action_proxy_validate, + msre_action_proxy_init, + msre_action_proxy_execute + ); + + /* pass */ + msre_engine_action_register(engine, + "pass", + ACTION_DISRUPTIVE, + 0, 0, + NO_PLUS_MINUS, + ACTION_CARDINALITY_ONE, + ACTION_CGROUP_DISRUPTIVE, + NULL, + msre_action_pass_init, + NULL + ); + + /* skip */ + msre_engine_action_register(engine, + "skip", + ACTION_DISRUPTIVE, + 1, 1, + NO_PLUS_MINUS, + ACTION_CARDINALITY_ONE, + ACTION_CGROUP_DISRUPTIVE, + msre_action_skip_validate, + msre_action_skip_init, + NULL + ); + + /* skipAfter */ + msre_engine_action_register(engine, + "skipAfter", + ACTION_DISRUPTIVE, + 1, 1, + NO_PLUS_MINUS, + ACTION_CARDINALITY_ONE, + ACTION_CGROUP_DISRUPTIVE, + msre_action_skipAfter_validate, + msre_action_skipAfter_init, + NULL + ); + + /* allow */ + msre_engine_action_register(engine, + "allow", + ACTION_DISRUPTIVE, + 0, 1, + NO_PLUS_MINUS, + ACTION_CARDINALITY_ONE, + ACTION_CGROUP_DISRUPTIVE, + msre_action_allow_validate, + msre_action_allow_init, + NULL + ); + + /* phase */ + /* ENH: This should be ACTION_NON_DISRUPTIVE or ACTION_FLOW??? */ + msre_engine_action_register(engine, + "phase", + ACTION_DISRUPTIVE, + 1, 1, + NO_PLUS_MINUS, + ACTION_CARDINALITY_ONE, + ACTION_CGROUP_NONE, + msre_action_phase_validate, + msre_action_phase_init, + NULL + ); + + /* t */ + msre_engine_action_register(engine, + "t", + ACTION_NON_DISRUPTIVE, + 1, 1, + ALLOW_PLUS_MINUS, + ACTION_CARDINALITY_MANY, + ACTION_CGROUP_NONE, + msre_action_t_validate, + msre_action_t_init, + NULL + ); + + /* ctl */ + msre_engine_action_register(engine, + "ctl", + ACTION_NON_DISRUPTIVE, + 1, 1, + NO_PLUS_MINUS, + ACTION_CARDINALITY_MANY, + ACTION_CGROUP_NONE, + msre_action_ctl_validate, + msre_action_ctl_init, + msre_action_ctl_execute + ); + + /* xmlns */ + msre_engine_action_register(engine, + "xmlns", + ACTION_NON_DISRUPTIVE, + 1, 1, + NO_PLUS_MINUS, + ACTION_CARDINALITY_MANY, + ACTION_CGROUP_NONE, + msre_action_xmlns_validate, + NULL, + NULL + ); + + /* capture */ + msre_engine_action_register(engine, + "capture", + ACTION_NON_DISRUPTIVE, + 0, 0, + NO_PLUS_MINUS, + ACTION_CARDINALITY_ONE, + ACTION_CGROUP_NONE, + NULL, + NULL, + NULL + ); + + /* sanitiseArg */ + msre_engine_action_register(engine, + "sanitiseArg", + ACTION_NON_DISRUPTIVE, + 1, 1, + NO_PLUS_MINUS, + ACTION_CARDINALITY_MANY, + ACTION_CGROUP_NONE, + NULL, + NULL, + msre_action_sanitiseArg_execute + ); + + /* sanitiseMatched */ + msre_engine_action_register(engine, + "sanitiseMatched", + ACTION_NON_DISRUPTIVE, + 0, 0, + NO_PLUS_MINUS, + ACTION_CARDINALITY_MANY, + ACTION_CGROUP_NONE, + NULL, + NULL, + msre_action_sanitiseMatched_execute + ); + + /* sanitiseRequestHeader */ + msre_engine_action_register(engine, + "sanitiseRequestHeader", + ACTION_NON_DISRUPTIVE, + 1, 1, + NO_PLUS_MINUS, + ACTION_CARDINALITY_MANY, + ACTION_CGROUP_NONE, + NULL, + NULL, + msre_action_sanitiseRequestHeader_execute + ); + + /* sanitiseResponseHeader */ + msre_engine_action_register(engine, + "sanitiseResponseHeader", + ACTION_NON_DISRUPTIVE, + 1, 1, + NO_PLUS_MINUS, + ACTION_CARDINALITY_MANY, + ACTION_CGROUP_NONE, + NULL, + NULL, + msre_action_sanitiseResponseHeader_execute + ); + + /* setenv */ + msre_engine_action_register(engine, + "setenv", + ACTION_NON_DISRUPTIVE, + 1, 1, + NO_PLUS_MINUS, + ACTION_CARDINALITY_MANY, + ACTION_CGROUP_NONE, + NULL, + NULL, + msre_action_setenv_execute + ); + + /* setvar */ + msre_engine_action_register(engine, + "setvar", + ACTION_NON_DISRUPTIVE, + 1, 1, + NO_PLUS_MINUS, + ACTION_CARDINALITY_MANY, + ACTION_CGROUP_NONE, + NULL, + NULL, + msre_action_setvar_execute + ); + + /* expirevar */ + msre_engine_action_register(engine, + "expirevar", + ACTION_NON_DISRUPTIVE, + 1, 1, + NO_PLUS_MINUS, + ACTION_CARDINALITY_MANY, + ACTION_CGROUP_NONE, + NULL, + NULL, + msre_action_expirevar_execute + ); + + /* deprecatevar */ + msre_engine_action_register(engine, + "deprecatevar", + ACTION_NON_DISRUPTIVE, + 1, 1, + NO_PLUS_MINUS, + ACTION_CARDINALITY_MANY, + ACTION_CGROUP_NONE, + NULL, + NULL, + msre_action_deprecatevar_execute + ); + + /* initcol */ + msre_engine_action_register(engine, + "initcol", + ACTION_NON_DISRUPTIVE, + 1, 1, + NO_PLUS_MINUS, + ACTION_CARDINALITY_MANY, + ACTION_CGROUP_NONE, + NULL, + NULL, + msre_action_initcol_execute + ); + + /* setsid */ + msre_engine_action_register(engine, + "setsid", + ACTION_NON_DISRUPTIVE, + 1, 1, + NO_PLUS_MINUS, + ACTION_CARDINALITY_ONE, + ACTION_CGROUP_NONE, + NULL, + NULL, + msre_action_setsid_execute + ); + + /* setuid */ + msre_engine_action_register(engine, + "setuid", + ACTION_NON_DISRUPTIVE, + 1, 1, + NO_PLUS_MINUS, + ACTION_CARDINALITY_ONE, + ACTION_CGROUP_NONE, + NULL, + NULL, + msre_action_setuid_execute + ); + + /* exec */ + msre_engine_action_register(engine, + "exec", + ACTION_NON_DISRUPTIVE, + 1, 1, + NO_PLUS_MINUS, + ACTION_CARDINALITY_MANY, + ACTION_CGROUP_NONE, + msre_action_exec_validate, + NULL, + msre_action_exec_execute + ); + + /* multiMatch */ + msre_engine_action_register(engine, + "multiMatch", + ACTION_NON_DISRUPTIVE, + 0, 0, + NO_PLUS_MINUS, + ACTION_CARDINALITY_ONE, + ACTION_CGROUP_NONE, + NULL, + NULL, + NULL + ); + + /* tag */ + /* ENH: This should be ACTION_METADATA??? */ + msre_engine_action_register(engine, + "tag", + ACTION_NON_DISRUPTIVE, + 1, 1, + NO_PLUS_MINUS, + ACTION_CARDINALITY_MANY, + ACTION_CGROUP_NONE, + NULL, + NULL, + NULL + ); + + /* prepend */ + msre_engine_action_register(engine, + "prepend", + ACTION_NON_DISRUPTIVE, + 1, 1, + NO_PLUS_MINUS, + ACTION_CARDINALITY_ONE, + ACTION_CGROUP_NONE, + NULL, + NULL, + msre_action_prepend_execute + ); + + /* append */ + msre_engine_action_register(engine, + "append", + ACTION_NON_DISRUPTIVE, + 1, 1, + NO_PLUS_MINUS, + ACTION_CARDINALITY_ONE, + ACTION_CGROUP_NONE, + NULL, + NULL, + msre_action_append_execute + ); +} diff --git a/apache2/re_operators.c b/apache2/re_operators.c new file mode 100644 index 0000000..c4eb7cf --- /dev/null +++ b/apache2/re_operators.c @@ -0,0 +1,2108 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ +#include "re.h" +#include "msc_pcre.h" +#include "msc_geo.h" +#include "apr_lib.h" +#include "apr_strmatch.h" +#include "acmp.h" + +/** + * + */ +void msre_engine_op_register(msre_engine *engine, const char *name, + fn_op_param_init_t fn1, fn_op_execute_t fn2) +{ + msre_op_metadata *metadata = (msre_op_metadata *)apr_pcalloc(engine->mp, + sizeof(msre_op_metadata)); + if (metadata == NULL) return; + + metadata->name = name; + metadata->param_init = fn1; + metadata->execute = fn2; + apr_table_setn(engine->operators, name, (void *)metadata); +} + +/** + * + */ +msre_op_metadata *msre_engine_op_resolve(msre_engine *engine, const char *name) { + return (msre_op_metadata *)apr_table_get(engine->operators, name); +} + + + +/* -- Operators -- */ + +/* unconditionalMatch */ + +static int msre_op_unconditionalmatch_execute(modsec_rec *msr, msre_rule *rule, + msre_var *var, char **error_msg) +{ + *error_msg = "Unconditional match in SecAction."; + + /* Always match. */ + return 1; +} + +/* noMatch */ + +static int msre_op_nomatch_execute(modsec_rec *msr, msre_rule *rule, + msre_var *var, char **error_msg) +{ + *error_msg = "No match."; + + /* Never match. */ + return 0; +} + +/* rx */ + +static int msre_op_rx_param_init(msre_rule *rule, char **error_msg) { + const char *errptr = NULL; + int erroffset; + msc_regex_t *regex; + const char *pattern = rule->op_param; + + if (error_msg == NULL) return -1; + *error_msg = NULL; + + /* Compile pattern */ + regex = msc_pregcomp(rule->ruleset->mp, pattern, PCRE_DOTALL | PCRE_DOLLAR_ENDONLY, &errptr, &erroffset); + if (regex == NULL) { + *error_msg = apr_psprintf(rule->ruleset->mp, "Error compiling pattern (offset %d): %s", + erroffset, errptr); + return 0; + } + + rule->op_param_data = regex; + + return 1; /* OK */ +} + +static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + msc_regex_t *regex = (msc_regex_t *)rule->op_param_data; + const char *target; + unsigned int target_length; + char *my_error_msg = NULL; + int ovector[33]; + int capture = 0; + int rc; + + if (error_msg == NULL) return -1; + *error_msg = NULL; + + if (regex == NULL) { + *error_msg = "Internal Error: regex data is null."; + return -1; + } + + /* If the given target is null run against an empty + * string. This is a behaviour consistent with previous + * releases. + */ + if (var->value == NULL) { + target = ""; + target_length = 0; + } else { + target = var->value; + target_length = var->value_len; + } + + /* Are we supposed to capture subexpressions? */ + capture = apr_table_get(rule->actionset->actions, "capture") ? 1 : 0; + + /* Show when the regex captures but "capture" is not set */ + if (msr->txcfg->debuglog_level >= 6) { + int capcount = 0; + rc = msc_fullinfo(regex, PCRE_INFO_CAPTURECOUNT, &capcount); + if ((capture == 0) && (capcount > 0)) { + msr_log(msr, 6, "Ignoring regex captures since \"capture\" action is not enabled."); + } + } + + /* We always use capture so that ovector can be used as working space + * and no memory has to be allocated for any backreferences. + */ + rc = msc_regexec_capture(regex, target, target_length, ovector, 30, &my_error_msg); + if (rc < -1) { + *error_msg = apr_psprintf(msr->mp, "Regex execution failed: %s", my_error_msg); + return -1; + } + + /* Handle captured subexpressions. */ + if (capture && rc > 0) { + int i; + + /* Use the available captures. */ + for(i = 0; i < rc; i++) { + msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + if (s == NULL) return -1; + s->name = apr_psprintf(msr->mp, "%d", i); + s->value = apr_pstrmemdup(msr->mp, + target + ovector[2*i], ovector[2*i + 1] - ovector[2*i]); + s->value_len = (ovector[2*i + 1] - ovector[2*i]); + if ((s->name == NULL)||(s->value == NULL)) return -1; + apr_table_setn(msr->tx_vars, s->name, (void *)s); + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Added regex subexpression to TX.%d: %s", i, + log_escape_nq_ex(msr->mp, s->value, s->value_len)); + } + } + + /* Unset the remaining ones (from previous invocations). */ + for(i = rc; i <= 9; i++) { + char buf[24]; + apr_snprintf(buf, sizeof(buf), "%d", i); + apr_table_unset(msr->tx_vars, buf); + } + } + + if (rc != PCRE_ERROR_NOMATCH) { /* Match. */ + /* We no longer escape the pattern here as it is done when logging */ + char *pattern = apr_pstrdup(msr->mp, regex->pattern); + + /* This message will be logged. */ + if (strlen(pattern) > 252) { + *error_msg = apr_psprintf(msr->mp, "Pattern match \"%.252s ...\" at %s.", + pattern, var->name); + } else { + *error_msg = apr_psprintf(msr->mp, "Pattern match \"%s\" at %s.", + pattern, var->name); + } + + return 1; + } + + /* No match. */ + return 0; +} + +/* pm */ + +static int msre_op_pm_param_init(msre_rule *rule, char **error_msg) { + ACMP *p; + const char *phrase; + const char *next; + + if ((rule->op_param == NULL)||(strlen(rule->op_param) == 0)) { + *error_msg = apr_psprintf(rule->ruleset->mp, "Missing parameter for operator 'pm'."); + return 0; /* ERROR */ + } + + p = acmp_create(0, rule->ruleset->mp); + if (p == NULL) return 0; + + phrase = apr_pstrdup(rule->ruleset->mp, rule->op_param); + + /* Loop through phrases */ + /* ENH: Need to allow quoted phrases w/space */ + for (;;) { + while((apr_isspace(*phrase) != 0) && (*phrase != '\0')) phrase++; + if (*phrase == '\0') break; + next = phrase; + while((apr_isspace(*next) == 0) && (*next != 0)) next++; + acmp_add_pattern(p, phrase, NULL, NULL, next - phrase); + phrase = next; + } + acmp_prepare(p); + rule->op_param_data = p; + return 1; +} + +/* pmFromFile */ + +static int msre_op_pmFromFile_param_init(msre_rule *rule, char **error_msg) { + char errstr[1024]; + char buf[HUGE_STRING_LEN + 1]; + char *fn; + char *next; + char *ptr; + const char *rulefile_path; + apr_status_t rc; + apr_file_t *fd; + ACMP *p; + + if ((rule->op_param == NULL)||(strlen(rule->op_param) == 0)) { + *error_msg = apr_psprintf(rule->ruleset->mp, "Missing parameter for operator 'pmFromFile'."); + return 0; /* ERROR */ + } + + p = acmp_create(0, rule->ruleset->mp); + if (p == NULL) return 0; + + fn = apr_pstrdup(rule->ruleset->mp, rule->op_param); + + /* Get the path of the rule filename to use as a base */ + rulefile_path = apr_pstrndup(rule->ruleset->mp, rule->filename, strlen(rule->filename) - strlen(apr_filepath_name_get(rule->filename))); + + #ifdef DEBUG_CONF + fprintf(stderr, "Rulefile path: \"%s\"\n", rulefile_path); + #endif + + /* Loop through filenames */ + /* ENH: Need to allow quoted filenames w/space */ + for (;;) { + const char *rootpath = NULL; + const char *filepath = NULL; + int line = 0; + + /* Trim whitespace */ + while((apr_isspace(*fn) != 0) && (*fn != '\0')) fn++; + if (*fn == '\0') break; + next = fn; + while((apr_isspace(*next) == 0) && (*next != '\0')) next++; + while((apr_isspace(*next) != 0) && (*next != '\0')) *(next++) = '\0'; + + /* Add path of the rule filename for a relative phrase filename */ + filepath = fn; + if (apr_filepath_root(&rootpath, &filepath, APR_FILEPATH_TRUENAME, rule->ruleset->mp) != APR_SUCCESS) { + /* We are not an absolute path. It could mean an error, but + * let that pass through to the open call for a better error */ + apr_filepath_merge(&fn, rulefile_path, fn, APR_FILEPATH_TRUENAME, rule->ruleset->mp); + } + + /* Open file and read */ + rc = apr_file_open(&fd, fn, APR_READ | APR_FILE_NOCLEANUP, 0, rule->ruleset->mp); + if (rc != APR_SUCCESS) { + *error_msg = apr_psprintf(rule->ruleset->mp, "Could not open phrase file \"%s\": %s", fn, apr_strerror(rc, errstr, 1024)); + return 0; + } + + #ifdef DEBUG_CONF + fprintf(stderr, "Loading phrase file: \"%s\"\n", fn); + #endif + + /* Read one pattern per line skipping empty/commented */ + for(;;) { + line++; + rc = apr_file_gets(buf, HUGE_STRING_LEN, fd); + if (rc == APR_EOF) break; + if (rc != APR_SUCCESS) { + *error_msg = apr_psprintf(rule->ruleset->mp, "Could not read \"%s\" line %d: %s", fn, line, apr_strerror(rc, errstr, 1024)); + return 0; + } + + /* Remove newline */ + ptr = buf; + while(*ptr != '\0') ptr++; + if ((ptr > buf) && (*(ptr - 1) == '\n')) *(ptr - 1) = '\0'; + + /* Ignore empty lines and comments */ + ptr = buf; + while((*ptr != '\0') && apr_isspace(*ptr)) ptr++; + if ((*ptr == '\0') || (*ptr == '#')) continue; + + #ifdef DEBUG_CONF + fprintf(stderr, "Adding phrase file pattern: \"%s\"\n", buf); + #endif + + acmp_add_pattern(p, buf, NULL, NULL, strlen(buf)); + } + fn = next; + } + if (fd != NULL) apr_file_close(fd); + acmp_prepare(p); + rule->op_param_data = p; + return 1; +} + +static int msre_op_pm_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + const char *match = NULL; + apr_status_t rc = 0; + int capture; + ACMPT pt; + + /* Nothing to read */ + if ((var->value == NULL) || (var->value_len == 0)) return 0; + + /* Are we supposed to capture subexpressions? */ + capture = apr_table_get(rule->actionset->actions, "capture") ? 1 : 0; + + pt.parser = (ACMP *)rule->op_param_data; + pt.ptr = NULL; + + rc = acmp_process_quick(&pt, &match, var->value, var->value_len); + if (rc) { + char *match_escaped = log_escape(msr->mp, match ? match : ""); + + /* This message will be logged. */ + if (strlen(match_escaped) > 252) { + *error_msg = apr_psprintf(msr->mp, "Matched phrase \"%.252s ...\" at %s.", + match_escaped, var->name); + } else { + *error_msg = apr_psprintf(msr->mp, "Matched phrase \"%s\" at %s.", + match_escaped, var->name); + } + + /* Handle capture as tx.0=match */ + if (capture) { + int i; + msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + + if (s == NULL) return -1; + + s->name = "0"; + s->value = apr_pstrdup(msr->mp, match); + if (s->value == NULL) return -1; + s->value_len = strlen(s->value); + apr_table_setn(msr->tx_vars, s->name, (void *)s); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Added phrase match to TX.0: %s", + log_escape_nq_ex(msr->mp, s->value, s->value_len)); + } + + /* Unset the remaining ones (from previous invocations). */ + for(i = rc; i <= 9; i++) { + char buf[2]; + apr_snprintf(buf, sizeof(buf), "%d", i); + apr_table_unset(msr->tx_vars, buf); + } + } + + return 1; + } + return rc; +} + +/* within */ + +static int msre_op_within_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + const char *match = NULL; + const char *target; + unsigned int match_length; + unsigned int target_length = 0; + unsigned int i, i_max; + + str->value = (char *)rule->op_param; + str->value_len = strlen(str->value); + + if (error_msg == NULL) return -1; + *error_msg = NULL; + + if (str->value == NULL) { + *error_msg = "Internal Error: match string is null."; + return -1; + } + + expand_macros(msr, str, rule, msr->mp); + + match = (const char *)str->value; + match_length = str->value_len; + + /* If the given target is null we give up without a match */ + if (var->value == NULL) { + /* No match. */ + return 0; + } + + target = var->value; + target_length = var->value_len; + + /* The empty string always matches */ + if (target_length == 0) { + /* Match. */ + *error_msg = apr_psprintf(msr->mp, "String match within \"\" at %s.", + var->name); + return 1; + } + + /* This is impossible to match */ + if (target_length > match_length) { + /* No match. */ + return 0; + } + + /* scan for first character, then compare from there until we + * have a match or there is no room left in the target + */ + i_max = match_length - target_length; + for (i = 0; i <= i_max; i++) { + if (match[i] == target[0]) { + if (memcmp((target + 1), (match + i + 1), (target_length - 1)) == 0) { + /* match. */ + *error_msg = apr_psprintf(msr->mp, "String match within \"%s\" at %s.", + log_escape_ex(msr->mp, match, match_length), + var->name); + return 1; + } + } + } + + /* No match. */ + return 0; +} + +/* contains */ + +static int msre_op_contains_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + const char *match = NULL; + const char *target; + unsigned int match_length; + unsigned int target_length = 0; + unsigned int i, i_max; + + str->value = (char *)rule->op_param; + str->value_len = strlen(str->value); + + if (error_msg == NULL) return -1; + *error_msg = NULL; + + if (str->value == NULL) { + *error_msg = "Internal Error: match string is null."; + return -1; + } + + expand_macros(msr, str, rule, msr->mp); + + match = (const char *)str->value; + match_length = str->value_len; + + /* If the given target is null run against an empty + * string. This is a behaviour consistent with previous + * releases. + */ + if (var->value == NULL) { + target = ""; + target_length = 0; + } else { + target = var->value; + target_length = var->value_len; + } + + /* The empty string always matches */ + if (match_length == 0) { + /* Match. */ + *error_msg = apr_psprintf(msr->mp, "String match \"\" at %s.", var->name); + return 1; + } + + /* This is impossible to match */ + if (match_length > target_length) { + /* No match. */ + return 0; + } + + /* scan for first character, then compare from there until we + * have a match or there is no room left in the target + */ + i_max = target_length - match_length; + for (i = 0; i <= i_max; i++) { + /* First character matched - avoid func call */ + if (target[i] == match[0]) { + /* See if remaining matches */ + if ( (match_length == 1) + || (memcmp((match + 1), (target + i + 1), (match_length - 1)) == 0)) + { + /* Match. */ + *error_msg = apr_psprintf(msr->mp, "String match \"%s\" at %s.", + log_escape_ex(msr->mp, match, match_length), + var->name); + return 1; + } + } + } + + /* No match. */ + return 0; +} + +/* containsWord */ + +static int msre_op_containsWord_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + const char *match = NULL; + const char *target; + unsigned int match_length; + unsigned int target_length = 0; + unsigned int i, i_max; + int rc = 0; + + str->value = (char *)rule->op_param; + str->value_len = strlen(str->value); + + if (error_msg == NULL) return -1; + *error_msg = NULL; + + if (str->value == NULL) { + *error_msg = "Internal Error: match string is null."; + return -1; + } + + expand_macros(msr, str, rule, msr->mp); + + match = (const char *)str->value; + match_length = str->value_len; + + /* If the given target is null run against an empty + * string. This is a behaviour consistent with previous + * releases. + */ + if (var->value == NULL) { + target = ""; + target_length = 0; + } else { + target = var->value; + target_length = var->value_len; + } + + /* The empty string always matches */ + if (match_length == 0) { + /* Match. */ + *error_msg = apr_psprintf(msr->mp, "String match \"\" at %s.", var->name); + return 1; + } + + /* This is impossible to match */ + if (match_length > target_length) { + /* No match. */ + return 0; + } + + /* scan for first character, then compare from there until we + * have a match or there is no room left in the target + */ + i_max = target_length - match_length; + for (i = 0; i <= i_max; i++) { + + /* Previous char must have been a start or non-word */ + if ((i > 0) && (apr_isalnum(target[i-1])||(target[i-1] == '_'))) + continue; + + /* First character matched - avoid func call */ + if (target[i] == match[0]) { + /* See if remaining matches */ + if ( (match_length == 1) + || (memcmp((match + 1), (target + i + 1), (match_length - 1)) == 0)) + { + /* check boundaries */ + if (i == i_max) { + /* exact/end word match */ + rc = 1; + } + else if (!(apr_isalnum(target[i + match_length])||(target[i + match_length] == '_'))) { + /* start/mid word match */ + rc = 1; + } + } + } + } + + if (rc == 1) { + /* Maybe a match. */ + *error_msg = apr_psprintf(msr->mp, "String match \"%s\" at %s.", + log_escape_ex(msr->mp, match, match_length), + var->name); + return 1; + } + + /* No match. */ + *error_msg = NULL; + return 0; +} + +/* streq */ + +static int msre_op_streq_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + const char *match = NULL; + const char *target; + unsigned int match_length; + unsigned int target_length; + + str->value = (char *)rule->op_param; + str->value_len = strlen(str->value); + + if (error_msg == NULL) return -1; + *error_msg = NULL; + + if (str->value == NULL) { + *error_msg = "Internal Error: match string is null."; + return -1; + } + + expand_macros(msr, str, rule, msr->mp); + + match = (const char *)str->value; + match_length = str->value_len; + + /* If the given target is null run against an empty + * string. This is a behaviour consistent with previous + * releases. + */ + if (var->value == NULL) { + target = ""; + target_length = 0; + } else { + target = var->value; + target_length = var->value_len; + } + + /* These are impossible to match */ + if (match_length != target_length) { + /* No match. */ + return 0; + } + + if (memcmp(match, target, target_length) == 0) { + /* Match. */ + *error_msg = apr_psprintf(msr->mp, "String match \"%s\" at %s.", + log_escape_ex(msr->mp, match, match_length), + var->name); + return 1; + } + + /* No match. */ + return 0; +} + +/* beginsWith */ + +static int msre_op_beginsWith_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + const char *match = NULL; + const char *target; + unsigned int match_length; + unsigned int target_length; + + str->value = (char *)rule->op_param; + str->value_len = strlen(str->value); + + if (error_msg == NULL) return -1; + *error_msg = NULL; + + if (str->value == NULL) { + *error_msg = "Internal Error: match string is null."; + return -1; + } + + expand_macros(msr, str, rule, msr->mp); + + match = (const char *)str->value; + match_length = str->value_len; + + /* If the given target is null run against an empty + * string. This is a behaviour consistent with previous + * releases. + */ + if (var->value == NULL) { + target = ""; + target_length = 0; + } else { + target = var->value; + target_length = var->value_len; + } + + /* The empty string always matches */ + if (match_length == 0) { + /* Match. */ + *error_msg = apr_psprintf(msr->mp, "String match \"\" at %s.", var->name); + return 1; + } + + /* This is impossible to match */ + if (match_length > target_length) { + /* No match. */ + return 0; + } + + if (memcmp(match, target, match_length) == 0) { + /* Match. */ + *error_msg = apr_psprintf(msr->mp, "String match \"%s\" at %s.", + log_escape_ex(msr->mp, match, match_length), + var->name); + return 1; + } + + /* No match. */ + return 0; +} + +/* endsWith */ + +static int msre_op_endsWith_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + const char *match = NULL; + const char *target; + unsigned int match_length; + unsigned int target_length; + + str->value = (char *)rule->op_param; + str->value_len = strlen(str->value); + + if (error_msg == NULL) return -1; + *error_msg = NULL; + + if (str->value == NULL) { + *error_msg = "Internal Error: match string is null."; + return -1; + } + + expand_macros(msr, str, rule, msr->mp); + + match = (const char *)str->value; + match_length = str->value_len; + + /* If the given target is null run against an empty + * string. This is a behaviour consistent with previous + * releases. + */ + if (var->value == NULL) { + target = ""; + target_length = 0; + } else { + target = var->value; + target_length = var->value_len; + } + + /* The empty string always matches */ + if (match_length == 0) { + /* Match. */ + *error_msg = apr_psprintf(msr->mp, "String match \"\" at %s.", var->name); + return 1; + } + + /* This is impossible to match */ + if (match_length > target_length) { + /* No match. */ + return 0; + } + + if (memcmp(match, (target + (target_length - match_length)), match_length) == 0) { + /* Match. */ + *error_msg = apr_psprintf(msr->mp, "String match \"%s\" at %s.", + log_escape_ex(msr->mp, match, match_length), + var->name); + return 1; + } + + /* No match. */ + return 0; +} + +/* m */ + +static int msre_op_m_param_init(msre_rule *rule, char **error_msg) { + const apr_strmatch_pattern *compiled_pattern; + const char *pattern = rule->op_param; + + if (error_msg == NULL) return -1; + *error_msg = NULL; + + /* Compile pattern */ + compiled_pattern = apr_strmatch_precompile(rule->ruleset->mp, pattern, 1); + if (compiled_pattern == NULL) { + *error_msg = apr_psprintf(rule->ruleset->mp, "Error compiling pattern: %s", pattern); + return 0; + } + + rule->op_param_data = (void *)compiled_pattern; + + return 1; /* OK */ +} + +static int msre_op_m_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + apr_strmatch_pattern *compiled_pattern = (apr_strmatch_pattern *)rule->op_param_data; + const char *target; + unsigned int target_length; + const char *rc; + + if (error_msg == NULL) return -1; + *error_msg = NULL; + + if (compiled_pattern == NULL) { + *error_msg = "Internal Error: strnmatch data is null."; + return -1; + } + + /* If the given target is null run against an empty + * string. This is a behaviour consistent with previous + * releases. + */ + if (var->value == NULL) { + target = ""; + target_length = 0; + } else { + target = var->value; + target_length = var->value_len; + } + + rc = apr_strmatch(compiled_pattern, target, target_length); + if (rc == NULL) { + /* No match. */ + return 0; + } + + *error_msg = apr_psprintf(msr->mp, "Pattern match \"%s\" at %s.", + log_escape(msr->mp, rule->op_param), var->name); + + /* Match. */ + return 1; +} + +/* validateDTD */ + +static int msre_op_validateDTD_init(msre_rule *rule, char **error_msg) { + /* ENH Verify here the file actually exists. */ + return 1; +} + +static int msre_op_validateDTD_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, + char **error_msg) +{ + xmlValidCtxtPtr cvp; + xmlDtdPtr dtd; + + if ((msr->xml == NULL)||(msr->xml->doc == NULL)) { + *error_msg = apr_psprintf(msr->mp, + "XML document tree could not be found for DTD validation."); + return -1; + } + + if (msr->xml->well_formed != 1) { + *error_msg = apr_psprintf(msr->mp, + "XML: DTD validation failed because content is not well formed."); + return 1; + } + + /* Make sure there were no other generic processing errors */ + if (msr->msc_reqbody_error) { + *error_msg = apr_psprintf(msr->mp, + "XML: DTD validation could not proceed due to previous" + " processing errors."); + return 1; + } + + dtd = xmlParseDTD(NULL, (const xmlChar *)rule->op_param); /* EHN support relative filenames */ + if (dtd == NULL) { + *error_msg = apr_psprintf(msr->mp, "XML: Failed to load DTD: %s", rule->op_param); + return -1; + } + + cvp = xmlNewValidCtxt(); + if (cvp == NULL) { + *error_msg = "XML: Failed to create a validation context."; + xmlFreeDtd(dtd); + return -1; + } + + /* Send validator errors/warnings to msr_log */ + /* NOTE: No xmlDtdSetValidErrors()? */ + cvp->error = (xmlSchemaValidityErrorFunc)msr_log_error; + cvp->warning = (xmlSchemaValidityErrorFunc)msr_log_warn; + cvp->userData = msr; + + if (!xmlValidateDtd(cvp, msr->xml->doc, dtd)) { + *error_msg = "XML: DTD validation failed."; + xmlFreeValidCtxt(cvp); + xmlFreeDtd(dtd); + return 1; /* No match. */ + } + + msr_log(msr, 4, "XML: Successfully validated payload against DTD: %s", rule->op_param); + + xmlFreeValidCtxt(cvp); + xmlFreeDtd(dtd); + + /* Match. */ + return 0; +} + +/* validateSchema */ + +static int msre_op_validateSchema_init(msre_rule *rule, char **error_msg) { + /* ENH Verify here the file actually exists. */ + return 1; +} + +static int msre_op_validateSchema_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, + char **error_msg) +{ + xmlSchemaParserCtxtPtr parserCtx; + xmlSchemaValidCtxtPtr validCtx; + xmlSchemaPtr schema; + int rc; + + if ((msr->xml == NULL)||(msr->xml->doc == NULL)) { + *error_msg = apr_psprintf(msr->mp, + "XML document tree could not be found for schema validation."); + return -1; + } + + if (msr->xml->well_formed != 1) { + *error_msg = apr_psprintf(msr->mp, + "XML: Schema validation failed because content is not well formed."); + return 1; + } + + /* Make sure there were no other generic processing errors */ + if (msr->msc_reqbody_error) { + *error_msg = apr_psprintf(msr->mp, + "XML: Schema validation could not proceed due to previous" + " processing errors."); + return 1; + } + + parserCtx = xmlSchemaNewParserCtxt(rule->op_param); /* ENH support relative filenames */ + if (parserCtx == NULL) { + *error_msg = apr_psprintf(msr->mp, "XML: Failed to load Schema from file: %s", + rule->op_param); + return -1; + } + + /* Send parser errors/warnings to msr_log */ + xmlSchemaSetParserErrors(parserCtx, (xmlSchemaValidityErrorFunc)msr_log_error, (xmlSchemaValidityWarningFunc)msr_log_warn, msr); + + schema = xmlSchemaParse(parserCtx); + if (schema == NULL) { + *error_msg = apr_psprintf(msr->mp, "XML: Failed to load Schema: %s", rule->op_param); + xmlSchemaFreeParserCtxt(parserCtx); + return -1; + } + + validCtx = xmlSchemaNewValidCtxt(schema); + if (validCtx == NULL) { + *error_msg = "XML: Failed to create validation context."; + xmlSchemaFree(schema); + xmlSchemaFreeParserCtxt(parserCtx); + return -1; + } + + /* Send validator errors/warnings to msr_log */ + xmlSchemaSetValidErrors(validCtx, (xmlSchemaValidityErrorFunc)msr_log_error, (xmlSchemaValidityWarningFunc)msr_log_warn, msr); + + rc = xmlSchemaValidateDoc(validCtx, msr->xml->doc); + if (rc != 0) { + *error_msg = "XML: Schema validation failed."; + xmlSchemaFree(schema); + xmlSchemaFreeParserCtxt(parserCtx); + return 1; /* No match. */ + } + + msr_log(msr, 4, "XML: Successfully validated payload against Schema: %s", rule->op_param); + + xmlSchemaFree(schema); + xmlSchemaFreeValidCtxt(validCtx); + + return 0; +} + +/* verifyCC */ + +/** + * Luhn Mod-10 Method (ISO 2894/ANSI 4.13) + */ +static int luhn_verify(const char *ccnumber, int len) { + int sum[2] = { 0, 0 }; + int odd = 0; + int digits = 0; + int i; + + /* Weighted lookup table which is just a precalculated (i = index): + * i*2 + (( (i*2) > 9 ) ? -9 : 0) + */ + static int wtable[10] = {0, 2, 4, 6, 8, 1, 3, 5, 7, 9}; /* weight lookup table */ + + /* Add up only digits (weighted digits via lookup table) + * for both odd and even CC numbers to avoid 2 passes. + */ + for (i = 0; i < len; i++) { + if (apr_isdigit(ccnumber[i])) { + sum[0] += (!odd ? wtable[ccnumber[i] - '0'] : (ccnumber[i] - '0')); + sum[1] += (odd ? wtable[ccnumber[i] - '0'] : (ccnumber[i] - '0')); + odd = 1 - odd; /* alternate weights */ + digits++; + } + } + + /* No digits extracted */ + if (digits == 0) return 0; + + /* Do a mod 10 on the sum */ + sum[odd] %= 10; + + /* If the result is a zero the card is valid. */ + return sum[odd] ? 0 : 1; +} + +static int msre_op_verifyCC_init(msre_rule *rule, char **error_msg) { + const char *errptr = NULL; + int erroffset; + msc_regex_t *regex; + + if (error_msg == NULL) return -1; + *error_msg = NULL; + + /* Compile rule->op_param */ + regex = msc_pregcomp(rule->ruleset->mp, rule->op_param, PCRE_DOTALL | PCRE_MULTILINE, &errptr, &erroffset); + if (regex == NULL) { + *error_msg = apr_psprintf(rule->ruleset->mp, "Error compiling pattern (offset %d): %s", + erroffset, errptr); + return 0; + } + + rule->op_param_data = regex; + + return 1; /* OK */ +} + +static int msre_op_verifyCC_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + msc_regex_t *regex = (msc_regex_t *)rule->op_param_data; + const char *target; + unsigned int target_length; + char *my_error_msg = NULL; + int ovector[33]; + int rc; + int is_cc = 0; + int offset; + + if (error_msg == NULL) return -1; + *error_msg = NULL; + + if (regex == NULL) { + *error_msg = "Internal Error: regex data is null."; + return -1; + } + + memset(ovector, 0, sizeof(ovector)); + + /* If the given target is null run against an empty + * string. This is a behaviour consistent with previous + * releases. + */ + if (var->value == NULL) { + target = ""; + target_length = 0; + } else { + target = var->value; + target_length = var->value_len; + } + + for (offset = 0; ((unsigned int)offset < target_length) && (is_cc == 0); offset++) { + if (msr->txcfg->debuglog_level >= 9) { + if (offset > 0) { + msr_log(msr, 9, "Continuing CC# search at target offset %d.", offset); + } + } + + rc = msc_regexec_ex(regex, target, target_length, offset, PCRE_NOTEMPTY, ovector, 30, &my_error_msg); + + /* If there was no match, then we are done. */ + if (rc == PCRE_ERROR_NOMATCH) { + break; + } + + if (rc < -1) { + *error_msg = apr_psprintf(msr->mp, "CC# regex execution failed: %s", my_error_msg); + return -1; + } + + /* Verify a match. */ + if (rc > 0) { + const char *match = target + ovector[0]; + int length = ovector[1] - ovector[0]; + int i = 0; + + offset = ovector[2*i]; + + /* Check the Luhn using the match string */ + is_cc = luhn_verify(match, length); + + /* Not a CC number, then try another match where we left off. */ + if (!is_cc) { + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "CC# Luhn check failed at target offset %d: \"%.*s\"", offset, length, match); + } + + continue; + } + + /* We have a potential CC number and need to set any captures + * and we are done. + */ + + if (apr_table_get(rule->actionset->actions, "capture")) { + for(; i < rc; i++) { + msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + if (s == NULL) return -1; + s->name = apr_psprintf(msr->mp, "%d", i); + s->value = apr_pstrmemdup(msr->mp, match, length); + s->value_len = length; + if ((s->name == NULL)||(s->value == NULL)) return -1; + + apr_table_setn(msr->tx_vars, s->name, (void *)s); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Added regex subexpression to TX.%d: %s", i, + log_escape_nq_ex(msr->mp, s->value, s->value_len)); + } + } + } + + /* Unset the remaining TX vars (from previous invocations). */ + for(; i <= 9; i++) { + char buf[24]; + apr_snprintf(buf, sizeof(buf), "%i", i); + apr_table_unset(msr->tx_vars, buf); + } + + break; + } + } + + if (is_cc) { + /* Match. */ + + /* This message will be logged. */ + *error_msg = apr_psprintf(msr->mp, "CC# match \"%s\" at %s. [offset \"%d\"]", + regex->pattern, var->name, offset); + + return 1; + } + + /* No match. */ + return 0; +} + + +/** + * Perform geograpical lookups on an IP/Host. + */ +static int msre_op_geoLookup_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, + char **error_msg) +{ + geo_rec rec; + geo_db *geo = msr->txcfg->geo; + const char *geo_host = var->value; + msc_string *s = NULL; + int rc; + + *error_msg = NULL; + + if (geo == NULL) { + msr_log(msr, 1, "Geo lookup for \"%s\" attempted without a database. Set SecGeoLookupDB.", log_escape(msr->mp, geo_host)); + return 0; + } + + + rc = geo_lookup(msr, &rec, geo_host, error_msg); + if (rc <= 0) { + if (! *error_msg) { + *error_msg = apr_psprintf(msr->mp, "Geo lookup for \"%s\" failed at %s.", log_escape_nq(msr->mp, geo_host), var->name); + } + apr_table_clear(msr->geo_vars); + return rc; + } + if (! *error_msg) { + *error_msg = apr_psprintf(msr->mp, "Geo lookup for \"%s\" succeeded at %s.", + log_escape_nq(msr->mp, geo_host), var->name); + } + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "GEO: %s={country_code=%s, country_code3=%s, country_name=%s, country_continent=%s, region=%s, city=%s, postal_code=%s, latitude=%f, longitude=%f, dma_code=%d, area_code=%d}", + geo_host, + rec.country_code, + rec.country_code3, + rec.country_name, + rec.country_continent, + rec.region, + rec.city, + rec.postal_code, + rec.latitude, + rec.longitude, + rec.dma_code, + rec.area_code); + } + + s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + s->name = apr_pstrdup(msr->mp, "COUNTRY_CODE"); + s->name_len = strlen(s->name); + s->value = apr_pstrdup(msr->mp, rec.country_code ? rec.country_code : ""); + s->value_len = strlen(s->value); + apr_table_setn(msr->geo_vars, s->name, (void *)s); + + s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + s->name = apr_pstrdup(msr->mp, "COUNTRY_CODE3"); + s->name_len = strlen(s->name); + s->value = apr_pstrdup(msr->mp, rec.country_code3 ? rec.country_code3 : ""); + s->value_len = strlen(s->value); + apr_table_setn(msr->geo_vars, s->name, (void *)s); + + s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + s->name = apr_pstrdup(msr->mp, "COUNTRY_NAME"); + s->name_len = strlen(s->name); + s->value = apr_pstrdup(msr->mp, rec.country_name ? rec.country_name : ""); + s->value_len = strlen(s->value); + apr_table_setn(msr->geo_vars, s->name, (void *)s); + + s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + s->name = apr_pstrdup(msr->mp, "COUNTRY_CONTINENT"); + s->name_len = strlen(s->name); + s->value = apr_pstrdup(msr->mp, rec.country_continent ? rec.country_continent : ""); + s->value_len = strlen(s->value); + apr_table_setn(msr->geo_vars, s->name, (void *)s); + + s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + s->name = apr_pstrdup(msr->mp, "REGION"); + s->name_len = strlen(s->name); + s->value = apr_pstrdup(msr->mp, rec.region ? rec.region : ""); + s->value_len = strlen(s->value); + apr_table_setn(msr->geo_vars, s->name, (void *)s); + + s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + s->name = apr_pstrdup(msr->mp, "CITY"); + s->name_len = strlen(s->name); + s->value = apr_pstrdup(msr->mp, rec.city ? rec.city : ""); + s->value_len = strlen(s->value); + apr_table_setn(msr->geo_vars, s->name, (void *)s); + + s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + s->name = apr_pstrdup(msr->mp, "POSTAL_CODE"); + s->name_len = strlen(s->name); + s->value = apr_pstrdup(msr->mp, rec.postal_code ? rec.postal_code : ""); + s->value_len = strlen(s->value); + apr_table_setn(msr->geo_vars, s->name, (void *)s); + + s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + s->name = apr_pstrdup(msr->mp, "LATITUDE"); + s->name_len = strlen(s->name); + s->value = apr_psprintf(msr->mp, "%f", rec.latitude); + s->value_len = strlen(s->value); + apr_table_setn(msr->geo_vars, s->name, (void *)s); + + s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + s->name = apr_pstrdup(msr->mp, "LONGITUDE"); + s->name_len = strlen(s->name); + s->value = apr_psprintf(msr->mp, "%f", rec.longitude); + s->value_len = strlen(s->value); + apr_table_setn(msr->geo_vars, s->name, (void *)s); + + s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + s->name = apr_pstrdup(msr->mp, "DMA_CODE"); + s->name_len = strlen(s->name); + s->value = apr_psprintf(msr->mp, "%d", rec.dma_code); + s->value_len = strlen(s->value); + apr_table_setn(msr->geo_vars, s->name, (void *)s); + + s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + s->name = apr_pstrdup(msr->mp, "AREA_CODE"); + s->name_len = strlen(s->name); + s->value = apr_psprintf(msr->mp, "%d", rec.area_code); + s->value_len = strlen(s->value); + apr_table_setn(msr->geo_vars, s->name, (void *)s); + + return 1; +} + +/* rbl */ + +static int msre_op_rbl_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + unsigned int h0, h1, h2, h3; + char *name_to_check = NULL; + char *target = NULL; + apr_sockaddr_t *sa = NULL; + apr_status_t rc; + + if (error_msg == NULL) return -1; + *error_msg = NULL; + + /* ENH Add IPv6 support. */ + + target = apr_pstrmemdup(msr->mp, var->value, var->value_len); + if (target == NULL) return -1; + + /* Construct the host name we want to resolve. */ + if (sscanf(target, "%d.%d.%d.%d", &h0, &h1, &h2, &h3) == 4) { + /* IPv4 address */ + name_to_check = apr_psprintf(msr->mp, "%d.%d.%d.%d.%s", h3, h2, h1, h0, rule->op_param); + } else { + /* Assume the input is a domain name. */ + name_to_check = apr_psprintf(msr->mp, "%s.%s", target, rule->op_param); + } + + if (name_to_check == NULL) return -1; + + rc = apr_sockaddr_info_get(&sa, name_to_check, + APR_UNSPEC/*msr->r->connection->remote_addr->family*/, 0, 0, msr->mp); + if (rc == APR_SUCCESS) { + *error_msg = apr_psprintf(msr->r->pool, "RBL lookup of %s succeeded at %s.", + log_escape_nq(msr->mp, name_to_check), var->name); + return 1; /* Match. */ + } + + msr_log(msr, 5, "RBL lookup of %s failed at %s.", log_escape_nq(msr->mp, name_to_check), var->name); + + /* No match. */ + return 0; +} + +/* inspectFile */ + +static int msre_op_inspectFile_init(msre_rule *rule, char **error_msg) { + char *filename = (char *)rule->op_param; + + if (error_msg == NULL) return -1; + *error_msg = NULL; + + if ((filename == NULL)||(is_empty_string(filename))) { + *error_msg = apr_psprintf(rule->ruleset->mp, "Operator @inspectFile requires parameter."); + return -1; + } + + filename = resolve_relative_path(rule->ruleset->mp, rule->filename, filename); + + #if defined(WITH_LUA) + /* ENH Write & use string_ends(s, e). */ + if (strlen(rule->op_param) > 4) { + char *p = filename + strlen(filename) - 4; + if ((p[0] == '.')&&(p[1] == 'l')&&(p[2] == 'u')&&(p[3] == 'a')) + { + msc_script *script = NULL; + + /* Compile script. */ + *error_msg = lua_compile(&script, filename, rule->ruleset->mp); + if (*error_msg != NULL) return -1; + + rule->op_param_data = script; + } + } + #endif + + if (rule->op_param_data == NULL) { + /* ENH Verify the script exists and that we have + * the rights to execute it. + */ + } + + return 1; +} + +static int msre_op_inspectFile_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, + char **error_msg) +{ + if (error_msg == NULL) return -1; + *error_msg = NULL; + + if (rule->op_param_data == NULL) { + /* Execute externally, as native binary/shell script. */ + char *script_output = NULL; + char const *argv[5]; + const char *approver_script = rule->op_param; + const char *target_file = apr_pstrmemdup(msr->mp, var->value, var->value_len); + + msr_log(msr, 4, "Executing %s to inspect %s.", approver_script, target_file); + + argv[0] = approver_script; + argv[1] = target_file; + argv[2] = NULL; + + if (apache2_exec(msr, approver_script, (const char **)argv, &script_output) <= 0) { + *error_msg = apr_psprintf(msr->mp, "Execution of the approver script \"%s\" failed (invocation failed).", + log_escape(msr->mp, approver_script)); + return -1; + } + + if (script_output == NULL) { + *error_msg = apr_psprintf(msr->mp, "Execution of the approver script \"%s\" failed (no output).", + log_escape(msr->mp, approver_script)); + return -1; + } + + if (script_output[0] != '1') { + *error_msg = apr_psprintf(msr->mp, "File \"%s\" rejected by the approver script \"%s\": %s", + log_escape(msr->mp, target_file), log_escape(msr->mp, approver_script), + log_escape_nq(msr->mp, script_output)); + return 1; /* Match. */ + } + } + #if defined(WITH_LUA) + else { + /* Execute internally, as Lua script. */ + char *target = apr_pstrmemdup(msr->mp, var->value, var->value_len); + msc_script *script = (msc_script *)rule->op_param_data; + int rc; + + rc = lua_execute(script, target, msr, rule, error_msg); + if (rc < 0) { + /* Error. */ + return -1; + } + + return rc; + } + #endif + + /* No match. */ + return 0; +} + +/* validateByteRange */ + +static int msre_op_validateByteRange_init(msre_rule *rule, char **error_msg) { + char *p = NULL, *saveptr = NULL; + char *table = NULL, *data = NULL; + + if (error_msg == NULL) return -1; + *error_msg = NULL; + + if (rule->op_param == NULL) { + *error_msg = apr_psprintf(rule->ruleset->mp, "Missing parameter for validateByteRange."); + return -1; + } + + /* Initialise. */ + data = apr_pstrdup(rule->ruleset->mp, rule->op_param); + rule->op_param_data = apr_pcalloc(rule->ruleset->mp, 32); + if ((data == NULL)||(rule->op_param_data == NULL)) return -1; + table = rule->op_param_data; + + /* Extract parameters and update table. */ + p = apr_strtok(data, ",", &saveptr); + while(p != NULL) { + char *s = strstr(p, "-"); + if (s == NULL) { + /* Single value. */ + int x = atoi(p); + if ((x < 0)||(x > 255)) { + *error_msg = apr_psprintf(rule->ruleset->mp, "Invalid range value: %d", x); + return 0; + } + table[x>>3] = (table[x>>3] | (1 << (x & 0x7))); + } else { + /* Range. */ + int start = atoi(p); + int end = atoi(s + 1); + + if ((start < 0)||(start > 255)) { + *error_msg = apr_psprintf(rule->ruleset->mp, "Invalid range start value: %d", + start); + return 0; + } + if ((end < 0)||(end > 255)) { + *error_msg = apr_psprintf(rule->ruleset->mp, "Invalid range end value: %d", end); + return 0; + } + if (start > end) { + *error_msg = apr_psprintf(rule->ruleset->mp, "Invalid range: %d-%d", start, end); + return 0; + } + + while(start <= end) { + table[start >> 3] = (table[start >> 3] | (1 << (start & 0x7))); + start++; + } + } + + p = apr_strtok(NULL, ",", &saveptr); + } + + return 1; +} + +static int msre_op_validateByteRange_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, + char **error_msg) +{ + char *table = rule->op_param_data; + unsigned int i, count; + + if (error_msg == NULL) return -1; + *error_msg = NULL; + + if (table == NULL) { + *error_msg = apr_psprintf(msr->mp, "Internal Error: validateByteRange table not " + "initialised."); + return -1; + } + + /* Check every byte of the target to detect characters that are not allowed. */ + + count = 0; + for(i = 0; i < var->value_len; i++) { + int x = ((unsigned char *)var->value)[i]; + if (!(table[x >> 3] & (1 << (x & 0x7)))) { + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Value %d in %s outside range: %s", x, var->name, rule->op_param); + } + count++; + } + } + + if (count == 0) return 0; /* Valid - no match. */ + + *error_msg = apr_psprintf(msr->mp, "Found %d byte(s) in %s outside range: %s.", + count, var->name, rule->op_param); + + return 1; /* Invalid - match.*/ +} + +/* validateUrlEncoding */ + +static int validate_url_encoding(const char *input, long int input_length) { + int i; + + if ((input == NULL)||(input_length < 0)) return -1; + + i = 0; + while (i < input_length) { + if (input[i] == '%') { + if (i + 2 >= input_length) { + /* Not enough bytes. */ + return -3; + } + else { + /* Here we only decode a %xx combination if it is valid, + * leaving it as is otherwise. + */ + char c1 = input[i + 1]; + char c2 = input[i + 2]; + + if ( (((c1 >= '0')&&(c1 <= '9')) || ((c1 >= 'a')&&(c1 <= 'f')) || ((c1 >= 'A')&&(c1 <= 'F'))) + && (((c2 >= '0')&&(c2 <= '9')) || ((c2 >= 'a')&&(c2 <= 'f')) || ((c2 >= 'A')&&(c2 <= 'F'))) ) + { + i += 3; + } else { + /* Non-hexadecimal characters used in encoding. */ + return -2; + } + } + } else { + i++; + } + } + + return 1; +} + +static int msre_op_validateUrlEncoding_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, + char **error_msg) +{ + int rc = validate_url_encoding(var->value, var->value_len); + switch(rc) { + case 1 : + /* Encoding is valid */ + *error_msg = apr_psprintf(msr->mp, "Valid URL Encoding at %s.", var->name); + break; + case -2 : + *error_msg = apr_psprintf(msr->mp, "Invalid URL Encoding: Non-hexadecimal " + "digits used at %s.", var->name); + return 1; /* Invalid match. */ + break; + case -3 : + *error_msg = apr_psprintf(msr->mp, "Invalid URL Encoding: Not enough characters " + "at the end of input at %s.", var->name); + return 1; /* Invalid match. */ + break; + case -1 : + default : + *error_msg = apr_psprintf(msr->mp, "Invalid URL Encoding: Internal Error (rc = %d) at %s", rc, var->name); + return -1; + break; + + } + + /* No match. */ + return 0; +} + +/* validateUtf8Encoding */ + +#define UNICODE_ERROR_CHARACTERS_MISSING -1 +#define UNICODE_ERROR_INVALID_ENCODING -2 +#define UNICODE_ERROR_OVERLONG_CHARACTER -3 +#define UNICODE_ERROR_RESTRICTED_CHARACTER -4 +#define UNICODE_ERROR_DECODING_ERROR -5 + +/* NOTE: This is over-commented for ease of verification */ +static int detect_utf8_character(const unsigned char *p_read, unsigned int length) { + int unicode_len = 0; + unsigned int d = 0; + unsigned char c; + + if (p_read == NULL) return UNICODE_ERROR_DECODING_ERROR; + c = *p_read; + + /* If first byte begins with binary 0 it is single byte encoding */ + if ((c & 0x80) == 0) { + /* single byte unicode (7 bit ASCII equivilent) has no validation */ + return 1; + } + /* If first byte begins with binary 110 it is two byte encoding*/ + else if ((c & 0xE0) == 0xC0) { + /* check we have at least two bytes */ + if (length < 2) unicode_len = UNICODE_ERROR_CHARACTERS_MISSING; + /* check second byte starts with binary 10 */ + else if (((*(p_read + 1)) & 0xC0) != 0x80) unicode_len = UNICODE_ERROR_INVALID_ENCODING; + else { + unicode_len = 2; + /* compute character number */ + d = ((c & 0x1F) << 6) | (*(p_read + 1) & 0x3F); + } + } + /* If first byte begins with binary 1110 it is three byte encoding */ + else if ((c & 0xF0) == 0xE0) { + /* check we have at least three bytes */ + if (length < 3) unicode_len = UNICODE_ERROR_CHARACTERS_MISSING; + /* check second byte starts with binary 10 */ + else if (((*(p_read + 1)) & 0xC0) != 0x80) unicode_len = UNICODE_ERROR_INVALID_ENCODING; + /* check third byte starts with binary 10 */ + else if (((*(p_read + 2)) & 0xC0) != 0x80) unicode_len = UNICODE_ERROR_INVALID_ENCODING; + else { + unicode_len = 3; + /* compute character number */ + d = ((c & 0x0F) << 12) | ((*(p_read + 1) & 0x3F) << 6) | (*(p_read + 2) & 0x3F); + } + } + /* If first byte begins with binary 11110 it is four byte encoding */ + else if ((c & 0xF8) == 0xF0) { + /* restrict characters to UTF-8 range (U+0000 - U+10FFFF)*/ + if (c >= 0xF5) { + return UNICODE_ERROR_RESTRICTED_CHARACTER; + } + /* check we have at least four bytes */ + if (length < 4) unicode_len = UNICODE_ERROR_CHARACTERS_MISSING; + /* check second byte starts with binary 10 */ + else if (((*(p_read + 1)) & 0xC0) != 0x80) unicode_len = UNICODE_ERROR_INVALID_ENCODING; + /* check third byte starts with binary 10 */ + else if (((*(p_read + 2)) & 0xC0) != 0x80) unicode_len = UNICODE_ERROR_INVALID_ENCODING; + /* check forth byte starts with binary 10 */ + else if (((*(p_read + 3)) & 0xC0) != 0x80) unicode_len = UNICODE_ERROR_INVALID_ENCODING; + else { + unicode_len = 4; + /* compute character number */ + d = ((c & 0x07) << 18) | ((*(p_read + 1) & 0x3F) << 12) | ((*(p_read + 2) & 0x3F) < 6) | (*(p_read + 3) & 0x3F); + } + } + /* any other first byte is invalid (RFC 3629) */ + else { + return UNICODE_ERROR_INVALID_ENCODING; + } + + /* invalid UTF-8 character number range (RFC 3629) */ + if ((d >= 0xD800) && (d <= 0xDFFF)) { + return UNICODE_ERROR_RESTRICTED_CHARACTER; + } + + /* check for overlong */ + if ((unicode_len == 4) && (d < 0x010000)) { + /* four byte could be represented with less bytes */ + return UNICODE_ERROR_OVERLONG_CHARACTER; + } + else if ((unicode_len == 3) && (d < 0x0800)) { + /* three byte could be represented with less bytes */ + return UNICODE_ERROR_OVERLONG_CHARACTER; + } + else if ((unicode_len == 2) && (d < 0x80)) { + /* two byte could be represented with less bytes */ + return UNICODE_ERROR_OVERLONG_CHARACTER; + } + + return unicode_len; +} + +static int msre_op_validateUtf8Encoding_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, + char **error_msg) +{ + unsigned int i, bytes_left; + + bytes_left = var->value_len; + + for(i = 0; i < var->value_len;) { + int rc = detect_utf8_character((unsigned char *)&var->value[i], bytes_left); + + switch(rc) { + case UNICODE_ERROR_CHARACTERS_MISSING : + *error_msg = apr_psprintf(msr->mp, "Invalid UTF-8 encoding: " + "not enough bytes in character " + "at %s. [offset \"%d\"]", var->name, i); + return 1; + break; + case UNICODE_ERROR_INVALID_ENCODING : + *error_msg = apr_psprintf(msr->mp, "Invalid UTF-8 encoding: " + "invalid byte value in character " + "at %s. [offset \"%d\"]", var->name, i); + return 1; + break; + case UNICODE_ERROR_OVERLONG_CHARACTER : + *error_msg = apr_psprintf(msr->mp, "Invalid UTF-8 encoding: " + "overlong character detected " + "at %s. [offset \"%d\"]", var->name, i); + return 1; + break; + case UNICODE_ERROR_RESTRICTED_CHARACTER : + *error_msg = apr_psprintf(msr->mp, "Invalid UTF-8 encoding: " + "use of restricted character " + "at %s. [offset \"%d\"]", var->name, i); + return 1; + break; + case UNICODE_ERROR_DECODING_ERROR : + *error_msg = apr_psprintf(msr->mp, "Error validating UTF-8 decoding " + "at %s. [offset \"%d\"]", var->name, i); + return 1; + break; + } + + if (rc <= 0) { + *error_msg = apr_psprintf(msr->mp, "Internal error during UTF-8 validation " + "at %s.", var->name); + return 1; + } + + i += rc; + bytes_left -= rc; + } + + return 0; +} + +/* eq */ + +static int msre_op_eq_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, + char **error_msg) +{ + int left, right; + char *target = NULL; + + if ((var->value == NULL)||(rule->op_param == NULL)) { + /* NULL values do not match anything. */ + return 0; + } + + target = apr_pstrmemdup(msr->mp, var->value, var->value_len); + if (target == NULL) return -1; + left = atoi(target); + right = atoi(rule->op_param); + + if (left != right) { + /* No match. */ + return 0; + } + else { + *error_msg = apr_psprintf(msr->mp, "Operator EQ matched %d at %s.", right, var->name); + /* Match. */ + return 1; + } +} + +/* gt */ + +static int msre_op_gt_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, + char **error_msg) +{ + int left, right; + char *target = NULL; + + if ((var->value == NULL)||(rule->op_param == NULL)) { + /* NULL values do not match anything. */ + return 0; + } + + target = apr_pstrmemdup(msr->mp, var->value, var->value_len); + if (target == NULL) return -1; + left = atoi(target); + right = atoi(rule->op_param); + + if (left <= right) { + /* No match. */ + return 0; + } + else { + *error_msg = apr_psprintf(msr->mp, "Operator GT matched %d at %s.", right, var->name); + /* Match. */ + return 1; + } +} + +/* lt */ + +static int msre_op_lt_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, + char **error_msg) +{ + int left, right; + char *target = NULL; + + if ((var->value == NULL)||(rule->op_param == NULL)) { + /* NULL values do not match anything. */ + return 0; + } + + target = apr_pstrmemdup(msr->mp, var->value, var->value_len); + if (target == NULL) return -1; + left = atoi(target); + right = atoi(rule->op_param); + + if (left >= right) { + /* No match. */ + return 0; + } + else { + *error_msg = apr_psprintf(msr->mp, "Operator LT matched %d at %s.", right, var->name); + /* Match. */ + return 1; + } +} + +/* ge */ + +static int msre_op_ge_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, + char **error_msg) +{ + int left, right; + char *target = NULL; + + if ((var->value == NULL)||(rule->op_param == NULL)) { + /* NULL values do not match anything. */ + return 0; + } + + target = apr_pstrmemdup(msr->mp, var->value, var->value_len); + if (target == NULL) return -1; + left = atoi(target); + right = atoi(rule->op_param); + + if (left < right) { + /* No match. */ + return 0; + } + else { + *error_msg = apr_psprintf(msr->mp, "Operator GE matched %d at %s.", right, var->name); + /* Match. */ + return 1; + } +} + +/* le */ + +static int msre_op_le_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, + char **error_msg) +{ + int left, right; + char *target = NULL; + + if ((var->value == NULL)||(rule->op_param == NULL)) { + /* NULL values do not match anything. */ + return 0; + } + + target = apr_pstrmemdup(msr->mp, var->value, var->value_len); + if (target == NULL) return -1; + left = atoi(target); + right = atoi(rule->op_param); + + if (left > right) { + /* No match. */ + return 0; + } + else { + *error_msg = apr_psprintf(msr->mp, "Operator LE matched %d at %s.", right, var->name); + /* Match. */ + return 1; + } +} + +/* ------------------------------------------------------------------------------- */ + +/** + * + */ +void msre_engine_register_default_operators(msre_engine *engine) { + /* unconditionalMatch */ + msre_engine_op_register(engine, + "unconditionalMatch", + NULL, + msre_op_unconditionalmatch_execute + ); + + /* noMatch */ + msre_engine_op_register(engine, + "noMatch", + NULL, + msre_op_nomatch_execute + ); + + /* rx */ + msre_engine_op_register(engine, + "rx", + msre_op_rx_param_init, + msre_op_rx_execute + ); + + /* pm */ + msre_engine_op_register(engine, + "pm", + msre_op_pm_param_init, + msre_op_pm_execute + ); + + /* pmFromFile */ + msre_engine_op_register(engine, + "pmFromFile", + msre_op_pmFromFile_param_init, + msre_op_pm_execute + ); + + /* within */ + msre_engine_op_register(engine, + "within", + NULL, /* ENH init function to flag var substitution */ + msre_op_within_execute + ); + + /* contains */ + msre_engine_op_register(engine, + "contains", + NULL, /* ENH init function to flag var substitution */ + msre_op_contains_execute + ); + + /* containsWord */ + msre_engine_op_register(engine, + "containsWord", + NULL, /* ENH init function to flag var substitution */ + msre_op_containsWord_execute + ); + + /* is */ + msre_engine_op_register(engine, + "streq", + NULL, /* ENH init function to flag var substitution */ + msre_op_streq_execute + ); + + /* beginsWith */ + msre_engine_op_register(engine, + "beginsWith", + NULL, /* ENH init function to flag var substitution */ + msre_op_beginsWith_execute + ); + + /* endsWith */ + msre_engine_op_register(engine, + "endsWith", + NULL, /* ENH init function to flag var substitution */ + msre_op_endsWith_execute + ); + + /* m */ + msre_engine_op_register(engine, + "m", + msre_op_m_param_init, + msre_op_m_execute + ); + + /* validateDTD */ + msre_engine_op_register(engine, + "validateDTD", + msre_op_validateDTD_init, + msre_op_validateDTD_execute + ); + + /* validateSchema */ + msre_engine_op_register(engine, + "validateSchema", + msre_op_validateSchema_init, + msre_op_validateSchema_execute + ); + + /* verifyCC */ + msre_engine_op_register(engine, + "verifyCC", + msre_op_verifyCC_init, + msre_op_verifyCC_execute + ); + + /* geoLookup */ + msre_engine_op_register(engine, + "geoLookup", + NULL, + msre_op_geoLookup_execute + ); + + /* rbl */ + msre_engine_op_register(engine, + "rbl", + NULL, /* ENH init function to validate DNS server */ + msre_op_rbl_execute + ); + + /* inspectFile */ + msre_engine_op_register(engine, + "inspectFile", + msre_op_inspectFile_init, + msre_op_inspectFile_execute + ); + + /* validateByteRange */ + msre_engine_op_register(engine, + "validateByteRange", + msre_op_validateByteRange_init, + msre_op_validateByteRange_execute + ); + + /* validateUrlEncoding */ + msre_engine_op_register(engine, + "validateUrlEncoding", + NULL, + msre_op_validateUrlEncoding_execute + ); + + /* validateUtf8Encoding */ + msre_engine_op_register(engine, + "validateUtf8Encoding", + NULL, + msre_op_validateUtf8Encoding_execute + ); + + /* eq */ + msre_engine_op_register(engine, + "eq", + NULL, + msre_op_eq_execute + ); + + /* gt */ + msre_engine_op_register(engine, + "gt", + NULL, + msre_op_gt_execute + ); + + /* lt */ + msre_engine_op_register(engine, + "lt", + NULL, + msre_op_lt_execute + ); + + /* le */ + msre_engine_op_register(engine, + "le", + NULL, + msre_op_le_execute + ); + + /* ge */ + msre_engine_op_register(engine, + "ge", + NULL, + msre_op_ge_execute + ); +} diff --git a/apache2/re_tfns.c b/apache2/re_tfns.c new file mode 100644 index 0000000..79d80cb --- /dev/null +++ b/apache2/re_tfns.c @@ -0,0 +1,778 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ +#include + +#include "apr_md5.h" +#include "apr_sha1.h" +#include "apr_base64.h" + +#include "re.h" +#include "msc_util.h" + +/* lowercase */ + +static int msre_fn_lowercase_execute(apr_pool_t *mptmp, unsigned char *input, + long int input_len, char **rval, long int *rval_len) +{ + long int i; + int changed = 0; + + if (rval == NULL) return -1; + *rval = NULL; + + i = 0; + while(i < input_len) { + int x = input[i]; + input[i] = tolower(x); + if (x != input[i]) changed = 1; + i++; + } + + *rval = (char *)input; + *rval_len = input_len; + + return changed; +} + +/* trimLeft */ + +static int msre_fn_trimLeft_execute(apr_pool_t *mptmp, unsigned char *input, + long int input_len, char **rval, long int *rval_len) +{ + long int i; + + *rval = (char *)input; + for (i = 0; i < input_len; i++) { + if (isspace(**rval) == 0) { + break; + } + (*rval)++; + } + + *rval_len = input_len - i; + + return (*rval_len == input_len ? 0 : 1); +} + +/* trimRight */ + +static int msre_fn_trimRight_execute(apr_pool_t *mptmp, unsigned char *input, + long int input_len, char **rval, long int *rval_len) +{ + long int i; + + *rval = (char *)input; + for (i = input_len - 1; i >= 0; i--) { + if (isspace((*rval)[i]) == 0) { + break; + } + (*rval)[i] = '\0'; + } + + *rval_len = i + 1; + + return (*rval_len == input_len ? 0 : 1); +} + +/* trim */ + +static int msre_fn_trim_execute(apr_pool_t *mptmp, unsigned char *input, + long int input_len, char **rval, long int *rval_len) +{ + int rc = 0; + + rc = msre_fn_trimLeft_execute(mptmp, input, input_len, rval, rval_len); + if (rc == 1) { + rc = msre_fn_trimRight_execute(mptmp, (unsigned char *)*rval, *rval_len, rval, rval_len); + } + else { + rc = msre_fn_trimRight_execute(mptmp, input, input_len, rval, rval_len); + } + + return (*rval_len == input_len ? 0 : 1); +} + +/* removeNulls */ + +static int msre_fn_removeNulls_execute(apr_pool_t *mptmp, unsigned char *input, + long int input_len, char **rval, long int *rval_len) +{ + long int i, j; + int changed = 0; + + i = j = 0; + while(i < input_len) { + if (input[i] == '\0') { + changed = 1; + } else { + input[j] = input[i]; + j++; + } + i++; + } + + *rval = (char *)input; + *rval_len = j; + + return changed; +} + +/* replaceNulls */ + +static int msre_fn_replaceNulls_execute(apr_pool_t *mptmp, unsigned char *input, + long int input_len, char **rval, long int *rval_len) +{ + long int i; + int changed = 0; + + if (rval == NULL) return -1; + *rval = NULL; + + i = 0; + while(i < input_len) { + if (input[i] == '\0') { + changed = 1; + input[i] = ' '; + } + i++; + } + + *rval = (char *)input; + *rval_len = input_len; + + return changed; +} + +/* compressWhitespace */ + +static int msre_fn_compressWhitespace_execute(apr_pool_t *mptmp, unsigned char *input, + long int input_len, char **rval, long int *rval_len) +{ + long int i, j, count; + int changed = 0; + int inwhitespace = 0; + + i = j = count = 0; + while(i < input_len) { + if (isspace(input[i])||(input[i] == NBSP)) { + if (inwhitespace) changed = 1; + inwhitespace = 1; + count++; + } else { + inwhitespace = 0; + if (count) { + input[j] = ' '; + count = 0; + j++; + } + input[j] = input[i]; + j++; + } + i++; + } + + if (count) { + input[j] = ' '; + j++; + } + + *rval = (char *)input; + *rval_len = j; + + return changed; +} + +/* cssDecode */ + +static int msre_fn_cssDecode_execute(apr_pool_t *mptmp, unsigned char *input, + long int input_len, char **rval, long int *rval_len) +{ + long int length; + + length = css_decode_inplace(input, input_len); + *rval = (char *)input; + *rval_len = length; + + return (*rval_len == input_len ? 0 : 1); +} + +/* removeWhitespace */ + +static int msre_fn_removeWhitespace_execute(apr_pool_t *mptmp, unsigned char *input, + long int input_len, char **rval, long int *rval_len) +{ + long int i, j; + int changed = 0; + + i = j = 0; + while(i < input_len) { + if (isspace(input[i])||(input[i] == NBSP)) { + /* do nothing */ + changed = 1; + } else { + input[j] = input[i]; + j++; + } + i++; + } + + *rval = (char *)input; + *rval_len = j; + + return changed; +} + +/* replaceComments */ + +static int msre_fn_replaceComments_execute(apr_pool_t *mptmp, unsigned char *input, + long int input_len, char **rval, long int *rval_len) +{ + long int i, j, incomment; + int changed = 0; + + i = j = incomment = 0; + while(i < input_len) { + if (incomment == 0) { + if ((input[i] == '/')&&(i + 1 < input_len)&&(input[i + 1] == '*')) { + changed = 1; + incomment = 1; + i += 2; + } else { + input[j] = input[i]; + i++; + j++; + } + } else { + if ((input[i] == '*')&&(i + 1 < input_len)&&(input[i + 1] == '/')) { + incomment = 0; + i += 2; + input[j] = ' '; + j++; + } else { + i++; + } + } + } + + if (incomment) { + input[j++] = ' '; + } + + *rval = (char *)input; + *rval_len = j; + + return changed; +} + +/* jsDecode */ + +static int msre_fn_jsDecode_execute(apr_pool_t *mptmp, unsigned char *input, + long int input_len, char **rval, long int *rval_len) +{ + long int length; + + length = js_decode_nonstrict_inplace(input, input_len); + *rval = (char *)input; + *rval_len = length; + + return (*rval_len == input_len ? 0 : 1); +} + +/* urlDecode */ + +static int msre_fn_urlDecode_execute(apr_pool_t *mptmp, unsigned char *input, + long int input_len, char **rval, long int *rval_len) +{ + long int length; + int invalid_count; + int changed; + + length = urldecode_nonstrict_inplace_ex(input, input_len, &invalid_count, &changed); + *rval = (char *)input; + *rval_len = length; + + return changed; +} + +/* urlDecodeUni */ + +static int msre_fn_urlDecodeUni_execute(apr_pool_t *mptmp, unsigned char *input, + long int input_len, char **rval, long int *rval_len) +{ + long int length; + int changed; + + length = urldecode_uni_nonstrict_inplace_ex(input, input_len, &changed); + *rval = (char *)input; + *rval_len = length; + + return changed; +} + +/* urlEncode */ + +static int msre_fn_urlEncode_execute(apr_pool_t *mptmp, unsigned char *input, + long int input_len, char **rval, long int *rval_len) +{ + int changed; + + *rval = url_encode(mptmp, (char *)input, input_len, &changed); + *rval_len = strlen(*rval); + + return changed; +} + +/* base64Encode */ + +static int msre_fn_base64Encode_execute(apr_pool_t *mptmp, unsigned char *input, + long int input_len, char **rval, long int *rval_len) +{ + *rval_len = apr_base64_encode_len(input_len); /* returns len with NULL byte included */ + *rval = apr_palloc(mptmp, *rval_len); + apr_base64_encode(*rval, (const char *)input, input_len); + (*rval_len)--; + + return *rval_len ? 1 : 0; +} + +/* base64Decode */ + +static int msre_fn_base64Decode_execute(apr_pool_t *mptmp, unsigned char *input, + long int input_len, char **rval, long int *rval_len) +{ + *rval_len = apr_base64_decode_len((const char *)input); /* returns len with NULL byte included */ + *rval = apr_palloc(mptmp, *rval_len); + *rval_len = apr_base64_decode(*rval, (const char *)input); + + return *rval_len ? 1 : 0; +} + +/* length */ + +static int msre_fn_length_execute(apr_pool_t *mptmp, unsigned char *input, + long int input_len, char **rval, long int *rval_len) +{ + *rval = apr_psprintf(mptmp, "%ld", input_len); + *rval_len = strlen(*rval); + + return 1; +} + +/* md5 */ + +static int msre_fn_md5_execute(apr_pool_t *mptmp, unsigned char *input, + long int input_len, char **rval, long int *rval_len) +{ + unsigned char digest[APR_MD5_DIGESTSIZE]; + + apr_md5(digest, input, input_len); + + *rval_len = APR_MD5_DIGESTSIZE; + *rval = apr_pstrmemdup(mptmp, (const char *)digest, APR_MD5_DIGESTSIZE); + + return 1; +} + +/* sha1 */ + +static int msre_fn_sha1_execute(apr_pool_t *mptmp, unsigned char *input, + long int input_len, char **rval, long int *rval_len) +{ + unsigned char digest[APR_SHA1_DIGESTSIZE]; + apr_sha1_ctx_t context; + + apr_sha1_init(&context); + apr_sha1_update(&context, (const char *)input, input_len); + apr_sha1_final(digest, &context); + + *rval_len = APR_SHA1_DIGESTSIZE; + *rval = apr_pstrmemdup(mptmp, (const char *)digest, APR_SHA1_DIGESTSIZE); + + return 1; +} + +/* hexDecode */ + +static int msre_fn_hexDecode_execute(apr_pool_t *mptmp, unsigned char *input, + long int input_len, char **rval, long int *rval_len) +{ + *rval_len = hex2bytes_inplace(input, input_len); + *rval = (char *)input; + + return 1; +} + +/* hexEncode */ + +static int msre_fn_hexEncode_execute(apr_pool_t *mptmp, unsigned char *input, + long int input_len, char **rval, long int *rval_len) +{ + *rval = bytes2hex(mptmp, input, input_len); + *rval_len = strlen(*rval); + + return 1; +} + +/* htmlEntityDecode */ + +static int msre_fn_htmlEntityDecode_execute(apr_pool_t *mptmp, unsigned char *input, + long int input_len, char **rval, long int *rval_len) +{ + *rval_len = html_entities_decode_inplace(mptmp, input, input_len); + *rval = (char *)input; + + return (*rval_len == input_len ? 0 : 1); +} + +/* escapeSeqDecode */ + +static int msre_fn_escapeSeqDecode_execute(apr_pool_t *mptmp, unsigned char *input, + long int input_len, char **rval, long int *rval_len) +{ + *rval_len = ansi_c_sequences_decode_inplace(input, input_len); + *rval = (char *)input; + + return (*rval_len == input_len ? 0 : 1); +} + +/* normalisePath */ + +static int msre_fn_normalisePath_execute(apr_pool_t *mptmp, unsigned char *input, + long int input_len, char **rval, long int *rval_len) +{ + int changed; + + *rval_len = normalise_path_inplace(input, input_len, 0, &changed); + *rval = (char *)input; + + return changed; +} + +/* normalisePathWin */ + +static int msre_fn_normalisePathWin_execute(apr_pool_t *mptmp, unsigned char *input, + long int input_len, char **rval, long int *rval_len) +{ + int changed; + + *rval_len = normalise_path_inplace(input, input_len, 1, &changed); + *rval = (char *)input; + + return changed; +} + +/* parityEven7bit */ + +static int msre_fn_parityEven7bit_execute(apr_pool_t *mptmp, unsigned char *input, + long int input_len, char **rval, long int *rval_len) +{ + long int i; + int changed = 0; + + if (rval == NULL) return -1; + *rval = NULL; + + i = 0; + while(i < input_len) { + unsigned int x = input[i]; + + input[i] ^= input[i] >> 4; + input[i] &= 0xf; + + if ((0x6996 >> input[i]) & 1) { + input[i] = x | 0x80; + } + else { + input[i] = x & 0x7f; + } + + if (x != input[i]) changed = 1; + i++; + } + + *rval = (char *)input; + *rval_len = input_len; + + return changed; +} + +/* parityZero7bit */ + +static int msre_fn_parityZero7bit_execute(apr_pool_t *mptmp, unsigned char *input, + long int input_len, char **rval, long int *rval_len) +{ + long int i; + int changed = 0; + + if (rval == NULL) return -1; + *rval = NULL; + + i = 0; + while(i < input_len) { + unsigned char c = input[i]; + input[i] &= 0x7f; + if (c != input[i]) changed = 1; + i++; + } + + *rval = (char *)input; + *rval_len = input_len; + + return changed; +} + +/* parityOdd7bit */ + +static int msre_fn_parityOdd7bit_execute(apr_pool_t *mptmp, unsigned char *input, + long int input_len, char **rval, long int *rval_len) +{ + long int i; + int changed = 0; + + if (rval == NULL) return -1; + *rval = NULL; + + i = 0; + while(i < input_len) { + unsigned int x = input[i]; + + input[i] ^= input[i] >> 4; + input[i] &= 0xf; + + if ((0x6996 >> input[i]) & 1) { + input[i] = x & 0x7f; + } + else { + input[i] = x | 0x80; + } + + if (x != input[i]) changed = 1; + i++; + } + + *rval = (char *)input; + *rval_len = input_len; + + return changed; +} + +/* ------------------------------------------------------------------------------ */ + +/** + * Registers one transformation function with the engine. + */ +void msre_engine_tfn_register(msre_engine *engine, const char *name, + fn_tfn_execute_t execute) +{ + msre_tfn_metadata *metadata = (msre_tfn_metadata *)apr_pcalloc(engine->mp, + sizeof(msre_tfn_metadata)); + if (metadata == NULL) return; + + metadata->name = name; + metadata->execute = execute; + + apr_table_setn(engine->tfns, name, (void *)metadata); +} + +/** + * Returns transformation function metadata given a name. + */ +msre_tfn_metadata *msre_engine_tfn_resolve(msre_engine *engine, const char *name) { + return (msre_tfn_metadata *)apr_table_get(engine->tfns, name); +} + +/** + * Register the default transformation functions. + */ +void msre_engine_register_default_tfns(msre_engine *engine) { + + /* none */ + msre_engine_tfn_register(engine, + "none", + NULL + ); + + /* base64Decode */ + msre_engine_tfn_register(engine, + "base64Decode", + msre_fn_base64Decode_execute + ); + + /* base64Encode */ + msre_engine_tfn_register(engine, + "base64Encode", + msre_fn_base64Encode_execute + ); + + /* compressWhitespace */ + msre_engine_tfn_register(engine, + "compressWhitespace", + msre_fn_compressWhitespace_execute + ); + + /* cssDecode */ + msre_engine_tfn_register(engine, + "cssDecode", + msre_fn_cssDecode_execute + ); + + /* escapeSeqDecode */ + msre_engine_tfn_register(engine, + "escapeSeqDecode", + msre_fn_escapeSeqDecode_execute + ); + + /* hexDecode */ + msre_engine_tfn_register(engine, + "hexDecode", + msre_fn_hexDecode_execute + ); + + /* hexEncode */ + msre_engine_tfn_register(engine, + "hexEncode", + msre_fn_hexEncode_execute + ); + + /* htmlEntityDecode */ + msre_engine_tfn_register(engine, + "htmlEntityDecode", + msre_fn_htmlEntityDecode_execute + ); + + /* jsDecode */ + msre_engine_tfn_register(engine, + "jsDecode", + msre_fn_jsDecode_execute + ); + + /* length */ + msre_engine_tfn_register(engine, + "length", + msre_fn_length_execute + ); + + /* lowercase */ + msre_engine_tfn_register(engine, + "lowercase", + msre_fn_lowercase_execute + ); + + /* md5 */ + msre_engine_tfn_register(engine, + "md5", + msre_fn_md5_execute + ); + + /* normalisePath */ + msre_engine_tfn_register(engine, + "normalisePath", + msre_fn_normalisePath_execute + ); + + /* normalisePathWin */ + msre_engine_tfn_register(engine, + "normalisePathWin", + msre_fn_normalisePathWin_execute + ); + + /* parityEven7bit */ + msre_engine_tfn_register(engine, + "parityEven7bit", + msre_fn_parityEven7bit_execute + ); + + /* parityZero7bit */ + msre_engine_tfn_register(engine, + "parityZero7bit", + msre_fn_parityZero7bit_execute + ); + + /* parityOdd7bit */ + msre_engine_tfn_register(engine, + "parityOdd7bit", + msre_fn_parityOdd7bit_execute + ); + + /* removeWhitespace */ + msre_engine_tfn_register(engine, + "removeWhitespace", + msre_fn_removeWhitespace_execute + ); + + /* removeNulls */ + msre_engine_tfn_register(engine, + "removeNulls", + msre_fn_removeNulls_execute + ); + + /* replaceNulls */ + msre_engine_tfn_register(engine, + "replaceNulls", + msre_fn_replaceNulls_execute + ); + + /* replaceComments */ + msre_engine_tfn_register(engine, + "replaceComments", + msre_fn_replaceComments_execute + ); + + /* sha1 */ + msre_engine_tfn_register(engine, + "sha1", + msre_fn_sha1_execute + ); + + /* trim */ + msre_engine_tfn_register(engine, + "trim", + msre_fn_trim_execute + ); + + /* trimLeft */ + msre_engine_tfn_register(engine, + "trimLeft", + msre_fn_trimLeft_execute + ); + + /* trimRight */ + msre_engine_tfn_register(engine, + "trimRight", + msre_fn_trimRight_execute + ); + + /* urlDecode */ + msre_engine_tfn_register(engine, + "urlDecode", + msre_fn_urlDecode_execute + ); + + /* urlDecodeUni */ + msre_engine_tfn_register(engine, + "urlDecodeUni", + msre_fn_urlDecodeUni_execute + ); + + /* urlEncode */ + msre_engine_tfn_register(engine, + "urlEncode", + msre_fn_urlEncode_execute + ); +} diff --git a/apache2/re_variables.c b/apache2/re_variables.c new file mode 100644 index 0000000..b8325d5 --- /dev/null +++ b/apache2/re_variables.c @@ -0,0 +1,3140 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ +#include "http_core.h" + +#include "modsecurity.h" +#include "apache2.h" +#include "re.h" +#include "msc_util.h" + +#include "libxml/xpathInternals.h" + +/** + * Generates a variable from a string and a length. + */ +static int var_simple_generate_ex(msre_var *var, apr_table_t *vartab, apr_pool_t *mptmp, + const char *value, int value_len) +{ + msre_var *rvar = NULL; + + if (value == NULL) return 0; + + rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + rvar->value = value; + rvar->value_len = value_len; + apr_table_addn(vartab, rvar->name, (void *)rvar); + + return 1; +} + +/** + * Generates a variable from a NULL-terminated string. + */ +static int var_simple_generate(msre_var *var, apr_table_t *vartab, apr_pool_t *mptmp, + const char *value) +{ + if (value == NULL) return 0; + return var_simple_generate_ex(var, vartab, mptmp, value, strlen(value)); +} + +/** + * Validate that a target parameter is valid. We only need to take + * care of the case when the parameter is a regular expression. + */ +static char *var_generic_list_validate(msre_ruleset *ruleset, msre_var *var) { + /* It's OK if there's no parameter. */ + if (var->param == NULL) return NULL; + + /* Is it a regular expression? */ + if ((strlen(var->param) > 2)&&(var->param[0] == '/') + &&(var->param[strlen(var->param) - 1] == '/')) + { /* Regex. */ + msc_regex_t *regex = NULL; + const char *errptr = NULL; + const char *pattern = NULL; + int erroffset; + + pattern = apr_pstrmemdup(ruleset->mp, var->param + 1, strlen(var->param + 1) - 1); + if (pattern == NULL) return FATAL_ERROR; + + regex = msc_pregcomp(ruleset->mp, pattern, PCRE_DOTALL | PCRE_CASELESS | PCRE_DOLLAR_ENDONLY, &errptr, &erroffset); + if (regex == NULL) { + return apr_psprintf(ruleset->mp, "Error compiling pattern (offset %d): %s", + erroffset, errptr); + } + + /* Store the compiled regex for later. */ + var->param_data = regex; + } + + /* Simple string */ + return NULL; +} + +/* Custom parameter validation functions */ + +/* ARGS */ + +static int var_args_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + const apr_array_header_t *arr = NULL; + const apr_table_entry_t *te = NULL; + int i, count = 0; + + /* Loop through the arguments. */ + arr = apr_table_elts(msr->arguments); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + msc_arg *arg = (msc_arg *)te[i].val; + int match = 0; + + /* Figure out if we want to include this argument. */ + if (var->param == NULL) match = 1; /* Unconditional inclusion. */ + else { + if (var->param_data != NULL) { /* Regex. */ + char *my_error_msg = NULL; + /* Run the regex against the argument name. */ + if (!(msc_regexec((msc_regex_t *)var->param_data, arg->name, + arg->name_len, &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + } else { /* Simple comparison. */ + if (strcasecmp(arg->name, var->param) == 0) match = 1; + } + } + + /* If we had a match add this argument to the collection. */ + if (match) { + msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + + rvar->value = arg->value; + rvar->value_len = arg->value_len; + rvar->name = apr_psprintf(mptmp, "ARGS:%s", log_escape_nq_ex(mptmp, arg->name, arg->name_len)); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + count++; + } + } + + return count; +} + +/* ARGS_COMBINED_SIZE */ + +static int var_args_combined_size_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + const apr_array_header_t *arr = NULL; + const apr_table_entry_t *te = NULL; + unsigned int combined_size = 0; + int i; + msre_var *rvar = NULL; + + arr = apr_table_elts(msr->arguments); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + msc_arg *arg = (msc_arg *)te[i].val; + combined_size += arg->name_len; + combined_size += arg->value_len; + } + + rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + rvar->value = apr_psprintf(mptmp, "%u", combined_size); + rvar->value_len = strlen(rvar->value); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + return 1; +} + +/* ARGS_NAMES */ + +static int var_args_names_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + const apr_array_header_t *arr = NULL; + const apr_table_entry_t *te = NULL; + int i, count = 0; + + arr = apr_table_elts(msr->arguments); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + msc_arg *arg = (msc_arg *)te[i].val; + int match = 0; + + /* Figure out if we want to include this variable. */ + if (var->param == NULL) match = 1; /* Unconditional inclusion. */ + else { + if (var->param_data != NULL) { /* Regex. */ + char *my_error_msg = NULL; + if (!(msc_regexec((msc_regex_t *)var->param_data, arg->name, + arg->name_len, &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + } else { /* Simple comparison. */ + if (strcasecmp(arg->name, var->param) == 0) match = 1; + } + } + + /* If we had a match add this argument to the collection. */ + if (match) { + msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + + rvar->value = arg->name; + rvar->value_len = arg->name_len; + rvar->name = apr_psprintf(mptmp, "ARGS_NAMES:%s", log_escape_nq_ex(mptmp, arg->name, arg->name_len)); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + count++; + } + } + + return count; +} + +/* ARGS_GET */ + +static int var_args_get_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + const apr_array_header_t *arr = NULL; + const apr_table_entry_t *te = NULL; + int i, count = 0; + + /* Loop through the arguments. */ + arr = apr_table_elts(msr->arguments); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + msc_arg *arg = (msc_arg *)te[i].val; + int match = 0; + + /* Only QUERY_STRING arguments */ + if (strcmp("QUERY_STRING", arg->origin) != 0) continue; + + /* Figure out if we want to include this argument. */ + if (var->param == NULL) match = 1; /* Unconditional inclusion. */ + else { + if (var->param_data != NULL) { /* Regex. */ + char *my_error_msg = NULL; + /* Run the regex against the argument name. */ + if (!(msc_regexec((msc_regex_t *)var->param_data, arg->name, + arg->name_len, &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + } else { /* Simple comparison. */ + if (strcasecmp(arg->name, var->param) == 0) match = 1; + } + } + + /* If we had a match add this argument to the collection. */ + if (match) { + msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + + rvar->value = arg->value; + rvar->value_len = arg->value_len; + rvar->name = apr_psprintf(mptmp, "ARGS_GET:%s", log_escape_nq_ex(mptmp, arg->name, arg->name_len)); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + count++; + } + } + + return count; +} + +/* ARGS_GET_NAMES */ + +static int var_args_get_names_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + const apr_array_header_t *arr = NULL; + const apr_table_entry_t *te = NULL; + int i, count = 0; + + arr = apr_table_elts(msr->arguments); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + msc_arg *arg = (msc_arg *)te[i].val; + int match = 0; + + /* Only QUERY_STRING arguments */ + if (strcmp("QUERY_STRING", arg->origin) != 0) continue; + + /* Figure out if we want to include this variable. */ + if (var->param == NULL) match = 1; /* Unconditional inclusion. */ + else { + if (var->param_data != NULL) { /* Regex. */ + char *my_error_msg = NULL; + if (!(msc_regexec((msc_regex_t *)var->param_data, arg->name, + arg->name_len, &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + } else { /* Simple comparison. */ + if (strcasecmp(arg->name, var->param) == 0) match = 1; + } + } + + /* If we had a match add this argument to the collection. */ + if (match) { + msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + + rvar->value = arg->name; + rvar->value_len = arg->name_len; + rvar->name = apr_psprintf(mptmp, "ARGS_GET_NAMES:%s", log_escape_nq_ex(mptmp, arg->name, arg->name_len)); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + count++; + } + } + + return count; +} + +/* ARGS_POST */ + +static int var_args_post_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + const apr_array_header_t *arr = NULL; + const apr_table_entry_t *te = NULL; + int i, count = 0; + + /* Loop through the arguments. */ + arr = apr_table_elts(msr->arguments); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + msc_arg *arg = (msc_arg *)te[i].val; + int match = 0; + + /* Only BODY arguments */ + if (strcmp("BODY", arg->origin) != 0) continue; + + /* Figure out if we want to include this argument. */ + if (var->param == NULL) match = 1; /* Unconditional inclusion. */ + else { + if (var->param_data != NULL) { /* Regex. */ + char *my_error_msg = NULL; + /* Run the regex against the argument name. */ + if (!(msc_regexec((msc_regex_t *)var->param_data, arg->name, + arg->name_len, &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + } else { /* Simple comparison. */ + if (strcasecmp(arg->name, var->param) == 0) match = 1; + } + } + + /* If we had a match add this argument to the collection. */ + if (match) { + msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + + rvar->value = arg->value; + rvar->value_len = arg->value_len; + rvar->name = apr_psprintf(mptmp, "ARGS_POST:%s", log_escape_nq_ex(mptmp, arg->name, arg->name_len)); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + count++; + } + } + + return count; +} + +/* ARGS_POST_NAMES */ + +static int var_args_post_names_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + const apr_array_header_t *arr = NULL; + const apr_table_entry_t *te = NULL; + int i, count = 0; + + arr = apr_table_elts(msr->arguments); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + msc_arg *arg = (msc_arg *)te[i].val; + int match = 0; + + /* Only BODY arguments */ + if (strcmp("BODY", arg->origin) != 0) continue; + + /* Figure out if we want to include this variable. */ + if (var->param == NULL) match = 1; /* Unconditional inclusion. */ + else { + if (var->param_data != NULL) { /* Regex. */ + char *my_error_msg = NULL; + if (!(msc_regexec((msc_regex_t *)var->param_data, arg->name, + arg->name_len, &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + } else { /* Simple comparison. */ + if (strcasecmp(arg->name, var->param) == 0) match = 1; + } + } + + /* If we had a match add this argument to the collection. */ + if (match) { + msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + + rvar->value = arg->name; + rvar->value_len = arg->name_len; + rvar->name = apr_psprintf(mptmp, "ARGS_POST_NAMES:%s", log_escape_nq_ex(mptmp, arg->name, arg->name_len)); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + count++; + } + } + + return count; +} + +/* RULE */ + +static int var_rule_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + msre_actionset *actionset = NULL; + + if (rule == NULL) return 0; + actionset = rule->actionset; + if (rule->chain_starter != NULL) actionset = rule->chain_starter->actionset; + + if ((strcasecmp(var->param, "id") == 0)&&(actionset->id != NULL)) { + return var_simple_generate(var, vartab, mptmp, actionset->id); + } else + if ((strcasecmp(var->param, "rev") == 0)&&(actionset->rev != NULL)) { + return var_simple_generate(var, vartab, mptmp, actionset->rev); + } else + if ((strcasecmp(var->param, "severity") == 0)&&(actionset->severity != -1)) { + char *value = apr_psprintf(mptmp, "%d", actionset->severity); + return var_simple_generate(var, vartab, mptmp, value); + } else + if ((strcasecmp(var->param, "msg") == 0)&&(actionset->msg != NULL)) { + return var_simple_generate(var, vartab, mptmp, actionset->msg); + } else + if ((strcasecmp(var->param, "logdata") == 0)&&(actionset->logdata != NULL)) { + return var_simple_generate(var, vartab, mptmp, actionset->logdata); + } + + return 0; +} + +/* ENV */ + +static char *var_env_validate(msre_ruleset *ruleset, msre_var *var) { + if (var->param == NULL) { + return apr_psprintf(ruleset->mp, "Parameter required for ENV."); + } + if ((strlen(var->param) > 2)&&(var->param[0] == '/') + &&(var->param[strlen(var->param) - 1] == '/')) + { + return apr_psprintf(ruleset->mp, "Regular expressions not supported in ENV."); + } + return NULL; +} + +static int var_env_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + char *value = get_env_var(msr->r, (char *)var->param); + if (value != NULL) { + return var_simple_generate(var, vartab, mptmp, value); + } + return 0; +} + +/* REQUEST_URI_RAW */ + +static int var_request_uri_raw_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + return var_simple_generate(var, vartab, mptmp, msr->r->unparsed_uri); +} + +/* REQUEST_URI */ + +static int var_request_uri_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) /* dynamic */ +{ + char *value = NULL; + + if (msr->r->parsed_uri.query == NULL) value = msr->r->parsed_uri.path; + else value = apr_pstrcat(mptmp, msr->r->parsed_uri.path, "?", msr->r->parsed_uri.query, NULL); + + return var_simple_generate(var, vartab, mptmp, value); +} + +/* REQBODY_PROCESSOR */ + +static int var_reqbody_processor_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + + if (msr->msc_reqbody_processor == NULL) { + rvar->value = apr_pstrdup(mptmp, ""); + rvar->value_len = 0; + } else { + rvar->value = apr_pstrdup(mptmp, msr->msc_reqbody_processor); + rvar->value_len = strlen(rvar->value); + } + + apr_table_addn(vartab, rvar->name, (void *)rvar); + + return 1; +} + +/* REQBODY_ERROR */ + +static int var_reqbody_processor_error_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + + rvar->value = apr_psprintf(mptmp, "%d", msr->msc_reqbody_error); + rvar->value_len = strlen(rvar->value); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + return 1; +} + +/* REQBODY_ERROR_MSG */ + +static int var_reqbody_processor_error_msg_generate(modsec_rec *msr, msre_var *var, + msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) +{ + msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + + if (msr->msc_reqbody_error_msg == NULL) { + rvar->value = apr_pstrdup(mptmp, ""); + rvar->value_len = 0; + } else { + rvar->value = apr_psprintf(mptmp, "%s", msr->msc_reqbody_error_msg); + rvar->value_len = strlen(rvar->value); + } + + apr_table_addn(vartab, rvar->name, (void *)rvar); + + return 1; +} + +/* XML */ + +static char *var_xml_validate(msre_ruleset *ruleset, msre_var *var) { + /* It's OK if there's no parameter. */ + if (var->param == NULL) return NULL; + + /* ENH validate XPath expression in advance. */ + + return NULL; +} + +static int var_xml_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + const apr_array_header_t *tarr; + const apr_table_entry_t *telts; + xmlXPathContextPtr xpathCtx; + xmlXPathObjectPtr xpathObj; + xmlNodeSetPtr nodes; + const xmlChar* xpathExpr = NULL; + int i, count; + + /* Is there an XML document tree at all? */ + if ((msr->xml == NULL)||(msr->xml->doc == NULL)) { + /* Sorry, we've got nothing to give! */ + return 0; + } + + if (var->param == NULL) { + /* Invocation without an XPath expression makes sense + * with functions that manipulate the document tree. + */ + msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + + rvar->value = apr_pstrdup(mptmp, "[XML document tree]"); + rvar->value_len = strlen(rvar->value); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + return 1; + } + + /* Process the XPath expression. */ + + count = 0; + xpathExpr = (const xmlChar*)var->param; + + xpathCtx = xmlXPathNewContext(msr->xml->doc); + if (xpathCtx == NULL) { + msr_log(msr, 1, "XML: Unable to create new XPath context."); + return -1; + } + + /* Look through the actionset of the associated rule + * for the namespace information. Register them if any are found. + */ + tarr = apr_table_elts(rule->actionset->actions); + telts = (const apr_table_entry_t*)tarr->elts; + for (i = 0; i < tarr->nelts; i++) { + msre_action *action = (msre_action *)telts[i].val; + + if (strcasecmp(action->metadata->name, "xmlns") == 0) { + char *prefix, *href; + + if (parse_name_eq_value(mptmp, action->param, &prefix, &href) < 0) return -1; + if ((prefix == NULL)||(href == NULL)) return -1; + + if(xmlXPathRegisterNs(xpathCtx, (const xmlChar*)prefix, (const xmlChar*)href) != 0) { + msr_log(msr, 1, "Failed to register XML namespace href \"%s\" prefix \"%s\".", + log_escape(mptmp, prefix), log_escape(mptmp, href)); + return -1; + } + + msr_log(msr, 4, "Registered XML namespace href \"%s\" prefix \"%s\".", + log_escape(mptmp, prefix), log_escape(mptmp, href)); + } + } + + /* Initialise XPath expression. */ + xpathObj = xmlXPathEvalExpression(xpathExpr, xpathCtx); + if (xpathObj == NULL) { + msr_log(msr, 1, "XML: Unable to evaluate xpath expression."); + xmlXPathFreeContext(xpathCtx); + return -1; + } + + /* Evaluate XPath expression. */ + nodes = xpathObj->nodesetval; + if (nodes == NULL) { + xmlXPathFreeObject(xpathObj); + xmlXPathFreeContext(xpathCtx); + return 0; + } + + /* Create one variable for each node in the result. */ + for(i = 0; i < nodes->nodeNr; i++) { + msre_var *rvar = NULL; + char *content = NULL; + + content = (char *)xmlNodeGetContent(nodes->nodeTab[i]); + if (content != NULL) { + rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + rvar->value = apr_pstrdup(mptmp, content); + xmlFree(content); + rvar->value_len = strlen(rvar->value); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + count++; + } + } + + xmlXPathFreeObject(xpathObj); + xmlXPathFreeContext(xpathCtx); + + return count; +} + +/* WEBSERVER_ERROR_LOG */ + +static int var_webserver_error_log_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + msre_var *rvar = NULL; + int i, count = 0; + + for(i = 0; i < msr->error_messages->nelts; i++) { + error_message *em = (((error_message**)msr->error_messages->elts)[i]); + char *fem = NULL; + + fem = format_error_log_message(mptmp, em); + if (fem != NULL) { + rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + rvar->value = apr_pstrdup(mptmp, fem); + rvar->value_len = strlen(rvar->value); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + count++; + } + } + + return count; +} + +/* REMOTE_ADDR */ + +static int var_remote_addr_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + return var_simple_generate(var, vartab, mptmp, msr->remote_addr); +} + +/* REMOTE_HOST */ + +static int var_remote_host_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + const char *value1 = ap_get_remote_host(msr->r->connection, msr->r->per_dir_config, + REMOTE_NAME, NULL); + return var_simple_generate(var, vartab, mptmp, value1); +} + +/* REMOTE_PORT */ + +static int var_remote_port_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + char *value = apr_psprintf(mptmp, "%u", msr->remote_port); + return var_simple_generate(var, vartab, mptmp, value); +} + +/* REMOTE_USER */ + +static int var_remote_user_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + return var_simple_generate(var, vartab, mptmp, msr->remote_user); +} + +/* TX */ + +static int var_tx_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + const apr_array_header_t *arr = NULL; + const apr_table_entry_t *te = NULL; + int i, count = 0; + + arr = apr_table_elts(msr->tx_vars); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + msc_string *str = (msc_string *)te[i].val; + int match; + + /* Figure out if we want to include this variable. */ + match = 0; + if (var->param == NULL) match = 1; /* Unconditional inclusion. */ + else { + if (var->param_data != NULL) { /* Regex. */ + char *my_error_msg = NULL; + if (!(msc_regexec((msc_regex_t *)var->param_data, str->name, + str->name_len, &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + } else { /* Simple comparison. */ + if (strcasecmp(str->name, var->param) == 0) match = 1; + } + } + + /* If we had a match add this argument to the collection. */ + if (match) { + msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + + rvar->value = str->value; + rvar->value_len = str->value_len; + rvar->name = apr_psprintf(mptmp, "TX:%s", log_escape_nq_ex(mptmp, str->name, str->name_len)); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + count++; + } + } + + return count; +} + +/* GEO */ + +static int var_geo_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + const apr_array_header_t *arr = NULL; + const apr_table_entry_t *te = NULL; + int i, count = 0; + + arr = apr_table_elts(msr->geo_vars); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + msc_string *str = (msc_string *)te[i].val; + int match; + + /* Figure out if we want to include this variable. */ + match = 0; + if (var->param == NULL) match = 1; /* Unconditional inclusion. */ + else { + if (var->param_data != NULL) { /* Regex. */ + char *my_error_msg = NULL; + if (!(msc_regexec((msc_regex_t *)var->param_data, str->name, + str->name_len, &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + } else { /* Simple comparison. */ + if (strcasecmp(str->name, var->param) == 0) match = 1; + } + } + + /* If we had a match add this argument to the collection. */ + if (match) { + msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + + rvar->value = str->value; + rvar->value_len = str->value_len; + rvar->name = apr_psprintf(mptmp, "GEO:%s", log_escape_nq_ex(mptmp, str->name, str->name_len)); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + count++; + } + } + + return count; +} + +/* HIGHEST_SEVERITY */ + +static int var_highest_severity_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + return var_simple_generate(var, vartab, mptmp, + apr_psprintf(mptmp, "%d", msr->highest_severity)); +} + +/* IP */ + +static int var_ip_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + const apr_array_header_t *arr = NULL; + const apr_table_entry_t *te = NULL; + int i, count = 0; + apr_table_t *target_col = NULL; + + target_col = (apr_table_t *)apr_table_get(msr->collections, "ip"); + if (target_col == NULL) return 0; + + arr = apr_table_elts(target_col); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + msc_string *str = (msc_string *)te[i].val; + int match; + + /* Figure out if we want to include this variable. */ + match = 0; + if (var->param == NULL) match = 1; /* Unconditional inclusion. */ + else { + if (var->param_data != NULL) { /* Regex. */ + char *my_error_msg = NULL; + if (!(msc_regexec((msc_regex_t *)var->param_data, str->name, + str->name_len, &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + } else { /* Simple comparison. */ + if (strcasecmp(str->name, var->param) == 0) match = 1; + } + } + + /* If we had a match add this argument to the collection. */ + if (match) { + msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + + rvar->value = str->value; + rvar->value_len = str->value_len; + rvar->name = apr_psprintf(mptmp, "IP:%s", log_escape_nq_ex(mptmp, str->name, str->name_len)); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + count++; + } + } + + return count; +} + +/* MATCHED_VAR */ + +static int var_matched_var_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + return var_simple_generate_ex(var, vartab, mptmp, + apr_pmemdup(mptmp, + msr->matched_var->value, + msr->matched_var->value_len), + msr->matched_var->value_len); +} + +/* MATCHED_VAR_NAME */ + +static int var_matched_var_name_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + return var_simple_generate_ex(var, vartab, mptmp, + apr_pmemdup(mptmp, + msr->matched_var->name, + msr->matched_var->name_len), + msr->matched_var->name_len); +} + +/* SESSION */ + +static int var_session_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + const apr_array_header_t *arr = NULL; + const apr_table_entry_t *te = NULL; + int i, count = 0; + apr_table_t *target_col = NULL; + + target_col = (apr_table_t *)apr_table_get(msr->collections, "session"); + if (target_col == NULL) return 0; + + arr = apr_table_elts(target_col); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + msc_string *str = (msc_string *)te[i].val; + int match; + + /* Figure out if we want to include this variable. */ + match = 0; + if (var->param == NULL) match = 1; /* Unconditional inclusion. */ + else { + if (var->param_data != NULL) { /* Regex. */ + char *my_error_msg = NULL; + if (!(msc_regexec((msc_regex_t *)var->param_data, str->name, + str->name_len, &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + } else { /* Simple comparison. */ + if (strcasecmp(str->name, var->param) == 0) match = 1; + } + } + + /* If we had a match add this argument to the collection. */ + if (match) { + msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + + rvar->value = str->value; + rvar->value_len = str->value_len; + rvar->name = apr_psprintf(mptmp, "SESSION:%s", log_escape_nq_ex(mptmp, str->name, str->name_len)); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + count++; + } + } + + return count; +} + +/* USER */ + +static int var_user_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + const apr_array_header_t *arr = NULL; + const apr_table_entry_t *te = NULL; + int i, count = 0; + apr_table_t *target_col = NULL; + + target_col = (apr_table_t *)apr_table_get(msr->collections, "user"); + if (target_col == NULL) return 0; + + arr = apr_table_elts(target_col); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + msc_string *str = (msc_string *)te[i].val; + int match; + + /* Figure out if we want to include this variable. */ + match = 0; + if (var->param == NULL) match = 1; /* Unconditional match. */ + else { + if (var->param_data != NULL) { /* Regex. */ + char *my_error_msg = NULL; + if (!(msc_regexec((msc_regex_t *)var->param_data, str->name, + str->name_len, &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + } else { /* Simple comparison. */ + if (strcasecmp(str->name, var->param) == 0) match = 1; + } + } + + /* If we had a match add this argument to the collection. */ + if (match) { + msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + + rvar->value = str->value; + rvar->value_len = str->value_len; + rvar->name = apr_psprintf(mptmp, "USER:%s", log_escape_nq_ex(mptmp, str->name, str->name_len)); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + count++; + } + } + + return count; +} + +/* GLOBAL */ + +static int var_global_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + const apr_array_header_t *arr = NULL; + const apr_table_entry_t *te = NULL; + int i, count = 0; + apr_table_t *target_col = NULL; + + target_col = (apr_table_t *)apr_table_get(msr->collections, "global"); + if (target_col == NULL) return 0; + + arr = apr_table_elts(target_col); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + msc_string *str = (msc_string *)te[i].val; + int match; + + /* Figure out if we want to include this variable. */ + match = 0; + if (var->param == NULL) match = 1; /* Unconditional match. */ + else { + if (var->param_data != NULL) { /* Regex. */ + char *my_error_msg = NULL; + if (!(msc_regexec((msc_regex_t *)var->param_data, str->name, + str->name_len, &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + } else { /* Simple comparison. */ + if (strcasecmp(str->name, var->param) == 0) match = 1; + } + } + + /* If we had a match add this argument to the collection. */ + if (match) { + msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + + rvar->value = str->value; + rvar->value_len = str->value_len; + rvar->name = apr_psprintf(mptmp, "GLOBAL:%s", log_escape_nq_ex(mptmp, str->name, str->name_len)); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + count++; + } + } + + return count; +} + +/* RESOURCE */ + +static int var_resource_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + const apr_array_header_t *arr = NULL; + const apr_table_entry_t *te = NULL; + int i, count = 0; + apr_table_t *target_col = NULL; + + target_col = (apr_table_t *)apr_table_get(msr->collections, "resource"); + if (target_col == NULL) return 0; + + arr = apr_table_elts(target_col); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + msc_string *str = (msc_string *)te[i].val; + int match; + + /* Figure out if we want to include this variable. */ + match = 0; + if (var->param == NULL) match = 1; /* Unconditional match. */ + else { + if (var->param_data != NULL) { /* Regex. */ + char *my_error_msg = NULL; + if (!(msc_regexec((msc_regex_t *)var->param_data, str->name, + str->name_len, &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + } else { /* Simple comparison. */ + if (strcasecmp(str->name, var->param) == 0) match = 1; + } + } + + /* If we had a match add this argument to the collection. */ + if (match) { + msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + + rvar->value = str->value; + rvar->value_len = str->value_len; + rvar->name = apr_psprintf(mptmp, "RESOURCE:%s", log_escape_nq_ex(mptmp, str->name, str->name_len)); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + count++; + } + } + + return count; +} + +/* FILES_TMPNAMES */ + +static int var_files_tmpnames_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + multipart_part **parts = NULL; + int i, count = 0; + + if (msr->mpd == NULL) return 0; + + parts = (multipart_part **)msr->mpd->parts->elts; + for(i = 0; i < msr->mpd->parts->nelts; i++) { + if ((parts[i]->type == MULTIPART_FILE)&&(parts[i]->tmp_file_name != NULL)) { + int match = 0; + + /* Figure out if we want to include this variable. */ + if (var->param == NULL) match = 1; + else { + if (var->param_data != NULL) { /* Regex. */ + char *my_error_msg = NULL; + if (!(msc_regexec((msc_regex_t *)var->param_data, parts[i]->name, + strlen(parts[i]->name), &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + } else { /* Simple comparison. */ + if (strcasecmp(parts[i]->name, var->param) == 0) match = 1; + } + } + + /* If we had a match add this argument to the collection. */ + if (match) { + msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + + rvar->value = parts[i]->tmp_file_name; + rvar->value_len = strlen(rvar->value); + rvar->name = apr_psprintf(mptmp, "FILES_TMPNAMES:%s", + log_escape_nq(mptmp, parts[i]->name)); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + count++; + } + } + } + + return count; +} + +/* FILES */ + +static int var_files_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + multipart_part **parts = NULL; + int i, count = 0; + + if (msr->mpd == NULL) return 0; + + parts = (multipart_part **)msr->mpd->parts->elts; + for(i = 0; i < msr->mpd->parts->nelts; i++) { + if (parts[i]->type == MULTIPART_FILE) { + int match = 0; + + /* Figure out if we want to include this variable. */ + if (var->param == NULL) match = 1; + else { + if (var->param_data != NULL) { /* Regex. */ + char *my_error_msg = NULL; + if (!(msc_regexec((msc_regex_t *)var->param_data, parts[i]->name, + strlen(parts[i]->name), &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + } else { /* Simple comparison. */ + if (strcasecmp(parts[i]->name, var->param) == 0) match = 1; + } + } + + /* If we had a match add this argument to the collection. */ + if (match) { + msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + + rvar->value = parts[i]->filename; + rvar->value_len = strlen(rvar->value); + rvar->name = apr_psprintf(mptmp, "FILES:%s", + log_escape_nq(mptmp, parts[i]->name)); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + count++; + } + } + } + + return count; +} + +/* FILES_SIZES */ + +static int var_files_sizes_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + multipart_part **parts = NULL; + int i, count = 0; + + if (msr->mpd == NULL) return 0; + + parts = (multipart_part **)msr->mpd->parts->elts; + for(i = 0; i < msr->mpd->parts->nelts; i++) { + if (parts[i]->type == MULTIPART_FILE) { + int match = 0; + + /* Figure out if we want to include this variable. */ + if (var->param == NULL) match = 1; + else { + if (var->param_data != NULL) { /* Regex. */ + char *my_error_msg = NULL; + if (!(msc_regexec((msc_regex_t *)var->param_data, parts[i]->name, + strlen(parts[i]->name), &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + } else { /* Simple comparison. */ + if (strcasecmp(parts[i]->name, var->param) == 0) match = 1; + } + } + + /* If we had a match add this argument to the collection. */ + if (match) { + msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + + rvar->value = apr_psprintf(mptmp, "%u", parts[i]->tmp_file_size); + rvar->value_len = strlen(rvar->value); + rvar->name = apr_psprintf(mptmp, "FILES_SIZES:%s", + log_escape_nq(mptmp, parts[i]->name)); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + count++; + } + } + } + + return count; +} + +/* FILES_NAMES */ + +static int var_files_names_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + multipart_part **parts = NULL; + int i, count = 0; + + if (msr->mpd == NULL) return 0; + + parts = (multipart_part **)msr->mpd->parts->elts; + for(i = 0; i < msr->mpd->parts->nelts; i++) { + if (parts[i]->type == MULTIPART_FILE) { + msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + + rvar->value = parts[i]->name; + rvar->value_len = strlen(rvar->value); + rvar->name = apr_psprintf(mptmp, "FILES_NAMES:%s", + log_escape_nq_ex(mptmp, parts[i]->name, rvar->value_len)); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + count++; + } + } + + return count; +} + +/* FILES_COMBINED_SIZE */ + +static int var_files_combined_size_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + multipart_part **parts = NULL; + msre_var *rvar = NULL; + unsigned int combined_size = 0; + int i; + + if (msr->mpd != NULL) { + parts = (multipart_part **)msr->mpd->parts->elts; + for(i = 0; i < msr->mpd->parts->nelts; i++) { + if (parts[i]->type == MULTIPART_FILE) { + combined_size += parts[i]->tmp_file_size; + } + } + } + + rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + rvar->value = apr_psprintf(mptmp, "%u", combined_size); + rvar->value_len = strlen(rvar->value); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + return 1; +} + +/* MODSEC_BUILD */ + +static int var_modsec_build_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + return var_simple_generate(var, vartab, mptmp, modsec_build(mptmp)); +} + +/* MULTIPART_BOUNDARY_QUOTED */ + +static int var_multipart_boundary_quoted_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + if ((msr->mpd != NULL)&&(msr->mpd->flag_boundary_quoted != 0)) { + return var_simple_generate(var, vartab, mptmp, "1"); + } else { + return var_simple_generate(var, vartab, mptmp, "0"); + } +} + +/* MULTIPART_BOUNDARY_WHITESPACE */ + +static int var_multipart_boundary_whitespace_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + if ((msr->mpd != NULL)&&(msr->mpd->flag_boundary_whitespace != 0)) { + return var_simple_generate(var, vartab, mptmp, "1"); + } else { + return var_simple_generate(var, vartab, mptmp, "0"); + } +} + +/* MULTIPART_DATA_AFTER */ + +static int var_multipart_data_after_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + if ((msr->mpd != NULL)&&(msr->mpd->flag_data_after != 0)) { + return var_simple_generate(var, vartab, mptmp, "1"); + } else { + return var_simple_generate(var, vartab, mptmp, "0"); + } +} + +/* MULTIPART_DATA_BEFORE */ + +static int var_multipart_data_before_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + if ((msr->mpd != NULL)&&(msr->mpd->flag_data_before != 0)) { + return var_simple_generate(var, vartab, mptmp, "1"); + } else { + return var_simple_generate(var, vartab, mptmp, "0"); + } +} + +/* MULTIPART_HEADER_FOLDING */ + +static int var_multipart_header_folding_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + if ((msr->mpd != NULL)&&(msr->mpd->flag_header_folding != 0)) { + return var_simple_generate(var, vartab, mptmp, "1"); + } else { + return var_simple_generate(var, vartab, mptmp, "0"); + } +} + +/* MULTIPART_CRLF_LINE */ + +static int var_multipart_crlf_line_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + if ((msr->mpd != NULL)&&(msr->mpd->flag_crlf_line != 0)) { + return var_simple_generate(var, vartab, mptmp, "1"); + } else { + return var_simple_generate(var, vartab, mptmp, "0"); + } +} + +/* MULTIPART_CRLF_LF_LINES */ + +static int var_multipart_crlf_lf_lines_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + if ((msr->mpd != NULL)&&(msr->mpd->flag_lf_line != 0)&&(msr->mpd->flag_crlf_line != 0)) { + return var_simple_generate(var, vartab, mptmp, "1"); + } else { + return var_simple_generate(var, vartab, mptmp, "0"); + } +} + +/* MULTIPART_LF_LINE */ + +static int var_multipart_lf_line_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + if ((msr->mpd != NULL)&&(msr->mpd->flag_lf_line != 0)) { + return var_simple_generate(var, vartab, mptmp, "1"); + } else { + return var_simple_generate(var, vartab, mptmp, "0"); + } +} + +/* MULTIPART_MISSING_SEMICOLON */ + +static int var_multipart_missing_semicolon_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + if ((msr->mpd != NULL)&&(msr->mpd->flag_missing_semicolon != 0)) { + return var_simple_generate(var, vartab, mptmp, "1"); + } else { + return var_simple_generate(var, vartab, mptmp, "0"); + } +} + +/* MULTIPART_INVALID_QUOTING */ + +static int var_multipart_invalid_quoting_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + if ((msr->mpd != NULL)&&(msr->mpd->flag_invalid_quoting != 0)) { + return var_simple_generate(var, vartab, mptmp, "1"); + } else { + return var_simple_generate(var, vartab, mptmp, "0"); + } +} + +/* MULTIPART_STRICT_ERROR */ + +static int var_multipart_strict_error_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + if (msr->mpd != NULL) { + /* Respond positive if at least one of the multipart flags is raised. */ + if ( (msr->mpd->flag_error) + ||(msr->mpd->flag_boundary_quoted != 0) + ||(msr->mpd->flag_boundary_whitespace != 0) + ||(msr->mpd->flag_data_before != 0) + ||(msr->mpd->flag_data_after != 0) + ||(msr->mpd->flag_header_folding != 0) + ||(msr->mpd->flag_lf_line != 0) + ||(msr->mpd->flag_missing_semicolon != 0) + ||(msr->mpd->flag_invalid_quoting != 0) + ) { + return var_simple_generate(var, vartab, mptmp, "1"); + } + } + + return var_simple_generate(var, vartab, mptmp, "0"); +} + +/* MULTIPART_UNMATCHED_BOUNDARY */ + +static int var_multipart_unmatched_boundary_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + if ((msr->mpd != NULL)&&(msr->mpd->flag_unmatched_boundary != 0)) { + return var_simple_generate(var, vartab, mptmp, "1"); + } else { + return var_simple_generate(var, vartab, mptmp, "0"); + } +} + +/* TIME */ + +static int var_time_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + msre_var *rvar = NULL; + struct tm *tm; + time_t tc; + + tc = time(NULL); + tm = localtime(&tc); + rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + rvar->value = apr_psprintf(mptmp, "%02d%02d%02d%02d%02d%02d%02d", + (tm->tm_year / 100) + 19, (tm->tm_year % 100), + tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, + tm->tm_sec); + rvar->value_len = strlen(rvar->value); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + return 1; +} + +/* TIME_YEAR */ + +static int var_time_year_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + msre_var *rvar = NULL; + struct tm *tm; + time_t tc; + + tc = time(NULL); + tm = localtime(&tc); + rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + rvar->value = apr_psprintf(mptmp, "%02d%02d", + (tm->tm_year / 100) + 19, + tm->tm_year % 100); + rvar->value_len = strlen(rvar->value); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + return 1; +} + +/* TIME_WDAY */ + +static int var_time_wday_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + msre_var *rvar = NULL; + struct tm *tm; + time_t tc; + + tc = time(NULL); + tm = localtime(&tc); + rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + rvar->value = apr_psprintf(mptmp, "%d", tm->tm_wday); + rvar->value_len = strlen(rvar->value); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + return 1; +} + +/* TIME_SEC */ + +static int var_time_sec_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + msre_var *rvar = NULL; + struct tm *tm; + time_t tc; + + tc = time(NULL); + tm = localtime(&tc); + rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + rvar->value = apr_psprintf(mptmp, "%02d", tm->tm_sec); + rvar->value_len = strlen(rvar->value); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + return 1; +} + +/* TIME_MIN */ + +static int var_time_min_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + msre_var *rvar = NULL; + struct tm *tm; + time_t tc; + + tc = time(NULL); + tm = localtime(&tc); + rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + rvar->value = apr_psprintf(mptmp, "%02d", tm->tm_min); + rvar->value_len = strlen(rvar->value); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + return 1; +} + +/* TIME_HOUR */ +static int var_time_hour_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + msre_var *rvar = NULL; + struct tm *tm; + time_t tc; + + tc = time(NULL); + tm = localtime(&tc); + rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + rvar->value = apr_psprintf(mptmp, "%02d", tm->tm_hour); + rvar->value_len = strlen(rvar->value); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + return 1; +} + +/* TIME_MON */ + +static int var_time_mon_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + msre_var *rvar = NULL; + struct tm *tm; + time_t tc; + + tc = time(NULL); + tm = localtime(&tc); + rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + rvar->value = apr_psprintf(mptmp, "%02d", tm->tm_mon + 1); + rvar->value_len = strlen(rvar->value); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + return 1; +} + +/* TIME_DAY */ + +static int var_time_day_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + msre_var *rvar = NULL; + struct tm *tm; + time_t tc; + + tc = time(NULL); + tm = localtime(&tc); + rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + rvar->value = apr_psprintf(mptmp, "%02d", tm->tm_mday); + rvar->value_len = strlen(rvar->value); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + return 1; +} + +/* TIME_EPOCH */ + +static int var_time_epoch_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + msre_var *rvar = NULL; + struct tm *tm; + time_t tc; + + tc = time(NULL); + tm = localtime(&tc); + rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + rvar->value = apr_psprintf(mptmp, "%ld", (long)tc); + rvar->value_len = strlen(rvar->value); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + return 1; +} + +/* QUERY_STRING */ + +static int var_query_string_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + return var_simple_generate(var, vartab, mptmp, msr->query_string); +} + +/* REQUEST_BASENAME */ + +static int var_request_basename_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + char *value = file_basename(mptmp, msr->r->parsed_uri.path); + return var_simple_generate(var, vartab, mptmp, value); +} + +/* REQUEST_BODY */ + +static int var_request_body_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + if (msr->msc_reqbody_buffer != NULL) { + return var_simple_generate_ex(var, vartab, mptmp, + msr->msc_reqbody_buffer, msr->msc_reqbody_length); + } + return 0; +} + +/* REQUEST_COOKIES */ + +static int var_request_cookies_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + const apr_array_header_t *arr = NULL; + const apr_table_entry_t *te = NULL; + int i, count = 0; + + arr = apr_table_elts(msr->request_cookies); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + int match = 0; + + /* Figure out if we want to include this variable. */ + if (var->param == NULL) match = 1; + else { + if (var->param_data != NULL) { /* Regex. */ + char *my_error_msg = NULL; + if (!(msc_regexec((msc_regex_t *)var->param_data, te[i].key, + strlen(te[i].key), &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + } else { /* Simple comparison. */ + if (strcasecmp(te[i].key, var->param) == 0) match = 1; + } + } + + /* If we had a match add this argument to the collection. */ + if (match) { + msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + + rvar->value = te[i].val; + rvar->value_len = strlen(rvar->value); + rvar->name = apr_psprintf(mptmp, "REQUEST_COOKIES:%s", + log_escape_nq(mptmp, te[i].key)); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + count++; + } + } + + return count; +} + +/* REQUEST_COOKIES_NAMES */ + +static int var_request_cookies_names_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + const apr_array_header_t *arr = NULL; + const apr_table_entry_t *te = NULL; + int i, count = 0; + + arr = apr_table_elts(msr->request_cookies); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + int match = 0; + + /* Figure out if we want to include this variable. */ + if (var->param == NULL) match = 1; + else { + if (var->param_data != NULL) { /* Regex. */ + char *my_error_msg = NULL; + if (!(msc_regexec((msc_regex_t *)var->param_data, te[i].key, + strlen(te[i].key), &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + } else { /* Simple comparison. */ + if (strcasecmp(te[i].key, var->param) == 0) match = 1; + } + } + + /* If we had a match add this argument to the collection. */ + if (match) { + msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + + rvar->value = te[i].key; + rvar->value_len = strlen(rvar->value); + rvar->name = apr_psprintf(mptmp, "REQUEST_COOKIES_NAMES:%s", + log_escape_nq(mptmp, te[i].key)); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + count++; + } + } + + return count; +} + +/* REQUEST_HEADERS */ + +static int var_request_headers_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + const apr_array_header_t *arr = NULL; + const apr_table_entry_t *te = NULL; + int i, count = 0; + + arr = apr_table_elts(msr->request_headers); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + int match = 0; + + /* Figure out if we want to include this variable. */ + if (var->param == NULL) match = 1; + else { + if (var->param_data != NULL) { /* Regex. */ + char *my_error_msg = NULL; + if (!(msc_regexec((msc_regex_t *)var->param_data, te[i].key, + strlen(te[i].key), &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + } else { /* Simple comparison. */ + if (strcasecmp(te[i].key, var->param) == 0) match = 1; + } + } + + /* If we had a match add this argument to the collection. */ + if (match) { + msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + + rvar->value = te[i].val; + rvar->value_len = strlen(rvar->value); + rvar->name = apr_psprintf(mptmp, "REQUEST_HEADERS:%s", + log_escape_nq(mptmp, te[i].key)); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + count++; + } + } + + return count; +} + +/* REQUEST_HEADERS_NAMES */ + +static int var_request_headers_names_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + const apr_array_header_t *arr = NULL; + const apr_table_entry_t *te = NULL; + int i, count = 0; + + arr = apr_table_elts(msr->request_headers); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + int match = 0; + + /* Figure out if we want to include this variable. */ + if (var->param == NULL) match = 1; + else { + if (var->param_data != NULL) { /* Regex. */ + char *my_error_msg = NULL; + if (!(msc_regexec((msc_regex_t *)var->param_data, te[i].key, + strlen(te[i].key), &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + } else { /* Simple comparison. */ + if (strcasecmp(te[i].key, var->param) == 0) match = 1; + } + } + + /* If we had a match add this argument to the collection. */ + if (match) { + msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + + rvar->value = te[i].key; + rvar->value_len = strlen(rvar->value); + rvar->name = apr_psprintf(mptmp, "REQUEST_HEADERS_NAMES:%s", + log_escape_nq(mptmp, te[i].key)); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + count++; + } + } + + return count; +} + +/* REQUEST_FILENAME */ + +static int var_request_filename_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + return var_simple_generate(var, vartab, mptmp, msr->r->parsed_uri.path); +} + +/* REQUEST_LINE */ + +static int var_request_line_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + return var_simple_generate(var, vartab, mptmp, msr->request_line); +} + +/* REQUEST_METHOD */ + +static int var_request_method_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + return var_simple_generate(var, vartab, mptmp, msr->request_method); +} + +/* REQUEST_PROTOCOL */ + +static int var_request_protocol_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + return var_simple_generate(var, vartab, mptmp, msr->request_protocol); +} + +/* SERVER_ADDR */ + +static int var_server_addr_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + return var_simple_generate(var, vartab, mptmp, msr->local_addr); +} + +/* SERVER_NAME */ + +static int var_server_name_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + return var_simple_generate(var, vartab, mptmp, msr->hostname); +} + +/* SERVER_PORT */ + +static int var_server_port_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + char *value = apr_psprintf(mptmp, "%u", msr->local_port); + return var_simple_generate(var, vartab, mptmp, value); +} + +/* SCRIPT_BASENAME */ + +static int var_script_basename_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + char *value = file_basename(mptmp, msr->r->filename); + return var_simple_generate(var, vartab, mptmp, value); +} + +/* SCRIPT_FILENAME */ + +static int var_script_filename_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + char *value = msr->r->filename; + return var_simple_generate(var, vartab, mptmp, value); +} + +/* SCRIPT_GID */ + +static int var_script_gid_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + char *value = apr_psprintf(mptmp, "%ld", (long)msr->r->finfo.group); + return var_simple_generate(var, vartab, mptmp, value); +} + +/* SCRIPT_GROUPNAME */ + +static int var_script_groupname_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + char *value = NULL; + if (apr_gid_name_get(&value, msr->r->finfo.group, mptmp) == APR_SUCCESS) { + return var_simple_generate(var, vartab, mptmp, value); + } + return 0; +} + +/* SCRIPT_MODE */ + +static int var_script_mode_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + char *value = apr_psprintf(mptmp, "%04x", msr->r->finfo.protection); + return var_simple_generate(var, vartab, mptmp, value); +} + +/* SCRIPT_UID */ + +static int var_script_uid_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + char *value = apr_psprintf(mptmp, "%ld", (long)msr->r->finfo.user); + return var_simple_generate(var, vartab, mptmp, value); +} + +/* SCRIPT_USERNAME */ + +static int var_script_username_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + char *value = NULL; + if (apr_uid_name_get(&value, msr->r->finfo.user, mptmp) == APR_SUCCESS) { + return var_simple_generate(var, vartab, mptmp, value); + } + return 0; +} + +/* AUTH_TYPE */ + +static int var_auth_type_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + char *value = msr->r->ap_auth_type; + return var_simple_generate(var, vartab, mptmp, value); +} + +/* PATH_INFO */ + +static int var_path_info_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + const char *value = msr->r->path_info; + return var_simple_generate(var, vartab, mptmp, value); +} + +/* RESPONSE_BODY */ + +static int var_response_body_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + if (msr->resbody_data != NULL) { + return var_simple_generate_ex(var, vartab, mptmp, + msr->resbody_data, msr->resbody_length); + } + + return 0; +} + +/* RESPONSE_HEADERS */ + +static int var_response_headers_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + const apr_array_header_t *arr = NULL; + const apr_table_entry_t *te = NULL; + int i, count = 0; + + if (msr->response_headers == NULL) return 0; + + arr = apr_table_elts(msr->response_headers); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + int match = 0; + + /* Figure out if we want to include this variable. */ + if (var->param == NULL) match = 1; + else { + if (var->param_data != NULL) { /* Regex. */ + char *my_error_msg = NULL; + if (!(msc_regexec((msc_regex_t *)var->param_data, te[i].key, + strlen(te[i].key), &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + } else { /* Simple comparison. */ + if (strcasecmp(te[i].key, var->param) == 0) match = 1; + } + } + + /* If we had a match add this argument to the collection. */ + if (match) { + msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + + rvar->value = te[i].val; + rvar->value_len = strlen(rvar->value); + rvar->name = apr_psprintf(mptmp, "RESPONSE_HEADERS:%s", + log_escape_nq(mptmp, te[i].key)); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + count++; + } + } + + return count; +} + +/* RESPONSE_HEADERS_NAMES */ + +static int var_response_headers_names_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + const apr_array_header_t *arr = NULL; + const apr_table_entry_t *te = NULL; + int i, count = 0; + + arr = apr_table_elts(msr->response_headers); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + int match = 0; + + /* Figure out if we want to include this variable. */ + if (var->param == NULL) match = 1; + else { + if (var->param_data != NULL) { /* Regex. */ + char *my_error_msg = NULL; + if (!(msc_regexec((msc_regex_t *)var->param_data, te[i].key, + strlen(te[i].key), &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + } else { /* Simple comparison. */ + if (strcasecmp(te[i].key, var->param) == 0) match = 1; + } + } + + /* If we had a match add this argument to the collection. */ + if (match) { + msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + + rvar->value = te[i].key; + rvar->value_len = strlen(rvar->value); + rvar->name = apr_psprintf(mptmp, "RESPONSE_HEADERS_NAMES:%s", + log_escape_nq(mptmp, te[i].key)); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + count++; + } + } + + return count; +} + +/* STATUS_LINE */ + +static int var_status_line_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + const char *value = msr->status_line; + return var_simple_generate(var, vartab, mptmp, value); +} + +/* RESPONSE_PROTOCOL */ + +static int var_response_protocol_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + const char *value = msr->response_protocol; + return var_simple_generate(var, vartab, mptmp, value); +} + +/* RESPONSE_STATUS */ + +static int var_response_status_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + const char *value = apr_psprintf(mptmp, "%u", msr->response_status); + return var_simple_generate(var, vartab, mptmp, value); +} + +/* RESPONSE_CONTENT_TYPE */ + +static int var_response_content_type(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + return var_simple_generate(var, vartab, mptmp, msr->r->content_type); +} + +/* RESPONSE_CONTENT_LENGTH */ + +static int var_response_content_length(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + const char *value = apr_psprintf(mptmp, "%" APR_OFF_T_FMT, msr->r->clength); + return var_simple_generate(var, vartab, mptmp, value); +} + +/* USERID */ + +static int var_userid_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + const char *value = msr->userid; + return var_simple_generate(var, vartab, mptmp, value); +} + +/* SESSIONID */ + +static int var_sessionid_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + const char *value = msr->sessionid; + return var_simple_generate(var, vartab, mptmp, value); +} + +/* WEBAPPID */ + +static int var_webappid_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + const char *value = msr->txcfg->webappid; + return var_simple_generate(var, vartab, mptmp, value); +} + +/* ---------------------------------------------- */ + +/** + * + */ +void msre_engine_variable_register(msre_engine *engine, const char *name, + unsigned int type, unsigned int argc_min, unsigned int argc_max, + fn_var_validate_t validate, fn_var_generate_t generate, + unsigned int is_cacheable, unsigned int availability) +{ + msre_var_metadata *metadata = (msre_var_metadata *)apr_pcalloc(engine->mp, + sizeof(msre_var_metadata)); + if (metadata == NULL) return; + + metadata->name = name; + metadata->type = type; + metadata->argc_min = argc_min; + metadata->argc_max = argc_max; + metadata->validate = validate; + metadata->generate = generate; + metadata->is_cacheable = is_cacheable; + metadata->availability = availability; + + apr_table_setn(engine->variables, name, (void *)metadata); +} + +/** + * + */ +void msre_engine_register_default_variables(msre_engine *engine) { + + /* ARGS */ + msre_engine_variable_register(engine, + "ARGS", + VAR_LIST, + 0, 1, + var_generic_list_validate, + var_args_generate, + VAR_CACHE, + PHASE_REQUEST_HEADERS + ); + + /* ARGS_COMBINED_SIZE */ + msre_engine_variable_register(engine, + "ARGS_COMBINED_SIZE", + VAR_LIST, + 0, 0, + NULL, + var_args_combined_size_generate, + VAR_DONT_CACHE, /* dynamic */ + PHASE_REQUEST_HEADERS + ); + + /* ARGS_GET */ + msre_engine_variable_register(engine, + "ARGS_GET", + VAR_LIST, + 0, 1, + var_generic_list_validate, + var_args_get_generate, + VAR_CACHE, + PHASE_REQUEST_HEADERS + ); + + /* ARGS_GET_NAMES */ + msre_engine_variable_register(engine, + "ARGS_GET_NAMES", + VAR_LIST, + 0, 1, + var_generic_list_validate, + var_args_get_names_generate, + VAR_CACHE, + PHASE_REQUEST_HEADERS + ); + + /* ARGS_NAMES */ + msre_engine_variable_register(engine, + "ARGS_NAMES", + VAR_LIST, + 0, 1, + var_generic_list_validate, + var_args_names_generate, + VAR_CACHE, + PHASE_REQUEST_HEADERS + ); + + /* ARGS_POST */ + msre_engine_variable_register(engine, + "ARGS_POST", + VAR_LIST, + 0, 1, + var_generic_list_validate, + var_args_post_generate, + VAR_CACHE, + PHASE_REQUEST_BODY + ); + + /* ARGS_POST_NAMES */ + msre_engine_variable_register(engine, + "ARGS_POST_NAMES", + VAR_LIST, + 0, 1, + var_generic_list_validate, + var_args_post_names_generate, + VAR_CACHE, + PHASE_REQUEST_BODY + ); + + /* AUTH_TYPE */ + msre_engine_variable_register(engine, + "AUTH_TYPE", + VAR_SIMPLE, + 0, 0, + NULL, + var_auth_type_generate, + VAR_CACHE, + PHASE_REQUEST_BODY + ); + + /* ENV */ + msre_engine_variable_register(engine, + "ENV", + VAR_LIST, + 0, 1, + var_env_validate, + var_env_generate, + VAR_DONT_CACHE, + PHASE_REQUEST_HEADERS + ); + + /* FILES */ + msre_engine_variable_register(engine, + "FILES", + VAR_LIST, + 0, 1, + var_generic_list_validate, + var_files_generate, + VAR_CACHE, + PHASE_REQUEST_BODY + ); + + /* FILES_COMBINED_SIZE */ + msre_engine_variable_register(engine, + "FILES_COMBINED_SIZE", + VAR_LIST, + 0, 0, + NULL, + var_files_combined_size_generate, + VAR_DONT_CACHE, /* temp copy */ + PHASE_REQUEST_BODY + ); + + /* FILES_NAMES */ + msre_engine_variable_register(engine, + "FILES_NAMES", + VAR_LIST, + 0, 0, + NULL, + var_files_names_generate, + VAR_CACHE, + PHASE_REQUEST_BODY + ); + + /* FILES_SIZES */ + msre_engine_variable_register(engine, + "FILES_SIZES", + VAR_LIST, + 0, 1, + var_generic_list_validate, + var_files_sizes_generate, + VAR_DONT_CACHE, /* temp copy */ + PHASE_REQUEST_BODY + ); + + /* FILES_TMPNAMES */ + msre_engine_variable_register(engine, + "FILES_TMPNAMES", + VAR_LIST, + 0, 1, + var_generic_list_validate, + var_files_tmpnames_generate, + VAR_CACHE, + PHASE_REQUEST_BODY + ); + + /* GEO */ + msre_engine_variable_register(engine, + "GEO", + VAR_LIST, + 0, 1, + var_generic_list_validate, + var_geo_generate, + VAR_DONT_CACHE, /* dynamic */ + PHASE_REQUEST_HEADERS + ); + + /* GLOBAL */ + msre_engine_variable_register(engine, + "GLOBAL", + VAR_LIST, + 1, 1, + var_generic_list_validate, + var_global_generate, + VAR_DONT_CACHE, /* dynamic */ + PHASE_REQUEST_HEADERS + ); + + /* HIGHEST_SEVERITY */ + msre_engine_variable_register(engine, + "HIGHEST_SEVERITY", + VAR_SIMPLE, + 0, 0, + NULL, + var_highest_severity_generate, + VAR_DONT_CACHE, /* dynamic */ + PHASE_REQUEST_HEADERS + ); + + /* IP */ + msre_engine_variable_register(engine, + "IP", + VAR_LIST, + 1, 1, + var_generic_list_validate, + var_ip_generate, + VAR_DONT_CACHE, /* dynamic */ + PHASE_REQUEST_HEADERS + ); + + /* MATCHED_VAR */ + msre_engine_variable_register(engine, + "MATCHED_VAR", + VAR_SIMPLE, + 0, 0, + NULL, + var_matched_var_generate, + VAR_DONT_CACHE, /* dynamic */ + PHASE_REQUEST_HEADERS + ); + + /* MATCHED_VAR_NAME */ + msre_engine_variable_register(engine, + "MATCHED_VAR_NAME", + VAR_SIMPLE, + 0, 0, + NULL, + var_matched_var_name_generate, + VAR_DONT_CACHE, /* dynamic */ + PHASE_REQUEST_HEADERS + ); + + /* MODSEC_BUILD */ + msre_engine_variable_register(engine, + "MODSEC_BUILD", + VAR_SIMPLE, + 0, 0, + NULL, + var_modsec_build_generate, + VAR_CACHE, + PHASE_REQUEST_HEADERS + ); + + /* MULTIPART_BOUNDARY_QUOTED */ + msre_engine_variable_register(engine, + "MULTIPART_BOUNDARY_QUOTED", + VAR_SIMPLE, + 0, 0, + NULL, + var_multipart_boundary_quoted_generate, + VAR_DONT_CACHE, /* flag */ + PHASE_REQUEST_BODY + ); + + /* MULTIPART_BOUNDARY_WHITESPACE */ + msre_engine_variable_register(engine, + "MULTIPART_BOUNDARY_WHITESPACE", + VAR_SIMPLE, + 0, 0, + NULL, + var_multipart_boundary_whitespace_generate, + VAR_DONT_CACHE, /* flag */ + PHASE_REQUEST_BODY + ); + + /* MULTIPART_DATA_AFTER */ + msre_engine_variable_register(engine, + "MULTIPART_DATA_AFTER", + VAR_SIMPLE, + 0, 0, + NULL, + var_multipart_data_after_generate, + VAR_DONT_CACHE, /* flag */ + PHASE_REQUEST_BODY + ); + + /* MULTIPART_DATA_BEFORE */ + msre_engine_variable_register(engine, + "MULTIPART_DATA_BEFORE", + VAR_SIMPLE, + 0, 0, + NULL, + var_multipart_data_before_generate, + VAR_DONT_CACHE, /* flag */ + PHASE_REQUEST_BODY + ); + + /* MULTIPART_HEADER_FOLDING */ + msre_engine_variable_register(engine, + "MULTIPART_HEADER_FOLDING", + VAR_SIMPLE, + 0, 0, + NULL, + var_multipart_header_folding_generate, + VAR_DONT_CACHE, /* flag */ + PHASE_REQUEST_BODY + ); + + /* MULTIPART_CRLF_LINE */ + msre_engine_variable_register(engine, + "MULTIPART_CRLF_LINE", + VAR_SIMPLE, + 0, 0, + NULL, + var_multipart_crlf_line_generate, + VAR_DONT_CACHE, /* flag */ + PHASE_REQUEST_BODY + ); + + /* MULTIPART_CRLF_LF_LINES */ + msre_engine_variable_register(engine, + "MULTIPART_CRLF_LF_LINES", + VAR_SIMPLE, + 0, 0, + NULL, + var_multipart_crlf_lf_lines_generate, + VAR_DONT_CACHE, /* flag */ + PHASE_REQUEST_BODY + ); + + /* MULTIPART_LF_LINE */ + msre_engine_variable_register(engine, + "MULTIPART_LF_LINE", + VAR_SIMPLE, + 0, 0, + NULL, + var_multipart_lf_line_generate, + VAR_DONT_CACHE, /* flag */ + PHASE_REQUEST_BODY + ); + + /* MULTIPART_MISSING_SEMICOLON */ + msre_engine_variable_register(engine, + "MULTIPART_MISSING_SEMICOLON", + VAR_SIMPLE, + 0, 0, + NULL, + var_multipart_missing_semicolon_generate, + VAR_DONT_CACHE, /* flag */ + PHASE_REQUEST_BODY + ); + + /* MULTIPART_INVALID_QUOTING */ + msre_engine_variable_register(engine, + "MULTIPART_INVALID_QUOTING", + VAR_SIMPLE, + 0, 0, + NULL, + var_multipart_invalid_quoting_generate, + VAR_DONT_CACHE, /* flag */ + PHASE_REQUEST_BODY + ); + + /* MULTIPART_STRICT_ERROR */ + msre_engine_variable_register(engine, + "MULTIPART_STRICT_ERROR", + VAR_SIMPLE, + 0, 0, + NULL, + var_multipart_strict_error_generate, + VAR_DONT_CACHE, /* flag */ + PHASE_REQUEST_BODY + ); + + /* MULTIPART_UNMATCHED_BOUNDARY */ + msre_engine_variable_register(engine, + "MULTIPART_UNMATCHED_BOUNDARY", + VAR_SIMPLE, + 0, 0, + NULL, + var_multipart_unmatched_boundary_generate, + VAR_DONT_CACHE, /* flag */ + PHASE_REQUEST_BODY + ); + + /* PATH_INFO */ + msre_engine_variable_register(engine, + "PATH_INFO", + VAR_SIMPLE, + 0, 0, + NULL, + var_path_info_generate, + VAR_CACHE, + PHASE_REQUEST_BODY + ); + + /* QUERY_STRING */ + msre_engine_variable_register(engine, + "QUERY_STRING", + VAR_SIMPLE, + 0, 0, + NULL, + var_query_string_generate, + VAR_CACHE, + PHASE_REQUEST_HEADERS + ); + + /* REMOTE_ADDR */ + msre_engine_variable_register(engine, + "REMOTE_ADDR", + VAR_SIMPLE, + 0, 0, + NULL, + var_remote_addr_generate, + VAR_CACHE, + PHASE_REQUEST_HEADERS + ); + + /* REMOTE_HOST */ + msre_engine_variable_register(engine, + "REMOTE_HOST", + VAR_SIMPLE, + 0, 0, + NULL, + var_remote_host_generate, + VAR_CACHE, + PHASE_REQUEST_BODY + ); + + /* REMOTE_PORT */ + msre_engine_variable_register(engine, + "REMOTE_PORT", + VAR_SIMPLE, + 0, 0, + NULL, + var_remote_port_generate, + VAR_DONT_CACHE, /* temp copy */ + PHASE_REQUEST_BODY + ); + + /* REMOTE_USER */ + msre_engine_variable_register(engine, + "REMOTE_USER", + VAR_SIMPLE, + 0, 0, + NULL, + var_remote_user_generate, + VAR_CACHE, + PHASE_REQUEST_BODY + ); + + /* RESOURCE */ + msre_engine_variable_register(engine, + "RESOURCE", + VAR_LIST, + 1, 1, + var_generic_list_validate, + var_resource_generate, + VAR_DONT_CACHE, /* dynamic */ + PHASE_REQUEST_HEADERS + ); + + /* REQBODY_PROCESSOR */ + msre_engine_variable_register(engine, + "REQBODY_PROCESSOR", + VAR_SIMPLE, + 0, 0, + NULL, + var_reqbody_processor_generate, + VAR_DONT_CACHE, /* temp copy */ + PHASE_REQUEST_HEADERS + ); + + /* REQBODY_PROCESSOR_ERROR */ + msre_engine_variable_register(engine, + "REQBODY_PROCESSOR_ERROR", + VAR_SIMPLE, + 0, 0, + NULL, + var_reqbody_processor_error_generate, + VAR_DONT_CACHE, /* dynamic */ + PHASE_REQUEST_BODY + ); + + /* REQBODY_PROCESSOR_ERROR_MSG */ + msre_engine_variable_register(engine, + "REQBODY_PROCESSOR_ERROR_MSG", + VAR_SIMPLE, + 0, 0, + NULL, + var_reqbody_processor_error_msg_generate, + VAR_DONT_CACHE, /* dynamic */ + PHASE_REQUEST_BODY + ); + + /* REQUEST_BASENAME */ + msre_engine_variable_register(engine, + "REQUEST_BASENAME", + VAR_SIMPLE, + 0, 0, + NULL, + var_request_basename_generate, + VAR_DONT_CACHE, /* temp copy */ + PHASE_REQUEST_HEADERS + ); + + /* REQUEST_BODY */ + msre_engine_variable_register(engine, + "REQUEST_BODY", + VAR_SIMPLE, + 0, 0, + NULL, + var_request_body_generate, + VAR_CACHE, + PHASE_REQUEST_BODY + ); + + /* REQUEST_COOKIES */ + msre_engine_variable_register(engine, + "REQUEST_COOKIES", + VAR_LIST, + 0, 1, + var_generic_list_validate, + var_request_cookies_generate, + VAR_CACHE, + PHASE_REQUEST_HEADERS + ); + + /* REQUEST_COOKIES_NAMES */ + msre_engine_variable_register(engine, + "REQUEST_COOKIES_NAMES", + VAR_LIST, + 0, 1, + var_generic_list_validate, + var_request_cookies_names_generate, + VAR_CACHE, + PHASE_REQUEST_HEADERS + ); + + /* REQUEST_FILENAME */ + msre_engine_variable_register(engine, + "REQUEST_FILENAME", + VAR_SIMPLE, + 0, 0, + NULL, + var_request_filename_generate, + VAR_CACHE, + PHASE_REQUEST_HEADERS + ); + + /* REQUEST_HEADERS */ + msre_engine_variable_register(engine, + "REQUEST_HEADERS", + VAR_LIST, + 0, 1, + var_generic_list_validate, + var_request_headers_generate, + VAR_CACHE, + PHASE_REQUEST_HEADERS + ); + + /* REQUEST_HEADERS_NAMES */ + msre_engine_variable_register(engine, + "REQUEST_HEADERS_NAMES", + VAR_LIST, + 0, 1, + var_generic_list_validate, + var_request_headers_names_generate, + VAR_CACHE, + PHASE_REQUEST_HEADERS + ); + + /* REQUEST_LINE */ + msre_engine_variable_register(engine, + "REQUEST_LINE", + VAR_SIMPLE, + 0, 0, + NULL, + var_request_line_generate, + VAR_CACHE, + PHASE_REQUEST_HEADERS + ); + + /* REQUEST_METHOD */ + msre_engine_variable_register(engine, + "REQUEST_METHOD", + VAR_SIMPLE, + 0, 0, + NULL, + var_request_method_generate, + VAR_CACHE, + PHASE_REQUEST_HEADERS + ); + + /* REQUEST_PROTOCOL */ + msre_engine_variable_register(engine, + "REQUEST_PROTOCOL", + VAR_SIMPLE, + 0, 0, + NULL, + var_request_protocol_generate, + VAR_CACHE, + PHASE_REQUEST_HEADERS + ); + + /* REQUEST_URI */ + msre_engine_variable_register(engine, + "REQUEST_URI", + VAR_SIMPLE, + 0, 0, + NULL, + var_request_uri_generate, + VAR_DONT_CACHE, /* temp copy */ + PHASE_REQUEST_HEADERS + ); + + /* REQUEST_URI_RAW */ + msre_engine_variable_register(engine, + "REQUEST_URI_RAW", + VAR_SIMPLE, + 0, 0, + NULL, + var_request_uri_raw_generate, + VAR_CACHE, + PHASE_REQUEST_HEADERS + ); + + /* RESPONSE_BODY */ + msre_engine_variable_register(engine, + "RESPONSE_BODY", + VAR_SIMPLE, + 0, 0, + NULL, + var_response_body_generate, + VAR_CACHE, + PHASE_RESPONSE_BODY + ); + + /* RESPONSE_CONTENT_LENGTH */ + msre_engine_variable_register(engine, + "RESPONSE_CONTENT_LENGTH", + VAR_SIMPLE, + 0, 0, + NULL, + var_response_content_length, + VAR_DONT_CACHE, /* temp copy */ + PHASE_RESPONSE_HEADERS + ); + + /* RESPONSE_CONTENT_TYPE */ + msre_engine_variable_register(engine, + "RESPONSE_CONTENT_TYPE", + VAR_SIMPLE, + 0, 0, + NULL, + var_response_content_type, + VAR_CACHE, + PHASE_RESPONSE_HEADERS + ); + + /* RESPONSE_HEADERS */ + msre_engine_variable_register(engine, + "RESPONSE_HEADERS", + VAR_LIST, + 0, 1, + var_generic_list_validate, + var_response_headers_generate, + VAR_CACHE, + PHASE_RESPONSE_HEADERS + ); + + /* RESPONSE_HEADERS_NAMES */ + msre_engine_variable_register(engine, + "RESPONSE_HEADERS_NAMES", + VAR_LIST, + 0, 1, + var_generic_list_validate, + var_response_headers_names_generate, + VAR_CACHE, + PHASE_RESPONSE_HEADERS + ); + + /* RESPONSE_PROTOCOL */ + msre_engine_variable_register(engine, + "RESPONSE_PROTOCOL", + VAR_SIMPLE, + 0, 0, + NULL, + var_response_protocol_generate, + VAR_CACHE, + PHASE_RESPONSE_HEADERS + ); + + /* RESPONSE_STATUS */ + msre_engine_variable_register(engine, + "RESPONSE_STATUS", + VAR_SIMPLE, + 0, 0, + NULL, + var_response_status_generate, + VAR_DONT_CACHE, /* temp copy */ + PHASE_RESPONSE_HEADERS + ); + + /* RULE */ + msre_engine_variable_register(engine, + "RULE", + VAR_LIST, + 1, 1, + NULL, + var_rule_generate, + VAR_DONT_CACHE, /* dynamic */ + PHASE_RESPONSE_HEADERS + ); + + /* SCRIPT_GID */ + msre_engine_variable_register(engine, + "SCRIPT_GID", + VAR_SIMPLE, + 0, 0, + NULL, + var_script_gid_generate, + VAR_DONT_CACHE, /* temp copy */ + PHASE_REQUEST_BODY + ); + + /* SCRIPT_BASENAME */ + msre_engine_variable_register(engine, + "SCRIPT_BASENAME", + VAR_SIMPLE, + 0, 0, + NULL, + var_script_basename_generate, + VAR_DONT_CACHE, /* temp copy */ + PHASE_REQUEST_BODY + ); + + /* SCRIPT_FILENAME */ + msre_engine_variable_register(engine, + "SCRIPT_FILENAME", + VAR_SIMPLE, + 0, 0, + NULL, + var_script_filename_generate, + VAR_CACHE, + PHASE_REQUEST_BODY + ); + + /* SCRIPT_GROUPNAME */ + msre_engine_variable_register(engine, + "SCRIPT_GROUPNAME", + VAR_SIMPLE, + 0, 0, + NULL, + var_script_groupname_generate, + VAR_DONT_CACHE, /* temp copy */ + PHASE_REQUEST_BODY + ); + + /* SCRIPT_MODE */ + msre_engine_variable_register(engine, + "SCRIPT_MODE", + VAR_SIMPLE, + 0, 0, + NULL, + var_script_mode_generate, + VAR_DONT_CACHE, /* temp copy */ + PHASE_REQUEST_BODY + ); + + /* SCRIPT_UID */ + msre_engine_variable_register(engine, + "SCRIPT_UID", + VAR_SIMPLE, + 0, 0, + NULL, + var_script_uid_generate, + VAR_DONT_CACHE, /* temp copy */ + PHASE_REQUEST_BODY + ); + + /* SCRIPT_USERNAME */ + msre_engine_variable_register(engine, + "SCRIPT_USERNAME", + VAR_SIMPLE, + 0, 0, + NULL, + var_script_username_generate, + VAR_DONT_CACHE, /* temp copy */ + PHASE_REQUEST_BODY + ); + + /* SERVER_ADDR */ + msre_engine_variable_register(engine, + "SERVER_ADDR", + VAR_SIMPLE, + 0, 0, + NULL, + var_server_addr_generate, + VAR_CACHE, + PHASE_REQUEST_HEADERS + ); + + /* SERVER_NAME */ + msre_engine_variable_register(engine, + "SERVER_NAME", + VAR_SIMPLE, + 0, 0, + NULL, + var_server_name_generate, + VAR_CACHE, + PHASE_REQUEST_HEADERS + ); + + /* SERVER_PORT */ + msre_engine_variable_register(engine, + "SERVER_PORT", + VAR_SIMPLE, + 0, 0, + NULL, + var_server_port_generate, + VAR_DONT_CACHE, /* temp copy */ + PHASE_REQUEST_HEADERS + ); + + /* SESSION */ + msre_engine_variable_register(engine, + "SESSION", + VAR_LIST, + 1, 1, + var_generic_list_validate, + var_session_generate, + VAR_DONT_CACHE, /* dynamic */ + PHASE_REQUEST_HEADERS + ); + + /* SESSIONID */ + msre_engine_variable_register(engine, + "SESSIONID", + VAR_SIMPLE, + 0, 0, + NULL, + var_sessionid_generate, + VAR_DONT_CACHE, /* dynamic */ + PHASE_RESPONSE_HEADERS + ); + + /* STATUS_LINE */ + msre_engine_variable_register(engine, + "STATUS_LINE", + VAR_SIMPLE, + 0, 0, + NULL, + var_status_line_generate, + VAR_CACHE, + PHASE_RESPONSE_HEADERS + ); + + /* USER */ + msre_engine_variable_register(engine, + "USER", + VAR_LIST, + 1, 1, + var_generic_list_validate, + var_user_generate, + VAR_DONT_CACHE, /* dynamic */ + PHASE_REQUEST_HEADERS + ); + + /* USERID */ + msre_engine_variable_register(engine, + "USERID", + VAR_SIMPLE, + 0, 0, + NULL, + var_userid_generate, + VAR_DONT_CACHE, /* dynamic */ + PHASE_RESPONSE_HEADERS + ); + + /* TIME */ + msre_engine_variable_register(engine, + "TIME", + VAR_SIMPLE, + 0, 0, + NULL, + var_time_generate, + VAR_DONT_CACHE, /* dynamic */ + PHASE_REQUEST_HEADERS + ); + + /* TIME_DAY */ + msre_engine_variable_register(engine, + "TIME_DAY", + VAR_SIMPLE, + 0, 0, + NULL, + var_time_day_generate, + VAR_DONT_CACHE, /* dynamic */ + PHASE_REQUEST_HEADERS + ); + + /* TIME_EPOCH */ + msre_engine_variable_register(engine, + "TIME_EPOCH", + VAR_SIMPLE, + 0, 0, + NULL, + var_time_epoch_generate, + VAR_DONT_CACHE, /* dynamic */ + PHASE_REQUEST_HEADERS + ); + + /* TIME_HOUR */ + msre_engine_variable_register(engine, + "TIME_HOUR", + VAR_SIMPLE, + 0, 0, + NULL, + var_time_hour_generate, + VAR_DONT_CACHE, /* dynamic */ + PHASE_REQUEST_HEADERS + ); + + /* TIME_MIN */ + msre_engine_variable_register(engine, + "TIME_MIN", + VAR_SIMPLE, + 0, 0, + NULL, + var_time_min_generate, + VAR_DONT_CACHE, /* dynamic */ + PHASE_REQUEST_HEADERS + ); + + /* TIME_MON */ + msre_engine_variable_register(engine, + "TIME_MON", + VAR_SIMPLE, + 0, 0, + NULL, + var_time_mon_generate, + VAR_DONT_CACHE, /* dynamic */ + PHASE_REQUEST_HEADERS + ); + + /* TIME_SEC */ + msre_engine_variable_register(engine, + "TIME_SEC", + VAR_SIMPLE, + 0, 0, + NULL, + var_time_sec_generate, + VAR_DONT_CACHE, /* dynamic */ + PHASE_REQUEST_HEADERS + ); + + /* TIME_WDAY */ + msre_engine_variable_register(engine, + "TIME_WDAY", + VAR_SIMPLE, + 0, 0, + NULL, + var_time_wday_generate, + VAR_DONT_CACHE, /* dynamic */ + PHASE_REQUEST_HEADERS + ); + + /* TIME_YEAR */ + msre_engine_variable_register(engine, + "TIME_YEAR", + VAR_SIMPLE, + 0, 0, + NULL, + var_time_year_generate, + VAR_DONT_CACHE, /* dynamic */ + PHASE_REQUEST_HEADERS + ); + + /* TX */ + msre_engine_variable_register(engine, + "TX", + VAR_LIST, + 1, 1, + var_generic_list_validate, + var_tx_generate, + VAR_DONT_CACHE, /* dynamic */ + PHASE_REQUEST_HEADERS + ); + + /* WEBAPPID */ + msre_engine_variable_register(engine, + "WEBAPPID", + VAR_SIMPLE, + 0, 0, + NULL, + var_webappid_generate, + VAR_DONT_CACHE, + PHASE_RESPONSE_HEADERS + ); + + /* WEBSERVER_ERROR_LOG */ + msre_engine_variable_register(engine, + "WEBSERVER_ERROR_LOG", + VAR_LIST, + 0, 0, + NULL, + var_webserver_error_log_generate, + VAR_DONT_CACHE, /* dynamic */ + PHASE_REQUEST_HEADERS + ); + + /* XML */ + msre_engine_variable_register(engine, + "XML", + VAR_LIST, + 0, 1, + var_xml_validate, + var_xml_generate, + VAR_DONT_CACHE, /* dynamic */ + PHASE_REQUEST_BODY + ); +} diff --git a/apache2/t/action/.empty b/apache2/t/action/.empty new file mode 100644 index 0000000..e69de29 diff --git a/apache2/t/csv_rx-pm.pl.in b/apache2/t/csv_rx-pm.pl.in new file mode 100755 index 0000000..6ea02ce --- /dev/null +++ b/apache2/t/csv_rx-pm.pl.in @@ -0,0 +1,21 @@ +#!@PERL@ +# +# Example to generate CSV performance data from test results taken from +# test generated by gen_rx-pm.pl. +# +use strict; + +my %H = (); +while (<>) { + chomp; + my ($op, $label, $n, $i, $value) = (m/\s*\d+\)\s+\S+\s+"([^"]*)"\s+(\S+)\s+(\d+) item\(s\): passed\s+\((\d+)\s+\@\s+([-\+\d\.E]+) msec\s.*/); + + next unless defined($value); + $H{$n}{$label} = $value; + +} + +printf "%s, %s, %s, %s\n", qw(N rx1 rx2 pm1); +for (sort {$a <=> $b} keys %H) { + printf "%s, %s, %s, %s\n", $_, $H{$_}{rx1}, $H{$_}{rx2}, $H{$_}{pm1} +}; diff --git a/apache2/t/gen_rx-pm.pl.in b/apache2/t/gen_rx-pm.pl.in new file mode 100755 index 0000000..c5e56ad --- /dev/null +++ b/apache2/t/gen_rx-pm.pl.in @@ -0,0 +1,99 @@ +#!@PERL@ +# +# Generates a test file for comparing @rx and @pm speed. +# +use strict; +use Regexp::Assemble; + +srand(424242); # We want this static, so we can compare different runs + +my $MIN = $ARGV[0] || 0; +my $MAX = $ARGV[1] || 5000; +my $INC = $ARGV[2] || int($MAX * .05); +my $ITERATIONS = 10000; +my $MINSTRLEN = 2; +my $MAXSTRLEN = 8; + +my $match = join '', ('a' .. 'z'); +my @param = (); +my $i=$MIN; +while ($i <= $MAX) { + my $ra = Regexp::Assemble->new; + + while (@param < $i) { + unshift @param, rndstr(); + } + + $ra->add(@param); + + printf ( + "# rx: %6d\n". + "{\n". + " comment => \"rx1 %6d item(s)\",\n". + " type => \"op\",\n". + " name => \"rx\",\n". + " param => qr/%s/,\n". + " input => \"%s\",\n". + " ret => " . (@param ? 0 : 1) . ",". + " iterations => %d,\n". + "},\n", + $i, + $i, + (@param ? '(?:' . join('|', @param) . ')' : ""), + $match, + $ITERATIONS, + ); + + printf ( + "# rx-optimized: %6d\n". + "{\n". + " comment => \"rx2 %6d item(s)\",\n". + " type => \"op\",\n". + " name => \"rx\",\n". + " param => qr/%s/,\n". + " input => \"%s\",\n". + " ret => " . (@param ? 0 : 1) . ",". + " iterations => %d,\n". + "},\n", + $i, + $i, + (@param ? $ra->as_string : ""), + $match, + $ITERATIONS, + ); + + printf ( + "# pm: %6d\n". + "{\n". + " comment => \"pm1 %6d item(s)\",\n". + " type => \"op\",\n". + " name => \"pm\",\n". + " param => \"%s\",\n". + " input => \"%s\",\n". + " ret => 0,". + " iterations => %d,\n". + "},\n", + $i, + $i, + join(' ', @param ? @param : ("''")), + $match, + $ITERATIONS, + ); + + $i = ($i == $MIN) ? ($i + $INC) - ($i % $INC) : $i + $INC; + +} + +sub rndstr { + my @c = ('a' .. 'z'); + my $rndstr; + my $max = int(rand($MAXSTRLEN - $MINSTRLEN)) + $MINSTRLEN; + foreach (1 .. $max) { + $rndstr .= $c[rand @c]; + } + # We need a string that is not in another string for "last" + if ($match =~ m/$rndstr/) { + $rndstr = rndstr(); + } + return $rndstr; +} diff --git a/apache2/t/op/beginsWith.t b/apache2/t/op/beginsWith.t new file mode 100644 index 0000000..831c00b --- /dev/null +++ b/apache2/t/op/beginsWith.t @@ -0,0 +1,45 @@ +### Empty +{ + type => "op", + name => "beginsWith", + param => "", + input => "", + ret => 1, +}, +{ + type => "op", + name => "beginsWith", + param => "TestCase", + input => "", + ret => 0, +}, +{ + type => "op", + name => "beginsWith", + param => "", + input => "TestCase", + ret => 1, +}, + +### General +{ + type => "op", + name => "beginsWith", + param => "abcdef", + input => "abcdef", + ret => 1, +}, +{ + type => "op", + name => "beginsWith", + param => "abcdef", + input => "abcdefghi", + ret => 1, +}, +{ + type => "op", + name => "beginsWith", + param => "abcdef", + input => "abc", + ret => 0, +}, diff --git a/apache2/t/op/contains.t b/apache2/t/op/contains.t new file mode 100644 index 0000000..0b406b4 --- /dev/null +++ b/apache2/t/op/contains.t @@ -0,0 +1,73 @@ +### Empty +{ + type => "op", + name => "contains", + param => "", + input => "", + ret => 1, +}, +{ + type => "op", + name => "contains", + param => "TestCase", + input => "", + ret => 0, +}, +{ + type => "op", + name => "contains", + param => "", + input => "TestCase", + ret => 1, +}, + +### General +{ + type => "op", + name => "contains", + param => "abc", + input => "abcdefghi", + ret => 1, +}, +{ + type => "op", + name => "contains", + param => "def", + input => "abcdefghi", + ret => 1, +}, +{ + type => "op", + name => "contains", + param => "ghi", + input => "abcdefghi", + ret => 1, +}, +{ + type => "op", + name => "contains", + param => "ghij", + input => "abcdefghi", + ret => 0, +}, +{ + type => "op", + name => "contains", + param => "x", + input => "x", + ret => 1, +}, +{ + type => "op", + name => "contains", + param => "y", + input => "xyz", + ret => 1, +}, +{ + type => "op", + name => "contains", + param => "hiding", + input => "hidinX<-not quite, but is later on->hiding", + ret => 1, +}, diff --git a/apache2/t/op/containsWord.t b/apache2/t/op/containsWord.t new file mode 100644 index 0000000..5b66bb5 --- /dev/null +++ b/apache2/t/op/containsWord.t @@ -0,0 +1,108 @@ +### Empty +{ + type => "op", + name => "containsWord", + param => "", + input => "", + ret => 1, +}, +{ + type => "op", + name => "containsWord", + param => "TestCase", + input => "", + ret => 0, +}, +{ + type => "op", + name => "containsWord", + param => "", + input => "TestCase", + ret => 1, +}, + +### General +{ + type => "op", + name => "containsWord", + param => "abc", + input => "abcdefghi", + ret => 0, +}, +{ + type => "op", + name => "containsWord", + param => "def", + input => "abcdefghi", + ret => 0, +}, +{ + type => "op", + name => "containsWord", + param => "ghi", + input => "abcdefghi", + ret => 0, +}, +{ + type => "op", + name => "containsWord", + param => "abc", + input => "abc def ghi", + ret => 1, +}, +{ + type => "op", + name => "containsWord", + param => "def", + input => "abc def ghi", + ret => 1, +}, +{ + type => "op", + name => "containsWord", + param => "ghi", + input => "abc def ghi", + ret => 1, +}, +{ + type => "op", + name => "containsWord", + param => "abc", + input => "abc\0def ghi", + ret => 1, +}, +{ + type => "op", + name => "containsWord", + param => "def", + input => "abc\0def ghi", + ret => 1, +}, +{ + type => "op", + name => "containsWord", + param => "x", + input => "x", + ret => 1, +}, +{ + type => "op", + name => "containsWord", + param => "x", + input => " x ", + ret => 1, +}, +{ + type => "op", + name => "containsWord", + param => "y", + input => "xyz", + ret => 0, +}, +{ + type => "op", + name => "containsWord", + param => "hiding", + input => "hidingX<-not on word boundary, but is later on->hiding", + ret => 1, +}, diff --git a/apache2/t/op/endsWith.t b/apache2/t/op/endsWith.t new file mode 100644 index 0000000..d1b3762 --- /dev/null +++ b/apache2/t/op/endsWith.t @@ -0,0 +1,52 @@ +### Empty +{ + type => "op", + name => "endsWith", + param => "", + input => "", + ret => 1, +}, +{ + type => "op", + name => "endsWith", + param => "TestCase", + input => "", + ret => 0, +}, +{ + type => "op", + name => "endsWith", + param => "", + input => "TestCase", + ret => 1, +}, + +### General +{ + type => "op", + name => "endsWith", + param => "abc", + input => "abcdefghi", + ret => 0, +}, +{ + type => "op", + name => "endsWith", + param => "def", + input => "abcdefghi", + ret => 0, +}, +{ + type => "op", + name => "endsWith", + param => "ghi", + input => "abcdefghi", + ret => 1, +}, +{ + type => "op", + name => "endsWith", + param => "ghi", + input => "abcdef\0ghi", + ret => 1, +}, diff --git a/apache2/t/op/eq.t b/apache2/t/op/eq.t new file mode 100644 index 0000000..b8f2068 --- /dev/null +++ b/apache2/t/op/eq.t @@ -0,0 +1,101 @@ +### Empty +{ + type => "op", + name => "eq", + param => "0", + input => "", + ret => 1, +}, +{ + type => "op", + name => "eq", + param => "5", + input => "", + ret => 0, +}, + +### Invalid +# xxx interpreted as 0 +{ + type => "op", + name => "eq", + param => "xxx", + input => "0", + ret => 1, +}, +# xxx interpreted as 0 +{ + type => "op", + name => "eq", + param => "xxx", + input => "5", + ret => 0, +}, +# xxx interpreted as 0 +{ + type => "op", + name => "eq", + param => "xxx", + input => "-1", + ret => 0, +}, +# xxx interpreted as 0 +{ + type => "op", + name => "eq", + param => "0", + input => "xxx", + ret => 1, +}, +# xxx interpreted as 0 +{ + type => "op", + name => "eq", + param => "5", + input => "xxx", + ret => 0, +}, + +### General +{ + type => "op", + name => "eq", + param => "0", + input => "-5", + ret => 0, +}, +{ + type => "op", + name => "eq", + param => "0", + input => "0", + ret => 1, +}, +{ + type => "op", + name => "eq", + param => "0", + input => "5", + ret => 0, +}, +{ + type => "op", + name => "eq", + param => "5", + input => "0", + ret => 0, +}, +{ + type => "op", + name => "eq", + param => "5", + input => "5", + ret => 1, +}, +{ + type => "op", + name => "eq", + param => "5", + input => "10", + ret => 0, +}, diff --git a/apache2/t/op/ge.t b/apache2/t/op/ge.t new file mode 100644 index 0000000..899c82a --- /dev/null +++ b/apache2/t/op/ge.t @@ -0,0 +1,93 @@ +### Empty +{ + type => "op", + name => "ge", + param => "0", + input => "", + ret => 1, +}, +{ + type => "op", + name => "ge", + param => "5", + input => "", + ret => 0, +}, + +### Invalid +# xxx interpreted as 0 +{ + type => "op", + name => "ge", + param => "xxx", + input => "5", + ret => 1, +}, +# xxx interpreted as 0 +{ + type => "op", + name => "ge", + param => "xxx", + input => "-1", + ret => 0, +}, +# xxx interpreted as 0 +{ + type => "op", + name => "ge", + param => "0", + input => "xxx", + ret => 1, +}, +# xxx interpreted as 0 +{ + type => "op", + name => "ge", + param => "5", + input => "xxx", + ret => 0, +}, + +### General +{ + type => "op", + name => "ge", + param => "0", + input => "-5", + ret => 0, +}, +{ + type => "op", + name => "ge", + param => "0", + input => "0", + ret => 1, +}, +{ + type => "op", + name => "ge", + param => "0", + input => "5", + ret => 1, +}, +{ + type => "op", + name => "ge", + param => "5", + input => "0", + ret => 0, +}, +{ + type => "op", + name => "ge", + param => "5", + input => "5", + ret => 1, +}, +{ + type => "op", + name => "ge", + param => "5", + input => "10", + ret => 1, +}, diff --git a/apache2/t/op/geoLookup.t b/apache2/t/op/geoLookup.t new file mode 100644 index 0000000..716d5e6 --- /dev/null +++ b/apache2/t/op/geoLookup.t @@ -0,0 +1,44 @@ +### Empty +# NOTE: All will return 0 because of lacking DB +{ + type => "op", + name => "geoLookup", + param => "", + input => "", + ret => 0, +}, +{ + type => "op", + name => "geoLookup", + param => "TestCase", + input => "", + ret => 0, +}, + +# Failed Lookup +{ + type => "op", + name => "geoLookup", + param => "", + input => "127.0.0.1", + ret => 0, +}, + +# Good +{ + type => "op", + name => "geoLookup", + param => "", + input => "216.75.21.122", + #ret => 1, + ret => 0, +}, +{ + type => "op", + name => "geoLookup", + param => "", + input => "www.modsecurity.org", + #ret => 1, + ret => 0, +}, + diff --git a/apache2/t/op/gt.t b/apache2/t/op/gt.t new file mode 100644 index 0000000..168d81f --- /dev/null +++ b/apache2/t/op/gt.t @@ -0,0 +1,93 @@ +### Empty +{ + type => "op", + name => "gt", + param => "0", + input => "", + ret => 0, +}, +{ + type => "op", + name => "gt", + param => "5", + input => "", + ret => 0, +}, + +### Invalid +# xxx interpreted as 0 +{ + type => "op", + name => "gt", + param => "xxx", + input => "5", + ret => 1, +}, +# xxx interpreted as 0 +{ + type => "op", + name => "gt", + param => "xxx", + input => "-1", + ret => 0, +}, +# xxx interpreted as 0 +{ + type => "op", + name => "gt", + param => "-1", + input => "xxx", + ret => 1, +}, +# xxx interpreted as 0 +{ + type => "op", + name => "gt", + param => "5", + input => "xxx", + ret => 0, +}, + +### General +{ + type => "op", + name => "gt", + param => "0", + input => "-5", + ret => 0, +}, +{ + type => "op", + name => "gt", + param => "0", + input => "0", + ret => 0, +}, +{ + type => "op", + name => "gt", + param => "0", + input => "5", + ret => 1, +}, +{ + type => "op", + name => "gt", + param => "5", + input => "0", + ret => 0, +}, +{ + type => "op", + name => "gt", + param => "5", + input => "5", + ret => 0, +}, +{ + type => "op", + name => "gt", + param => "5", + input => "10", + ret => 1, +}, diff --git a/apache2/t/op/inspectFile.t b/apache2/t/op/inspectFile.t new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/apache2/t/op/inspectFile.t @@ -0,0 +1 @@ + diff --git a/apache2/t/op/le.t b/apache2/t/op/le.t new file mode 100644 index 0000000..b6a8417 --- /dev/null +++ b/apache2/t/op/le.t @@ -0,0 +1,93 @@ +### Empty +{ + type => "op", + name => "le", + param => "0", + input => "", + ret => 1, +}, +{ + type => "op", + name => "le", + param => "5", + input => "", + ret => 1, +}, + +### Invalid +# xxx interpreted as 0 +{ + type => "op", + name => "le", + param => "xxx", + input => "5", + ret => 0, +}, +# xxx interpreted as 0 +{ + type => "op", + name => "le", + param => "xxx", + input => "-1", + ret => 1, +}, +# xxx interpreted as 0 +{ + type => "op", + name => "le", + param => "0", + input => "xxx", + ret => 1, +}, +# xxx interpreted as 0 +{ + type => "op", + name => "le", + param => "5", + input => "xxx", + ret => 1, +}, + +### General +{ + type => "op", + name => "le", + param => "0", + input => "-5", + ret => 1, +}, +{ + type => "op", + name => "le", + param => "0", + input => "0", + ret => 1, +}, +{ + type => "op", + name => "le", + param => "0", + input => "5", + ret => 0, +}, +{ + type => "op", + name => "le", + param => "5", + input => "0", + ret => 1, +}, +{ + type => "op", + name => "le", + param => "5", + input => "5", + ret => 1, +}, +{ + type => "op", + name => "le", + param => "5", + input => "10", + ret => 0, +}, diff --git a/apache2/t/op/lt.t b/apache2/t/op/lt.t new file mode 100644 index 0000000..59882d4 --- /dev/null +++ b/apache2/t/op/lt.t @@ -0,0 +1,93 @@ +### Empty +{ + type => "op", + name => "lt", + param => "0", + input => "", + ret => 0, +}, +{ + type => "op", + name => "lt", + param => "5", + input => "", + ret => 1, +}, + +### Invalid +# xxx interpreted as 0 +{ + type => "op", + name => "lt", + param => "xxx", + input => "5", + ret => 0, +}, +# xxx interpreted as 0 +{ + type => "op", + name => "lt", + param => "xxx", + input => "-1", + ret => 1, +}, +# xxx interpreted as 0 +{ + type => "op", + name => "lt", + param => "-1", + input => "xxx", + ret => 0, +}, +# xxx interpreted as 0 +{ + type => "op", + name => "lt", + param => "5", + input => "xxx", + ret => 1, +}, + +### General +{ + type => "op", + name => "lt", + param => "0", + input => "-5", + ret => 1, +}, +{ + type => "op", + name => "lt", + param => "0", + input => "0", + ret => 0, +}, +{ + type => "op", + name => "lt", + param => "0", + input => "5", + ret => 0, +}, +{ + type => "op", + name => "lt", + param => "5", + input => "0", + ret => 1, +}, +{ + type => "op", + name => "lt", + param => "5", + input => "5", + ret => 0, +}, +{ + type => "op", + name => "lt", + param => "5", + input => "10", + ret => 0, +}, diff --git a/apache2/t/op/m.t b/apache2/t/op/m.t new file mode 100644 index 0000000..def6d08 --- /dev/null +++ b/apache2/t/op/m.t @@ -0,0 +1,52 @@ +### Empty +{ + type => "op", + name => "m", + param => "", + input => "", + ret => 1, +}, +{ + type => "op", + name => "m", + param => "TestCase", + input => "", + ret => 0, +}, +{ + type => "op", + name => "m", + param => "", + input => "TestCase", + ret => 1, +}, + +### General +{ + type => "op", + name => "m", + param => "abc", + input => "abcdefghi", + ret => 1, +}, +{ + type => "op", + name => "m", + param => "def", + input => "abcdefghi", + ret => 1, +}, +{ + type => "op", + name => "m", + param => "ghi", + input => "abcdefghi", + ret => 1, +}, +{ + type => "op", + name => "m", + param => "ghij", + input => "abcdefghi", + ret => 0, +}, diff --git a/apache2/t/op/noMatch.t b/apache2/t/op/noMatch.t new file mode 100644 index 0000000..8775dd5 --- /dev/null +++ b/apache2/t/op/noMatch.t @@ -0,0 +1,23 @@ +### Empty +{ + type => "op", + name => "noMatch", + param => "", + input => "", + ret => 0, +}, +{ + type => "op", + name => "noMatch", + param => "TestCase", + input => "", + ret => 0, +}, +{ + type => "op", + name => "noMatch", + param => "", + input => "TestCase", + ret => 0, +}, + diff --git a/apache2/t/op/pm.t b/apache2/t/op/pm.t new file mode 100644 index 0000000..2850a81 --- /dev/null +++ b/apache2/t/op/pm.t @@ -0,0 +1,112 @@ +### Empty +{ + type => "op", + name => "pm", + param => "TestCase", + input => "", + ret => 0, +}, + +### General +{ + type => "op", + name => "pm", + param => "abc", + input => "abcdefghi", + ret => 1, +}, +{ + type => "op", + name => "pm", + param => "def", + input => "abcdefghi", + ret => 1, +}, +{ + type => "op", + name => "pm", + param => "ghi", + input => "abcdefghi", + ret => 1, +}, +{ + type => "op", + name => "pm", + param => "ghij", + input => "abcdefghi", + ret => 0, +}, + +### Multiple +{ + type => "op", + name => "pm", + param => "abc def ghi", + input => "abcxxxyyy", + ret => 1, +}, +{ + type => "op", + name => "pm", + param => "abc def ghi", + input => "xxxabcyyy", + ret => 1, +}, +{ + type => "op", + name => "pm", + param => "abc def ghi", + input => "xxxyyyabc", + ret => 1, +}, +{ + type => "op", + name => "pm", + param => "abc def ghi", + input => "defxxxyyy", + ret => 1, +}, +{ + type => "op", + name => "pm", + param => "abc def ghi", + input => "xxxdefyyy", + ret => 1, +}, +{ + type => "op", + name => "pm", + param => "abc def ghi", + input => "xxxyyydef", + ret => 1, +}, +{ + type => "op", + name => "pm", + param => "abc def ghi", + input => "ghixxxyyy", + ret => 1, +}, +{ + type => "op", + name => "pm", + param => "abc def ghi", + input => "xxxghiyyy", + ret => 1, +}, +{ + type => "op", + name => "pm", + param => "abc def ghi", + input => "xxxyyyghi", + ret => 1, +}, + +### Long +{ + type => "op", + name => "pm", + param => "000 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999", + input => "xxxyyy999", + ret => 1, +}, diff --git a/apache2/t/op/pmFromFile-01.dat b/apache2/t/op/pmFromFile-01.dat new file mode 100644 index 0000000..f7b07ea --- /dev/null +++ b/apache2/t/op/pmFromFile-01.dat @@ -0,0 +1,4 @@ +abc +def +ghi +xxx yyy zzz diff --git a/apache2/t/op/pmFromFile.t b/apache2/t/op/pmFromFile.t new file mode 100644 index 0000000..b565d86 --- /dev/null +++ b/apache2/t/op/pmFromFile.t @@ -0,0 +1,45 @@ +### No Match +{ + type => "op", + name => "pmFromFile", + param => "op/pmFromFile-01.dat", + input => "xxxyyyzzz", + ret => 0, +}, + +### Multiple +{ + type => "op", + name => "pmFromFile", + param => "op/pmFromFile-01.dat", + input => "defxxxyyy", + ret => 1, +}, +{ + type => "op", + name => "pmFromFile", + param => "op/pmFromFile-01.dat", + input => "xxxdefyyy", + ret => 1, +}, +{ + type => "op", + name => "pmFromFile", + param => "op/pmFromFile-01.dat", + input => "xxxyyydef", + ret => 1, +}, +{ + type => "op", + name => "pmFromFile", + param => "op/pmFromFile-01.dat", + input => "xxx yyy zzz", + ret => 1, +}, +{ + type => "op", + name => "pmFromFile", + param => "op/pmFromFile-01.dat", + input => "xxx yyy", + ret => 0, +}, diff --git a/apache2/t/op/rbl.t b/apache2/t/op/rbl.t new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/apache2/t/op/rbl.t @@ -0,0 +1 @@ + diff --git a/apache2/t/op/rx.t b/apache2/t/op/rx.t new file mode 100644 index 0000000..4be49e7 --- /dev/null +++ b/apache2/t/op/rx.t @@ -0,0 +1,62 @@ +### Empty +{ + type => "op", + name => "rx", + param => "", + input => "", + ret => 1, +}, +{ + type => "op", + name => "rx", + param => "TestCase", + input => "", + ret => 0, +}, +{ + type => "op", + name => "rx", + param => "", + input => "TestCase", + ret => 1, +}, + +### General +{ + type => "op", + name => "rx", + param => "abc", + input => "abcdefghi", + ret => 1, +}, +{ + type => "op", + name => "rx", + param => "def", + input => "abcdefghi", + ret => 1, +}, +{ + type => "op", + name => "rx", + param => "ghi", + input => "abcdefghi", + ret => 1, +}, +{ + type => "op", + name => "rx", + param => "ghij", + input => "abcdefghi", + ret => 0, +}, + +### Complex regex +{ + type => "op", + name => "rx", + param => qr/^([^=])\s*=\s*((?:abc)+(?:def|ghi){2})$/i, + input => "x =AbCDeFgHi", + ret => 1, +}, + diff --git a/apache2/t/op/streq.t b/apache2/t/op/streq.t new file mode 100644 index 0000000..76451fe --- /dev/null +++ b/apache2/t/op/streq.t @@ -0,0 +1,52 @@ +### Empty +{ + type => "op", + name => "streq", + param => "", + input => "", + ret => 1, +}, +{ + type => "op", + name => "streq", + param => "TestCase", + input => "", + ret => 0, +}, +{ + type => "op", + name => "streq", + param => "", + input => "TestCase", + ret => 0, +}, + +### General +{ + type => "op", + name => "streq", + param => "abc", + input => "abcdefghi", + ret => 0, +}, +{ + type => "op", + name => "streq", + param => "def", + input => "abcdefghi", + ret => 0, +}, +{ + type => "op", + name => "streq", + param => "ghi", + input => "abcdefghi", + ret => 0, +}, +{ + type => "op", + name => "streq", + param => "abcdefghi", + input => "abcdefghi", + ret => 1, +}, diff --git a/apache2/t/op/unconditionalMatch.t b/apache2/t/op/unconditionalMatch.t new file mode 100644 index 0000000..56458d8 --- /dev/null +++ b/apache2/t/op/unconditionalMatch.t @@ -0,0 +1,23 @@ +### Empty +{ + type => "op", + name => "unconditionalMatch", + param => "", + input => "", + ret => 1, +}, +{ + type => "op", + name => "unconditionalMatch", + param => "TestCase", + input => "", + ret => 1, +}, +{ + type => "op", + name => "unconditionalMatch", + param => "", + input => "TestCase", + ret => 1, +}, + diff --git a/apache2/t/op/validateByteRange.t b/apache2/t/op/validateByteRange.t new file mode 100644 index 0000000..21a535e --- /dev/null +++ b/apache2/t/op/validateByteRange.t @@ -0,0 +1,54 @@ +### Empty +{ + type => "op", + name => "validateByteRange", + param => "0-255", + input => "", + ret => 0, +}, +{ + type => "op", + name => "validateByteRange", + param => "", + input => "TestCase", + ret => 1, +}, + +### Invalid +{ + type => "op", + name => "validateByteRange", + param => "xxx", + input => "TestCase", + ret => 1, +}, +{ + type => "op", + name => "validateByteRange", + param => "xxx", + input => "\x00", + ret => 0, +}, + +### General +{ + type => "op", + name => "validateByteRange", + param => "0-255", + input => "abcdefghi", + ret => 0, +}, +{ + type => "op", + name => "validateByteRange", + param => ord("a")."-".ord("i"), + input => "abcdefghi", + ret => 0, +}, +{ + type => "op", + name => "validateByteRange", + param => ord("a")."-".ord("i"), + input => "abcdefghij", + ret => 1, +}, diff --git a/apache2/t/op/validateDTD.t b/apache2/t/op/validateDTD.t new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/apache2/t/op/validateDTD.t @@ -0,0 +1 @@ + diff --git a/apache2/t/op/validateSchema.t b/apache2/t/op/validateSchema.t new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/apache2/t/op/validateSchema.t @@ -0,0 +1 @@ + diff --git a/apache2/t/op/validateUrlEncoding.t b/apache2/t/op/validateUrlEncoding.t new file mode 100644 index 0000000..904b1c3 --- /dev/null +++ b/apache2/t/op/validateUrlEncoding.t @@ -0,0 +1,101 @@ +### Empty +{ + type => "op", + name => "validateUrlEncoding", + param => "", + input => "", + ret => 0, +}, + +### General +{ + type => "op", + name => "validateUrlEncoding", + param => "", + input => "Hello%20World!", + ret => 0, +}, +{ + type => "op", + name => "validateUrlEncoding", + param => "", + input => "Hello+World!", + ret => 0, +}, +{ + type => "op", + name => "validateUrlEncoding", + param => "", + input => "HelloWorld!", + ret => 0, +}, +{ + type => "op", + name => "validateUrlEncoding", + param => "", + input => "%00Hello%20World!", + ret => 0, +}, +{ + type => "op", + name => "validateUrlEncoding", + param => "", + input => "Hello%20World!%00", + ret => 0, +}, +{ + type => "op", + name => "validateUrlEncoding", + param => "", + input => "%00", + ret => 0, +}, +{ + type => "op", + name => "validateUrlEncoding", + param => "", + input => "%ff", + ret => 0, +}, +{ + type => "op", + name => "validateUrlEncoding", + param => "", + input => "%0", + ret => 1, +}, +{ + type => "op", + name => "validateUrlEncoding", + param => "", + input => "%f", + ret => 1, +}, +{ + type => "op", + name => "validateUrlEncoding", + param => "", + input => "%", + ret => 1, +}, +{ + type => "op", + name => "validateUrlEncoding", + param => "", + input => "%0z", + ret => 1, +}, +{ + type => "op", + name => "validateUrlEncoding", + param => "", + input => "%z0", + ret => 1, +}, +{ + type => "op", + name => "validateUrlEncoding", + param => "", + input => "%0%", + ret => 1, +}, diff --git a/apache2/t/op/validateUtf8Encoding.t b/apache2/t/op/validateUtf8Encoding.t new file mode 100644 index 0000000..8c3825a --- /dev/null +++ b/apache2/t/op/validateUtf8Encoding.t @@ -0,0 +1,260 @@ +### Empty +{ + type => "op", + name => "validateUtf8Encoding", + param => "", + input => "", + ret => 0, +}, + +### Valid "I can eat glass and it does not hurt me." +# Greek +{ + type => "op", + name => "validateUtf8Encoding", + param => "", + input => "ὕαλον ϕαγεῖν δύναμαι· τοῦτο οὔ με βλάπτει.", + ret => 0, +}, +# French +{ + type => "op", + name => "validateUtf8Encoding", + param => "", + input => "Je peux manger du verre, ça ne me fait pas de mal.", + ret => 0, +}, +# Spanish +{ + type => "op", + name => "validateUtf8Encoding", + param => "", + input => "Puedo comer vidrio, no me hace daño.", + ret => 0, +}, +# Esparanto +{ + type => "op", + name => "validateUtf8Encoding", + param => "", + input => "Mi povas manĝi vitron, ĝi ne damaĝas min.", + ret => 0, +}, +# Latin +{ + type => "op", + name => "validateUtf8Encoding", + param => "", + input => "Ic mæg glæs eotan ond hit ne hearmiað me.", + ret => 0, +}, +# Serbian +{ + type => "op", + name => "validateUtf8Encoding", + param => "", + input => "Могу јести стакло а да ми не шкоди.", + ret => 0, +}, +# Russian +{ + type => "op", + name => "validateUtf8Encoding", + param => "", + input => "Я могу есть стекло, оно мне не вредит.", + ret => 0, +}, +# Armenian +{ + type => "op", + name => "validateUtf8Encoding", + param => "", + input => "Կրնամ Õ¡ÕºÕ¡Õ¯Õ« ուտել և Õ«Õ¶Õ®Õ« Õ¡Õ¶Õ°Õ¡Õ¶Õ£Õ«Õ½Õ¿ չըներ։", + ret => 0, +}, +# Turkish +{ + type => "op", + name => "validateUtf8Encoding", + param => "", + input => "جام ييه بلورم بڭا ضررى طوقونمز", + ret => 0, +}, +# Hindi +{ + type => "op", + name => "validateUtf8Encoding", + param => "", + input => "मैं काँच खा सकता हूँ, मुझे उस से कोई पीडा नहीं होती.", + ret => 0, +}, +# Arabic +{ + type => "op", + name => "validateUtf8Encoding", + param => "", + input => "أنا قادر على أكل الزجاج و هذا لا يؤلمني.", + ret => 0, +}, +# Hebrew +{ + type => "op", + name => "validateUtf8Encoding", + param => "", + input => "אני יכול לאכול זכוכית וזה לא מזיק לי.", + ret => 0, +}, +# Japanese +{ + type => "op", + name => "validateUtf8Encoding", + param => "", + input => "私はガラスを食べられます。それは私を傷つけません。", + ret => 0, +}, +# Thai +{ + type => "op", + name => "validateUtf8Encoding", + param => "", + input => "ฉันกินกระจกได้ แต่มันไม่ทำให้ฉันเจ็บ", + ret => 0, +}, +# Korean +{ + type => "op", + name => "validateUtf8Encoding", + param => "", + input => "나는 유리를 먹을 수 있어요. 그래도 아프지 않아요", + ret => 0, +}, +# Navajo +{ + type => "op", + name => "validateUtf8Encoding", + param => "", + input => "Tsésǫʼ yishą́ągo bííníshghah dóó doo shił neezgai da.", + ret => 0, +}, +# Icelandic +{ + type => "op", + name => "validateUtf8Encoding", + param => "", + input => "Ég get etið gler án þess að meiða mig.", + ret => 0, +}, +# Sanskrit +{ + type => "op", + name => "validateUtf8Encoding", + param => "", + input => "काचं शक्नोम्यत्तुम् । नोपहिनस्ति माम् ॥", + ret => 0, +}, +# English Braille +{ + type => "op", + name => "validateUtf8Encoding", + param => "", + input => "⠊⠀⠉⠁⠝⠀⠑⠁⠞⠀⠛⠇⠁⠎⠎⠀⠁⠝⠙⠀⠊⠞⠀⠙⠕⠑⠎⠝⠞⠀⠓⠥⠗⠞⠀⠍⠑", + ret => 0, +}, +# Danish +{ + type => "op", + name => "validateUtf8Encoding", + param => "", + input => "Jeg kan spise glas, det gør ikke ondt pÃ¥ mig.", + ret => 0, +}, +# Hungarian +{ + type => "op", + name => "validateUtf8Encoding", + param => "", + input => "Meg tudom enni az üveget, nem lesz tőle bajom.", + ret => 0, +}, +# Estonian +{ + type => "op", + name => "validateUtf8Encoding", + param => "", + input => "Ma võin klaasi süüa, see ei tee mulle midagi.", + ret => 0, +}, +# Czech +{ + type => "op", + name => "validateUtf8Encoding", + param => "", + input => "Mohu jíst sklo, neublíží mi.", + ret => 0, +}, +# Slovak +{ + type => "op", + name => "validateUtf8Encoding", + param => "", + input => "Môžem jesÅ¥ sklo. Nezraní ma.", + ret => 0, +}, +# Polish +{ + type => "op", + name => "validateUtf8Encoding", + param => "", + input => "Mogę jeść szkło i mi nie szkodzi.", + ret => 0, +}, +# Symbols +{ + type => "op", + name => "validateUtf8Encoding", + param => "", + input=>"∮E⋅da=Qn→∞∑f(i)=∏g(i)∀x∈ℝ:⌈x⌉=−⌊−x⌋α∧¬β=¬(¬α∨β)ℕ⊆ℕ₀⊂ℤ⊂ℚ⊂ℝ⊂ℂ⊥ 0, +}, +### Invalid +# Umlauted a +{ + type => "op", + name => "validateUtf8Encoding", + param => "", + input => "\x00\xe4", + ret => 1, +}, +# Umlauted a +{ + type => "op", + name => "validateUtf8Encoding", + param => "", + input => "\xe4", + ret => 1, +}, +# +{ + type => "op", + name => "validateUtf8Encoding", + param => "", + input => "\x03\xbf", + ret => 1, +}, +# +{ + type => "op", + name => "validateUtf8Encoding", + param => "", + input => "\xc9\x3b", + ret => 1, +}, +### Invalid Full width +# +{ + type => "op", + name => "validateUtf8Encoding", + param => "", + input => "\xFF\x00", + ret => 1, +}, diff --git a/apache2/t/op/verifyCC.t b/apache2/t/op/verifyCC.t new file mode 100644 index 0000000..9116278 --- /dev/null +++ b/apache2/t/op/verifyCC.t @@ -0,0 +1,514 @@ +### Empty +# empty w/re not matching empty +{ + type => "op", + name => "verifyCC", + param => "\d+", + input => "", + ret => 0, +}, +# empty w/re matching empty +{ + type => "op", + name => "verifyCC", + param => '\d*', + input => "", + ret => 0, +}, + +### Non-matching +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "TestCase", + ret => 0, +}, + +### No digits in match +{ + type => "op", + name => "verifyCC", + param => 'TestCase', + input => "TestCase", + ret => 0, +}, + +### Too generic RE w/no matchs (Luhn will be called until all fail) +{ + type => "op", + name => "verifyCC", + param => '.*', + input => "TestCase", + ret => 0, +}, + +### Test Good CC# +# Mastercard +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "5484605089158216", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "5574407071707154", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "5351341509714210", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "5585166974020647", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "5492180332479256", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "5111178142162816", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "5511424748431031", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "5259964281562326", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "5138342589974385", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "5362069587634979", + ret => 1, +}, +# VISA 16 digit +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "4916545704601136", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "4539501231827691", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "4556338049595394", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "4929326438756024", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "4485432027326322", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "4532104980682081", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "4485974616349298", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "4916580487207199", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "4532009746910413", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "4024007144622932", + ret => 1, +}, +# VISA 13 digit +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "4556324125126", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "4067482954141", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "4532402654980", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "4539709679875", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "4024007182237", + ret => 1, +}, +# American Express +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "343918934573386", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "344881778330710", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "345439478558905", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "346465614421111", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "372263817755618", + ret => 1, +}, +# Discover +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "6011402777433576", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "6011890045362751", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "6011439091242416", + ret => 1, +}, +# Diners Club +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "30162519308318", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "30311556856867", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "36850112043985", + ret => 1, +}, +# enRoute +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "201427829075664", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "201434726660424", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "201453368666085", + ret => 1, +}, +# JCB 15 digit +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "210091499965007", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "210072739882947", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "180013970064072", + ret => 1, +}, +# JCB 16 digit +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "3096676276259096", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "3158726040010070", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "3096531217494742", + ret => 1, +}, +# Voyager +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "869974262335041", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "869905005856398", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "869950500085465", + ret => 1, +}, + +### Test Bad CC# +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d+)(?:[^\d]|$)', + input => "1234567890012345", + ret => 0, +}, + +### Test regex + Luhn +# from http://www.merriampark.com/anatomycc.htm +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d{4}\-?\d{4}\-?\d{2}\-?\d{2}\-?\d{1,4})(?:[^\d]|$)', + input => "4417123456789113", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d{4}\-?\d{4}\-?\d{2}\-?\d{2}\-?\d{1,4})(?:[^\d]|$)', + input => "4408041234567893", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d{4}\-?\d{4}\-?\d{2}\-?\d{2}\-?\d{1,4})(?:[^\d]|$)', + input => "4408041234567890", + ret => 0, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d{4}\-?\d{4}\-?\d{2}\-?\d{2}\-?\d{1,4})(?:[^\d]|$)', + input => "4417123456789112", + ret => 0, +}, +# on word boundary +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d{4}\-?\d{4}\-?\d{2}\-?\d{2}\-?\d{1,4})(?:[^\d]|$)', + input => "a5484605089158216", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d{4}\-?\d{4}\-?\d{2}\-?\d{2}\-?\d{1,4})(?:[^\d]|$)', + input => "a5484605089158216b", + ret => 1, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d{4}\-?\d{4}\-?\d{2}\-?\d{2}\-?\d{1,4})(?:[^\d]|$)', + input => "5484605089158216b", + ret => 1, +}, +# valid patterns +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d{4}\-?\d{4}\-?\d{2}\-?\d{2}\-?\d{1,4})(?:[^\d]|$)', + input => "5484-6050-8915-8216", + ret => 1, +}, +# changed digit from table above +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d{4}\-?\d{4}\-?\d{2}\-?\d{2}\-?\d{1,4})(?:[^\d]|$)', + input => "5484605089158217", + ret => 0, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d{4}\-?\d{4}\-?\d{2}\-?\d{2}\-?\d{1,4})(?:[^\d]|$)', + input => "5574407071807154", + ret => 0, +}, +# wrong patterns +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d{4}\-?\d{4}\-?\d{2}\-?\d{2}\-?\d{1,4})(?:[^\d]|$)', + input => "5-484-6050-8915-8216", + ret => 0, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d{4}\-?\d{4}\-?\d{2}\-?\d{2}\-?\d{1,4})(?:[^\d]|$)', + input => "5484 6050 8915 8216", + ret => 0, +}, +# not on digits boundary +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d{4}\-?\d{4}\-?\d{2}\-?\d{2}\-?\d{1,4})(?:[^\d]|$)', + input => "15484605089158216", + ret => 0, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d{4}\-?\d{4}\-?\d{2}\-?\d{2}\-?\d{1,4})(?:[^\d]|$)', + input => "154846050891582162", + ret => 0, +}, +{ + type => "op", + name => "verifyCC", + param => '(?:^|[^\d])(\d{4}\-?\d{4}\-?\d{2}\-?\d{2}\-?\d{1,4})(?:[^\d]|$)', + input => "54846050891582162", + ret => 0, +}, diff --git a/apache2/t/op/within.t b/apache2/t/op/within.t new file mode 100644 index 0000000..9d86dcd --- /dev/null +++ b/apache2/t/op/within.t @@ -0,0 +1,52 @@ +### Empty +{ + type => "op", + name => "within", + param => "", + input => "", + ret => 1, +}, +{ + type => "op", + name => "within", + param => "TestCase", + input => "", + ret => 1, +}, +{ + type => "op", + name => "within", + param => "", + input => "TestCase", + ret => 0, +}, + +### General +{ + type => "op", + name => "within", + param => "abcdefghi", + input => "abc", + ret => 1, +}, +{ + type => "op", + name => "within", + param => "abcdefghi", + input => "def", + ret => 1, +}, +{ + type => "op", + name => "within", + param => "abcdefghi", + input => "ghi", + ret => 1, +}, +{ + type => "op", + name => "within", + param => "abcdefghi", + input => "ghij", + ret => 0, +}, diff --git a/apache2/t/regression/action/00-disruptive-actions.t b/apache2/t/regression/action/00-disruptive-actions.t new file mode 100644 index 0000000..c37133b --- /dev/null +++ b/apache2/t/regression/action/00-disruptive-actions.t @@ -0,0 +1,531 @@ +### Tests all of the actions in each phase + +# Pass +{ + type => "action", + comment => "pass in phase:1", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecAction "phase:1,pass" + SecAction "phase:1,deny" + ), + match_log => { + error => [ qr/ModSecurity: Warning. Unconditional match in SecAction/, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "action", + comment => "pass in phase:2", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecAction "phase:2,pass" + SecAction "phase:2,deny" + ), + match_log => { + error => [ qr/ModSecurity: Warning. Unconditional match in SecAction/, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "action", + comment => "pass in phase:3", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecDebugLog "$ENV{DEBUG_LOG}" + SecDebugLogLevel 4 + SecAction "phase:3,pass" + SecAction "phase:3,deny" + ), + match_log => { + error => [ qr/ModSecurity: Warning. Unconditional match in SecAction/, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "action", + comment => "pass in phase:4", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecDebugLog "$ENV{DEBUG_LOG}" + SecDebugLogLevel 4 + SecAction "phase:4,pass" + SecAction "phase:4,deny" + ), + match_log => { + error => [ qr/ModSecurity: Warning. Unconditional match in SecAction/, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, + +# Allow +{ + type => "action", + comment => "allow in phase:1", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecAction "phase:1,allow" + SecAction "phase:1,deny" + ), + match_log => { + error => [ qr/ModSecurity: Access allowed \(phase 1\). Unconditional match in SecAction/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "action", + comment => "allow in phase:2", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecAction "phase:2,allow" + SecAction "phase:2,deny" + ), + match_log => { + error => [ qr/ModSecurity: Access allowed \(phase 2\). Unconditional match in SecAction/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "action", + comment => "allow in phase:3", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecDebugLog "$ENV{DEBUG_LOG}" + SecDebugLogLevel 4 + SecAction "phase:3,allow" + SecAction "phase:3,deny" + ), + match_log => { + error => [ qr/ModSecurity: Access allowed \(phase 3\). Unconditional match in SecAction/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "action", + comment => "allow in phase:4", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecDebugLog "$ENV{DEBUG_LOG}" + SecDebugLogLevel 4 + SecAction "phase:4,allow" + SecAction "phase:4,deny" + ), + match_log => { + error => [ qr/ModSecurity: Access allowed \(phase 4\). Unconditional match in SecAction/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, + +# Deny +{ + type => "action", + comment => "deny in phase:1", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecAction "phase:1,deny" + ), + match_log => { + error => [ qr/Access denied with code 403 \(phase 1\). Unconditional match in SecAction./, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "action", + comment => "deny in phase:2", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecAction "phase:2,deny" + ), + match_log => { + error => [ qr/Access denied with code 403 \(phase 2\). Unconditional match in SecAction./, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "action", + comment => "deny in phase:3", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecDebugLog "$ENV{DEBUG_LOG}" + SecDebugLogLevel 4 + SecAction "phase:3,deny" + ), + match_log => { + error => [ qr/Access denied with code 403 \(phase 3\). Unconditional match in SecAction./, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "action", + comment => "deny in phase:4", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecDebugLog "$ENV{DEBUG_LOG}" + SecDebugLogLevel 4 + SecAction "phase:4,deny" + ), + match_log => { + error => [ qr/Access denied with code 403 \(phase 4\). Unconditional match in SecAction./, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, + +# Drop +{ + type => "action", + comment => "drop in phase:1", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecAction "phase:1,drop" + ), + match_log => { + error => [ qr/Access denied with connection close \(phase 1\). Unconditional match in SecAction./, 1 ], + }, + match_response => { + status => qr/^500$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "action", + comment => "drop in phase:2", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecAction "phase:2,drop" + ), + match_log => { + error => [ qr/Access denied with connection close \(phase 2\). Unconditional match in SecAction./, 1 ], + }, + match_response => { + status => qr/^500$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "action", + comment => "drop in phase:3", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecDebugLog "$ENV{DEBUG_LOG}" + SecDebugLogLevel 4 + SecAction "phase:3,drop" + ), + match_log => { + error => [ qr/Access denied with connection close \(phase 3\). Unconditional match in SecAction./, 1 ], + }, + match_response => { + status => qr/^500$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "action", + comment => "drop in phase:4", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecDebugLog "$ENV{DEBUG_LOG}" + SecDebugLogLevel 4 + SecAction "phase:4,drop" + ), + match_log => { + error => [ qr/Access denied with connection close \(phase 4\). Unconditional match in SecAction./, 1 ], + }, + match_response => { + status => qr/^500$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, + +# Redirect +{ + type => "action", + comment => "redirect in phase:1 (get)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecRule REQUEST_URI "\@streq /test2.txt" "phase:1,redirect:'http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt'" + ), + match_log => { + error => [ qr/ModSecurity: Access denied with redirection to .* using status 302 \(phase 1\)/, 1 ], + }, + match_response => { + status => qr/^200$/, + content => qr/^TEST$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test2.txt", + ), +}, +{ + type => "action", + comment => "redirect in phase:2 (get)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecRule REQUEST_URI "\@streq /test2.txt" "phase:2,redirect:'http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt'" + ), + match_log => { + error => [ qr/ModSecurity: Access denied with redirection to .* using status 302 \(phase 2\)/, 1 ], + }, + match_response => { + status => qr/^200$/, + content => qr/^TEST$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test2.txt", + ), +}, +{ + type => "action", + comment => "redirect in phase:3 (get)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecDebugLog "$ENV{DEBUG_LOG}" + SecDebugLogLevel 4 + SecRule REQUEST_URI "\@streq /test2.txt" "phase:3,redirect:'http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt'" + ), + match_log => { + error => [ qr/ModSecurity: Access denied with redirection to .* using status 302 \(phase 3\)/, 1 ], + }, + match_response => { + status => qr/^200$/, + content => qr/^TEST$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test2.txt", + ), +}, +{ + type => "action", + comment => "redirect in phase:4 (get)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecDebugLog "$ENV{DEBUG_LOG}" + SecDebugLogLevel 4 + SecRule REQUEST_URI "\@streq /test2.txt" "phase:4,redirect:'http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt'" + ), + match_log => { + error => [ qr/ModSecurity: Access denied with redirection to .* using status 302 \(phase 4\)/, 1 ], + }, + match_response => { + status => qr/^200$/, + content => qr/^TEST$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test2.txt", + ), +}, + +# Proxy +{ + type => "action", + comment => "proxy in phase:1 (get)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecRule REQUEST_URI "\@streq /test2.txt" "phase:1,proxy:'http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt'" + ), + match_log => { + error => [ qr/ModSecurity: Access denied using proxy to \(phase 1\)/, 1 ], + }, + match_response => { + status => qr/^200$/, + content => qr/^TEST$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test2.txt", + ), +}, +{ + type => "action", + comment => "proxy in phase:2 (get)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecRule REQUEST_URI "\@streq /test2.txt" "phase:2,proxy:'http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt'" + ), + match_log => { + error => [ qr/ModSecurity: Access denied using proxy to \(phase 2\)/, 1 ], + }, + match_response => { + status => qr/^200$/, + content => qr/^TEST$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test2.txt", + ), +}, +{ + type => "action", + comment => "proxy in phase:3 (get)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecDebugLog "$ENV{DEBUG_LOG}" + SecDebugLogLevel 4 + SecRule REQUEST_URI "\@streq /test2.txt" "phase:3,proxy:'http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt'" + ), + match_log => { + error => [ qr/ModSecurity: Access denied with code 500 \(phase 3\) \(Configuration Error: Proxy action requested but it does not work in output phases\)./, 1 ], + }, + match_response => { + status => qr/^500$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test2.txt", + ), +}, +{ + type => "action", + comment => "proxy in phase:4 (get)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecDebugLog "$ENV{DEBUG_LOG}" + SecDebugLogLevel 4 + SecRule REQUEST_URI "\@streq /test2.txt" "phase:4,proxy:'http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt'" + ), + match_log => { + error => [ qr/ModSecurity: Access denied with code 500 \(phase 4\) \(Configuration Error: Proxy action requested but it does not work in output phases\)./, 1 ], + }, + match_response => { + status => qr/^500$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test2.txt", + ), +}, diff --git a/apache2/t/regression/action/00-meta.t b/apache2/t/regression/action/00-meta.t new file mode 100644 index 0000000..9e7b92a --- /dev/null +++ b/apache2/t/regression/action/00-meta.t @@ -0,0 +1,8 @@ +### Test meta actions + +# TODO: id +# TODO: logdata +# TODO: msg +# TODO: rev +# TODO: severity +# TODO: tag diff --git a/apache2/t/regression/action/00-misc.t b/apache2/t/regression/action/00-misc.t new file mode 100644 index 0000000..1629d69 --- /dev/null +++ b/apache2/t/regression/action/00-misc.t @@ -0,0 +1,22 @@ +### Test misc actions + +# TODO: block +# TODO: capture +# TODO: chain +# TODO: deprecatevar +# TODO: exec +# TODO: expirevar +# TODO: initcol +# TODO: multiMatch +# TODO: pause +# TODO: sanitiseArg +# TODO: sanitiseMatched +# TODO: sanitiseRequestHeader +# TODO: sanitiseResponseHeader +# TODO: setuid +# TODO: setsid +# TODO: setenv +# TODO: setvar +# TODO: skip +# TODO: skipAfter +# TODO: xmlns diff --git a/apache2/t/regression/action/00-transformations.t b/apache2/t/regression/action/00-transformations.t new file mode 100644 index 0000000..e8f7bb2 --- /dev/null +++ b/apache2/t/regression/action/00-transformations.t @@ -0,0 +1,8 @@ +### Transformation tests + +# NOTE: individual tests done in unit tests + +# TODO: t:none to override default +# TODO: t:none inline +# TODO: combined +# TODO: caching diff --git a/apache2/t/regression/action/10-append-prepend.t b/apache2/t/regression/action/10-append-prepend.t new file mode 100644 index 0000000..97f2868 --- /dev/null +++ b/apache2/t/regression/action/10-append-prepend.t @@ -0,0 +1,49 @@ +# TODO: Need more tests here + +### append +{ + type => "action", + comment => "append content", + conf => qq( + SecRuleEngine On + SecContentInjection On + SecDebugLog "$ENV{DEBUG_LOG}" + SecDebugLogLevel 9 + SecAction "phase:1,setvar:tx.test=test" + SecAction "phase:2,append:'APPEND: \%{tx.test}'" + ), + match_log => { + debug => [ "Added content to bottom: APPEND: test", 1 ], + }, + match_response => { + status => qr/^200$/, + content => qr/APPEND: test$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, + +### prepend +{ + type => "action", + comment => "prepend content", + conf => qq( + SecRuleEngine On + SecContentInjection On + SecDebugLog "$ENV{DEBUG_LOG}" + SecDebugLogLevel 9 + SecAction "phase:1,setvar:tx.test=test" + SecAction "phase:2,prepend:'PREPEND: \%{tx.test}'" + ), + match_log => { + debug => [ "Added content to top: PREPEND: test", 1 ], + }, + match_response => { + status => qr/^200$/, + content => qr/^PREPEND: test/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, diff --git a/apache2/t/regression/action/10-ctl.t b/apache2/t/regression/action/10-ctl.t new file mode 100644 index 0000000..1aa9fd1 --- /dev/null +++ b/apache2/t/regression/action/10-ctl.t @@ -0,0 +1,56 @@ +### ctl + +### ruleRemoveById +{ + type => "action", + comment => "ruleRemoveById existing rule across phases", + conf => qq( + SecRuleEngine On + SecAction "phase:2,id:666,deny" + SecAction "phase:1,pass,ctl:ruleRemoveById=666" + ), + match_log => { + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "action", + comment => "ruleRemoveById future rule across phases", + conf => qq( + SecRuleEngine On + SecAction "phase:1,pass,ctl:ruleRemoveById=666" + SecAction "phase:2,id:666,deny" + ), + match_log => { + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "action", + comment => "ruleRemoveById future rule same phase", + conf => qq( + SecRuleEngine On + SecAction "phase:1,pass,ctl:ruleRemoveById=666" + SecAction "phase:1,id:666,deny" + ), + match_log => { + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, + + diff --git a/apache2/t/regression/action/10-detectiononly-actions.t b/apache2/t/regression/action/10-detectiononly-actions.t new file mode 100644 index 0000000..238972c --- /dev/null +++ b/apache2/t/regression/action/10-detectiononly-actions.t @@ -0,0 +1,545 @@ +### Tests all of the actions in each phase in detection only mode + +# Pass +{ + type => "action", + comment => "pass in phase:1", + conf => qq( + SecRuleEngine DetectionOnly + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecDebugLog "$ENV{DEBUG_LOG}" + SecDebugLogLevel 9 + SecAction "phase:1,pass,msg:'PASSED'" + SecAction "phase:1,deny,msg:'DENIED'" + ), + match_log => { + error => [ qr/ModSecurity: Warning. Unconditional match in SecAction.*PASSED/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "action", + comment => "pass in phase:2", + conf => qq( + SecRuleEngine DetectionOnly + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecAction "phase:2,pass,msg:'PASSED'" + SecAction "phase:2,deny,msg:'DENIED'" + ), + match_log => { + error => [ qr/ModSecurity: Warning. Unconditional match in SecAction.*PASSED/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "action", + comment => "pass in phase:3", + conf => qq( + SecRuleEngine DetectionOnly + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecDebugLog "$ENV{DEBUG_LOG}" + SecDebugLogLevel 4 + SecAction "phase:3,pass,msg:'PASSED'" + SecAction "phase:3,deny,msg:'DENIED'" + ), + match_log => { + error => [ qr/ModSecurity: Warning. Unconditional match in SecAction.*PASSED/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "action", + comment => "pass in phase:4", + conf => qq( + SecRuleEngine DetectionOnly + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecDebugLog "$ENV{DEBUG_LOG}" + SecDebugLogLevel 4 + SecAction "phase:4,pass,msg:'PASSED'" + SecAction "phase:4,deny,msg:'DENIED'" + ), + match_log => { + error => [ qr/ModSecurity: Warning. Unconditional match in SecAction.*PASSED/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, + +# Allow +{ + type => "action", + comment => "allow in phase:1", + conf => qq( + SecRuleEngine DetectionOnly + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecAction "phase:1,allow,msg:'ALLOWED'" + SecAction "phase:1,deny,msg:'DENIED'" + ), + match_log => { + error => [ qr/ModSecurity: Warning. Unconditional match in SecAction.*ALLOWED/, 1 ], + -error => [ qr/Access allowed/, 1 ], +# TODO: Allow should probably stop rule execution +# -error => [ qr/DENIED/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "action", + comment => "allow in phase:2", + conf => qq( + SecRuleEngine DetectionOnly + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecAction "phase:2,allow,msg:'ALLOWED'" + SecAction "phase:2,deny,msg:'DENIED'" + ), + match_log => { + error => [ qr/ModSecurity: Warning. Unconditional match in SecAction.*ALLOWED/, 1 ], + -error => [ qr/Access allowed/, 1 ], +# TODO: Allow should probably stop rule execution +# -error => [ qr/DENIED/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "action", + comment => "allow in phase:3", + conf => qq( + SecRuleEngine DetectionOnly + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecAction "phase:3,allow,msg:'ALLOWED'" + SecAction "phase:3,deny,msg:'DENIED'" + ), + match_log => { + error => [ qr/ModSecurity: Warning. Unconditional match in SecAction.*ALLOWED/, 1 ], + -error => [ qr/Access allowed/, 1 ], +# TODO: Allow should probably stop rule execution +# -error => [ qr/DENIED/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "action", + comment => "allow in phase:4", + conf => qq( + SecRuleEngine DetectionOnly + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecAction "phase:4,allow,msg:'ALLOWED'" + SecAction "phase:4,deny,msg:'DENIED'" + ), + match_log => { + error => [ qr/ModSecurity: Warning. Unconditional match in SecAction.*ALLOWED/, 1 ], + -error => [ qr/Access allowed/, 1 ], +# TODO: Allow should probably stop rule execution +# -error => [ qr/DENIED/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, + +# Deny +{ + type => "action", + comment => "deny in phase:1", + conf => qq( + SecRuleEngine DetectionOnly + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecAction "phase:1,deny,msg:'DENIED'" + ), + match_log => { + error => [ qr/ModSecurity: Warning. Unconditional match in SecAction.*DENIED/, 1 ], + -error => [ qr/Access denied/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "action", + comment => "deny in phase:2", + conf => qq( + SecRuleEngine DetectionOnly + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecAction "phase:2,deny,msg:'DENIED'" + ), + match_log => { + error => [ qr/ModSecurity: Warning. Unconditional match in SecAction.*DENIED/, 1 ], + -error => [ qr/Access denied/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "action", + comment => "deny in phase:3", + conf => qq( + SecRuleEngine DetectionOnly + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecAction "phase:3,deny,msg:'DENIED'" + ), + match_log => { + error => [ qr/ModSecurity: Warning. Unconditional match in SecAction.*DENIED/, 1 ], + -error => [ qr/Access denied/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "action", + comment => "deny in phase:4", + conf => qq( + SecRuleEngine DetectionOnly + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecAction "phase:4,deny,msg:'DENIED'" + ), + match_log => { + error => [ qr/ModSecurity: Warning. Unconditional match in SecAction.*DENIED/, 1 ], + -error => [ qr/Access denied/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, + +# Drop +{ + type => "action", + comment => "drop in phase:1", + conf => qq( + SecRuleEngine DetectionOnly + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecAction "phase:1,drop,msg:'DROPPED'" + ), + match_log => { + error => [ qr/ModSecurity: Warning. Unconditional match in SecAction.*DROPPED/, 1 ], + -error => [ qr/Access denied/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "action", + comment => "drop in phase:2", + conf => qq( + SecRuleEngine DetectionOnly + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecAction "phase:2,drop,msg:'DROPPED'" + ), + match_log => { + error => [ qr/ModSecurity: Warning. Unconditional match in SecAction.*DROPPED/, 1 ], + -error => [ qr/Access denied/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "action", + comment => "drop in phase:3", + conf => qq( + SecRuleEngine DetectionOnly + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecAction "phase:3,drop,msg:'DROPPED'" + ), + match_log => { + error => [ qr/ModSecurity: Warning. Unconditional match in SecAction.*DROPPED/, 1 ], + -error => [ qr/Access denied/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "action", + comment => "drop in phase:4", + conf => qq( + SecRuleEngine DetectionOnly + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecAction "phase:4,drop,msg:'DROPPED'" + ), + match_log => { + error => [ qr/ModSecurity: Warning. Unconditional match in SecAction.*DROPPED/, 1 ], + -error => [ qr/Access denied/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, + +# Redirect +{ + type => "action", + comment => "redirect in phase:1 (get)", + conf => qq( + SecRuleEngine DetectionOnly + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecRule REQUEST_URI "\@streq /test2.txt" "phase:1,redirect:'http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt',msg:'REDIRECTED'" + ), + match_log => { + error => [ qr/ModSecurity: Warning. String match "\/test2.txt" at REQUEST_URI.*REDIRECTED/, 1 ], + -error => [ qr/Access denied/, 1 ], + }, + match_response => { + status => qr/^200$/, + content => qr/^TEST 2$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test2.txt", + ), +}, +{ + type => "action", + comment => "redirect in phase:2 (get)", + conf => qq( + SecRuleEngine DetectionOnly + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecRule REQUEST_URI "\@streq /test2.txt" "phase:2,redirect:'http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt',msg:'REDIRECTED'" + ), + match_log => { + error => [ qr/ModSecurity: Warning. String match "\/test2.txt" at REQUEST_URI.*REDIRECTED/, 1 ], + -error => [ qr/Access denied/, 1 ], + }, + match_response => { + status => qr/^200$/, + content => qr/^TEST 2$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test2.txt", + ), +}, +{ + type => "action", + comment => "redirect in phase:3 (get)", + conf => qq( + SecRuleEngine DetectionOnly + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecRule REQUEST_URI "\@streq /test2.txt" "phase:3,redirect:'http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt',msg:'REDIRECTED'" + ), + match_log => { + error => [ qr/ModSecurity: Warning. String match "\/test2.txt" at REQUEST_URI.*REDIRECTED/, 1 ], + -error => [ qr/Access denied/, 1 ], + }, + match_response => { + status => qr/^200$/, + content => qr/^TEST 2$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test2.txt", + ), +}, +{ + type => "action", + comment => "redirect in phase:4 (get)", + conf => qq( + SecRuleEngine DetectionOnly + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecRule REQUEST_URI "\@streq /test2.txt" "phase:4,redirect:'http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt',msg:'REDIRECTED'" + ), + match_log => { + error => [ qr/ModSecurity: Warning. String match "\/test2.txt" at REQUEST_URI.*REDIRECTED/, 1 ], + -error => [ qr/Access denied/, 1 ], + }, + match_response => { + status => qr/^200$/, + content => qr/^TEST 2$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test2.txt", + ), +}, + +# Proxy +{ + type => "action", + comment => "proxy in phase:1 (get)", + conf => qq( + SecRuleEngine DetectionOnly + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecRule REQUEST_URI "\@streq /test2.txt" "phase:1,proxy:'http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt',msg:'PROXIED'" + ), + match_log => { + error => [ qr/ModSecurity: Warning. String match "\/test2.txt" at REQUEST_URI.*PROXIED/, 1 ], + -error => [ qr/Access denied/, 1 ], + }, + match_response => { + status => qr/^200$/, + content => qr/^TEST 2$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test2.txt", + ), +}, +{ + type => "action", + comment => "proxy in phase:2 (get)", + conf => qq( + SecRuleEngine DetectionOnly + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecRule REQUEST_URI "\@streq /test2.txt" "phase:2,proxy:'http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt',msg:'PROXIED'" + ), + match_log => { + error => [ qr/ModSecurity: Warning. String match "\/test2.txt" at REQUEST_URI.*PROXIED/, 1 ], + -error => [ qr/Access denied/, 1 ], + }, + match_response => { + status => qr/^200$/, + content => qr/^TEST 2$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test2.txt", + ), +}, +{ + type => "action", + comment => "proxy in phase:3 (get)", + conf => qq( + SecRuleEngine DetectionOnly + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecDebugLog "$ENV{DEBUG_LOG}" + SecDebugLogLevel 4 + SecRule REQUEST_URI "\@streq /test2.txt" "phase:3,proxy:'http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt',msg:'PROXIED'" + ), + match_log => { + error => [ qr/ModSecurity: Warning. String match "\/test2.txt" at REQUEST_URI.*PROXIED/, 1 ], + -error => [ qr/Access denied/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test2.txt", + ), +}, +{ + type => "action", + comment => "proxy in phase:4 (get)", + conf => qq( + SecRuleEngine DetectionOnly + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecDebugLog "$ENV{DEBUG_LOG}" + SecDebugLogLevel 4 + SecRule REQUEST_URI "\@streq /test2.txt" "phase:4,proxy:'http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt',msg:'PROXIED'" + ), + match_log => { + error => [ qr/ModSecurity: Warning. String match "\/test2.txt" at REQUEST_URI.*PROXIED/, 1 ], + -error => [ qr/Access denied/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test2.txt", + ), +}, diff --git a/apache2/t/regression/action/10-logging.t b/apache2/t/regression/action/10-logging.t new file mode 100644 index 0000000..0a199ea --- /dev/null +++ b/apache2/t/regression/action/10-logging.t @@ -0,0 +1,246 @@ +### Logging tests + +# log/nolog +{ + type => "action", + comment => "log", + conf => qq( + SecRuleEngine On + SecAuditEngine RelevantOnly + SecAuditLog "$ENV{AUDIT_LOG}" + SecAction "phase:1,pass,log" + ), + match_log => { + error => [ qr/ModSecurity: Warning. Unconditional match in SecAction\./, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "action", + comment => "nolog", + conf => qq( + SecRuleEngine On + SecAuditEngine RelevantOnly + SecAuditLog "$ENV{AUDIT_LOG}" + SecAction "phase:1,pass,nolog" + ), + match_log => { + -error => [ qr/ModSecurity: /, 1 ], + -audit => [ qr/./, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, + +# auditlog/noauditlog +{ + type => "action", + comment => "auditlog", + conf => qq( + SecRuleEngine On + SecAuditEngine RelevantOnly + SecAuditLog "$ENV{AUDIT_LOG}" + SecAction "phase:1,pass,auditlog" + ), + match_log => { + error => [ qr/ModSecurity: Warning. Unconditional match in SecAction\./, 1 ], + audit => [ qr/Message: Warning. Unconditional match in SecAction\./, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "action", + comment => "noauditlog", + conf => qq( + SecRuleEngine On + SecAuditEngine RelevantOnly + SecAuditLog "$ENV{AUDIT_LOG}" + SecAction "phase:1,pass,noauditlog" + ), + match_log => { + error => [ qr/ModSecurity: Warning. Unconditional match in SecAction\./, 1 ], + -audit => [ qr/./, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, + +# All log/nolog auditlog/noauditlog combos +{ + type => "action", + comment => "log,auditlog", + conf => qq( + SecRuleEngine On + SecAuditEngine RelevantOnly + SecAuditLog "$ENV{AUDIT_LOG}" + SecAction "phase:1,pass,log,auditlog" + ), + match_log => { + error => [ qr/ModSecurity: Warning. Unconditional match in SecAction\./, 1 ], + audit => [ qr/Message: Warning. Unconditional match in SecAction\./, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "action", + comment => "log,noauditlog", + conf => qq( + SecRuleEngine On + SecAuditEngine RelevantOnly + SecAuditLog "$ENV{AUDIT_LOG}" + SecAction "phase:1,pass,log,noauditlog" + ), + match_log => { + error => [ qr/ModSecurity: Warning. Unconditional match in SecAction\./, 1 ], + -audit => [ qr/./, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "action", + comment => "nolog,auditlog", + conf => qq( + SecRuleEngine On + SecAuditEngine RelevantOnly + SecAuditLog "$ENV{AUDIT_LOG}" + SecAction "phase:1,pass,nolog,auditlog" + ), + match_log => { + audit => [ qr/-H--\s+Message: .*Stopwatch: /s, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "action", + comment => "nolog,noauditlog", + conf => qq( + SecRuleEngine On + SecAuditEngine RelevantOnly + SecAuditLog "$ENV{AUDIT_LOG}" + SecAction "phase:1,pass,nolog,noauditlog" + ), + match_log => { + -error => [ qr/ModSecurity: /, 1 ], + -audit => [ qr/./, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "action", + comment => "auditlog,log", + conf => qq( + SecRuleEngine On + SecAuditEngine RelevantOnly + SecAuditLog "$ENV{AUDIT_LOG}" + SecAction "phase:1,pass,auditlog,log" + ), + match_log => { + error => [ qr/ModSecurity: Warning. Unconditional match in SecAction\./, 1 ], + audit => [ qr/Message: Warning. Unconditional match in SecAction\./, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "action", + comment => "auditlog,nolog", + conf => qq( + SecRuleEngine On + SecAuditEngine RelevantOnly + SecAuditLog "$ENV{AUDIT_LOG}" + SecAction "phase:1,pass,auditlog,nolog" + ), + match_log => { + -error => [ qr/ModSecurity: /, 1 ], + -audit => [ qr/./, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "action", + comment => "noauditlog,log", + conf => qq( + SecRuleEngine On + SecAuditEngine RelevantOnly + SecAuditLog "$ENV{AUDIT_LOG}" + SecAction "phase:1,pass,noauditlog,log" + ), + match_log => { + error => [ qr/ModSecurity: Warning. Unconditional match in SecAction\./, 1 ], + -audit => [ qr/./, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "action", + comment => "noauditlog,nolog", + conf => qq( + SecRuleEngine On + SecAuditEngine RelevantOnly + SecAuditLog "$ENV{AUDIT_LOG}" + SecAction "phase:1,pass,noauditlog,nolog" + ), + match_log => { + -error => [ qr/ModSecurity: /, 1 ], + -audit => [ qr/./, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, + diff --git a/apache2/t/regression/config/00-load-modsec.t b/apache2/t/regression/config/00-load-modsec.t new file mode 100644 index 0000000..9c6ecc5 --- /dev/null +++ b/apache2/t/regression/config/00-load-modsec.t @@ -0,0 +1,23 @@ +{ + type => "config", + comment => "module loaded", + match_log => { + error => [ qr/ModSecurity for Apache.* configured\./, 10 ], + }, +}, +{ + type => "config", + comment => "minimal config", + conf => sub { + # Open the minimal conf file, substituting the + # relative log paths with full paths. + open(C, "<$ENV{DIST_ROOT}/modsecurity.conf-minimal") or die "$!\n"; + (my $conf = join('', )) =~ s#Log logs/#Log $ENV{TEST_SERVER_ROOT}/logs/#g; + close C; + + return $conf; + }, + match_log => { + error => [ qr/ModSecurity for Apache.* configured\./, 10 ], + }, +}, diff --git a/apache2/t/regression/config/10-audit-directives.t b/apache2/t/regression/config/10-audit-directives.t new file mode 100644 index 0000000..8a9d166 --- /dev/null +++ b/apache2/t/regression/config/10-audit-directives.t @@ -0,0 +1,264 @@ +### SecAudit* directive tests + +# SecAuditEngine +{ + type => "config", + comment => "SecAuditEngine On", + conf => qq( + SecAuditEngine On + SecAuditLog $ENV{AUDIT_LOG} + ), + match_log => { + audit => [ qr/./, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "config", + comment => "SecAuditEngine Off", + conf => qq( + SecAuditEngine Off + SecAuditLog $ENV{AUDIT_LOG} + ), + match_log => { + -audit => [ qr/./, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "config", + comment => "SecAuditEngine RelevantOnly (pos)", + conf => qq( + SecRuleEngine On + SecAuditEngine RelevantOnly + SecAuditLog $ENV{AUDIT_LOG} + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecResponseBodyAccess On + SecDefaultAction "phase:2,log,auditlog,pass" + SecRule REQUEST_URI "." "phase:4,deny" + ), + match_log => { + audit => [ qr/./, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "config", + comment => "SecAuditEngine RelevantOnly (neg)", + conf => qq( + SecAuditEngine RelevantOnly + SecAuditLog $ENV{AUDIT_LOG} + SecResponseBodyAccess On + SecDefaultAction "phase:2,log,auditlog,pass" + ), + match_log => { + -audit => [ qr/./, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, + +# SecAuditLogType & SecAuditLogStorageDir +{ + type => "config", + comment => "SecAuditLogType Serial", + conf => qq( + SecAuditEngine On + SecAuditLog $ENV{AUDIT_LOG} + SecAuditLogType Serial + ), + match_log => { + audit => [ qr/./, 1 ], + }, + match_response => { + status => qr/^404$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/bogus", + ), +}, +{ + type => "config", + comment => "SecAuditLogType Concurrent", + conf => qq( + SecAuditEngine On + SecAuditLog $ENV{AUDIT_LOG} + SecAuditLogType Concurrent + SecAuditLogStorageDir "$ENV{LOGS_DIR}/audit" + ), + test => sub { + ### Perl code to parse the audit log entry and verify + ### that the concurrent audit log exists and contains + ### the correct data. + ### + ### TODO: Need some API for this :) + ### + + # Parse log + my $alogre = qr/^(?:\S+)\ (?:\S+)\ (?:\S+)\ (?:\S+)\ \[(?:[^:]+):(?:\d+:\d+:\d+)\ (?:[^\]]+)\]\ \"(?:.*)\"\ (?:\d+)\ (?:\S+)\ \"(?:.*)\"\ \"(?:.*)\"\ (\S+)\ \"(?:.*)\"\ (\S+)\ (?:\d+)\ (?:\d+)\ (?:\S+)(?:.*)$/m; + my $alog = match_log("audit", $alogre, 1); + chomp $alog; + my @log = ($alog =~ m/$alogre/); + my($id, $fn) = ($log[0], $log[1]); + if (!$id or !$fn) { + dbg("LOG ENTRY: $alog"); + die "Failed to parse audit log: $ENV{AUDIT_LOG}\n"; + } + + # Verify concurrent log exists + my $alogdatafn = "$ENV{LOGS_DIR}/audit$fn"; + if (! -e "$alogdatafn") { + die "Audit log does not exist: $alogdatafn\n"; + } + + # Verify concurrent log contents + if (defined match_file($alogdatafn, qr/^--[^-]+-A--.*$id.*-Z--$/s)) { + return 0; + } + + # Error + dbg("LOGDATA: \"$FILE{$alogdatafn}{buf}\""); + die "Audit log data did not match.\n"; + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, + +# SecAuditLogRelevantStatus +{ + type => "config", + comment => "SecAuditLogRelevantStatus (pos)", + conf => qq( + SecAuditEngine RelevantOnly + SecAuditLog $ENV{AUDIT_LOG} + SecAuditLogRelevantStatus "^4" + ), + match_log => { + audit => [ qr/./, 1 ], + }, + match_response => { + status => qr/^404$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/bogus", + ), +}, +{ + type => "config", + comment => "SecAuditLogRelevantStatus (neg)", + conf => qq( + SecAuditEngine RelevantOnly + SecAuditLog $ENV{AUDIT_LOG} + SecAuditLogRelevantStatus "^4" + ), + match_log => { + -audit => [ qr/./, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, + +# SecAuditLogParts +{ + type => "config", + comment => "SecAuditLogParts (minimal)", + conf => qq( + SecAuditEngine On + SecAuditLog $ENV{AUDIT_LOG} + SecRequestBodyAccess On + SecResponseBodyAccess On + SecAuditLogParts "AZ" + ), + match_log => { + audit => [ qr/-A--.*-Z--/s, 1 ], + -audit => [ qr/-[B-Y]--/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "application/x-www-form-urlencoded", + ], + "a=1r&=2", + ), +}, +{ + type => "config", + comment => "SecAuditLogParts (default)", + conf => qq( + SecAuditEngine On + SecAuditLog $ENV{AUDIT_LOG} + SecRequestBodyAccess On + SecResponseBodyAccess On + ), + match_log => { + audit => [ qr/-A--.*-B--.*-F--.*-H--.*-Z--/s, 1 ], + -audit => [ qr/-[DEGIJK]--/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "application/x-www-form-urlencoded", + ], + "a=1r&=2", + ), +}, +{ + type => "config", + comment => "SecAuditLogParts (all)", + conf => qq( + SecRuleEngine On + SecAuditEngine On + SecAuditLog $ENV{AUDIT_LOG} + SecRequestBodyAccess On + SecResponseBodyAccess On + SecAuditLogParts "ABCDEFGHIJKZ" + SecAction "phase:4,log,auditlog,allow" + ), + match_log => { + audit => [ qr/-A--.*-B--.*-C--.*-F--.*-E--.*-H--.*-K--.*-Z--/s, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "application/x-www-form-urlencoded", + ], + "a=1r&=2", + ), +}, diff --git a/apache2/t/regression/config/10-debug-directives.t b/apache2/t/regression/config/10-debug-directives.t new file mode 100644 index 0000000..b537687 --- /dev/null +++ b/apache2/t/regression/config/10-debug-directives.t @@ -0,0 +1,278 @@ +### SecDebug* directive tests +{ + type => "config", + comment => "SecDebugLog (pos)", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + ), + match_log => { + debug => [ qr/./, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "config", + comment => "SecDebugLog (neg)", + conf => qq( + SecRuleEngine On + ), + match_log => { + -debug => [ qr/./, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "config", + comment => "SecDebugLogLevel 0", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 0 + SecRule REQUEST_URI "." "phase:1,deny" + ), + match_log => { + -debug => [ qr/./, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "config", + comment => "SecDebugLogLevel 1", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 1 + SecRuleScript "test.lua" "phase:1" + SecRule REQUEST_URI "(.)" "phase:4,deny,deprecatevar:bogus" + ), + match_log => { + debug => [ qr/\]\[[1]\] /, 1 ], + -debug => [ qr/\]\[[2-9]\] /, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "application/x-www-form-urlencoded", + ], + "a=1&b=2", + ), +}, +{ + type => "config", + comment => "SecDebugLogLevel 2", + conf => qq( + SecRuleEngine DetectionOnly + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 2 + SecRuleScript "test.lua" "phase:1" + SecRule REQUEST_URI "(.)" "phase:4,deny,deprecatevar:bogus" + ), + match_log => { + debug => [ qr/\]\[2\] /, 1 ], + -debug => [ qr/\]\[[3-9]\] /, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "application/x-www-form-urlencoded", + ], + "a=1&b=2", + ), +}, +{ + type => "config", + comment => "SecDebugLogLevel 3", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 3 + SecRuleScript "test.lua" "phase:1" + SecRule REQUEST_URI "(.)" "phase:4,deny,deprecatevar:bogus" + ), + match_log => { + debug => [ qr/\]\[3\] /, 1 ], + -debug => [ qr/\]\[[4-9]\] /, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "application/x-www-form-urlencoded", + ], + "a=1&b=2", + ), +}, +{ + type => "config", + comment => "SecDebugLogLevel 4", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 4 + SecRuleScript "test.lua" "phase:1" + SecRule REQUEST_URI "(.)" "phase:4,deny,deprecatevar:bogus" + ), + match_log => { + debug => [ qr/\]\[4\] /, 1 ], + -debug => [ qr/\]\[[5-9]\] /, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "application/x-www-form-urlencoded", + ], + "a=1&b=2", + ), +}, +{ + type => "config", + comment => "SecDebugLogLevel 5", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 5 + SecRuleScript "test.lua" "phase:1" + SecRule REQUEST_URI "(.)" "phase:4,deny,deprecatevar:bogus" + ), + match_log => { + debug => [ qr/\]\[5\] /, 1 ], + -debug => [ qr/\]\[[6-9]\] /, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "application/x-www-form-urlencoded", + ], + "a=1&b=2", + ), +}, +{ + type => "config", + comment => "SecDebugLogLevel 6", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 6 + SecRuleScript "test.lua" "phase:1" + SecRule REQUEST_URI "(.)" "phase:4,deny,deprecatevar:bogus" + ), + match_log => { + debug => [ qr/\]\[6\] /, 1 ], + -debug => [ qr/\]\[[7-9]\] /, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "application/x-www-form-urlencoded", + ], + "a=1&b=2", + ), +}, +{ + type => "config", + comment => "SecDebugLogLevel 7", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 7 + SecRuleScript "test.lua" "phase:1" + SecRule REQUEST_URI "(.)" "phase:4,deny,deprecatevar:bogus" + ), + match_log => { + debug => [ qr/\]\[7\] /, 1 ], + -debug => [ qr/\]\[[8-9]\] /, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "application/x-www-form-urlencoded", + ], + "a=1&b=2", + ), +}, +{ + type => "config", + comment => "SecDebugLogLevel 8", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 8 + SecRuleScript "test.lua" "phase:1" + SecRule REQUEST_URI "(.)" "phase:4,deny,deprecatevar:bogus" + ), + match_log => { + debug => [ qr/\]\[8\] /, 1 ], + -debug => [ qr/\]\[9\] /, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "application/x-www-form-urlencoded", + ], + "a=1&b=2", + ), +}, +{ + type => "config", + comment => "SecDebugLogLevel 9", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRuleScript "test.lua" "phase:1" + SecRule REQUEST_URI "(.)" "phase:4,deny,deprecatevar:bogus" + ), + match_log => { + debug => [ qr/\]\[9\] /, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "application/x-www-form-urlencoded", + ], + "a=1&b=2", + ), +}, diff --git a/apache2/t/regression/config/10-misc-directives.t b/apache2/t/regression/config/10-misc-directives.t new file mode 100644 index 0000000..7968785 --- /dev/null +++ b/apache2/t/regression/config/10-misc-directives.t @@ -0,0 +1,148 @@ +### Misc directive tests + +### TODO: +# SecTmpDir +# SecUploadKeepFiles +# SecChrootDir +# SecGuardianLog + +# SecDefaultAction +{ + type => "config", + comment => "SecDefaultAction", + conf => qq( + SecRuleEngine on + SecDefaultAction "phase:1,deny,status:500" + SecRule REQUEST_URI "test.txt" + ), + match_log => { + error => [ qr/ModSecurity: Access denied with code 500 \(phase 1\)/, 1 ], + }, + match_response => { + status => qr/^500$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, + +# SecServerSignature +{ + type => "config", + comment => "SecServerSignature On", + conf => qq( + SecServerSignature "NewServerSignature" + ), + match_log => { + error => [ qr/NewServerSignature/, 1 ], + }, + match_response => { + status => qr/^200$/, + raw => qr/^Server: +NewServerSignature$/m, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, + +# SecDataDir +{ + type => "config", + comment => "SecDataDir", + conf => qq( + SecRuleEngine On + SecDataDir "$ENV{DATA_DIR}" + SecAction initcol:ip=%{REMOTE_ADDR},setvar:ip.dummy=1,pass + ), + match_log => { + error => [ qr/ModSecurity: Warning. Unconditional match in SecAction\./, 1 ], + }, + match_file => { + "$ENV{DATA_DIR}/ip.pag" => qr/\x00\x06dummy\x00\x00\x021\x00/, + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, + +# SecTmpDir/SecUploadDir/SecUploadKeepFiles +{ + type => "config", + comment => "SecTmpDir/SecUploadDir/SecUploadKeepFiles", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 4 + SecTmpDir "$ENV{TEMP_DIR}" + SecUploadKeepFiles On + SecUploadDir "$ENV{UPLOAD_DIR}" + ), + test => sub { + # Get the filename and make sure the file exists + my $fn = match_log(debug => qr/Moved file from .* to ".*"\./, 5); + die "Failed to determine uploaded filename\n" unless (defined $fn); + + $fn =~ s/Moved file from .* to "(.*)"\..*/$1/; + die "File does not exist: $fn\n" unless (-e $fn); + + # Check the contents of the file + return 0 if (match_file($fn, qr/^TESTFILE$/m)); + + msg("Failed to match contents of uploaded file: $fn"); + return 1; + }, + match_log => { + debug => [ qr/Created temporary file: $ENV{TEMP_DIR}/, 1 ], + -debug => [ qr/Failed to /, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "multipart/form-data; boundary=---------------------------19813181771830765643996187206", + ], + q(-----------------------------19813181771830765643996187206 +Content-Disposition: form-data; name="upload-file"; filename="test" +Content-Type: application/octet-stream + +TESTFILE +-----------------------------19813181771830765643996187206 +Content-Disposition: form-data; name="file" + +Upload File +-----------------------------19813181771830765643996187206--), + ), +}, + +# SecWebAppId +{ + type => "config", + comment => "SecWebAppId", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 4 + SecAuditLog "$ENV{AUDIT_LOG}" + SecAuditEngine RelevantOnly + SecWebAppId "app-1" + SecAction "pass,log,auditlog,id:1" + ), + match_log => { + error => [ qr/Warning\. Unconditional match in SecAction\./, 1 ], + debug => [ qr/Warning\. Unconditional match in SecAction\./, 1 ], + audit => [ qr/^WebApp-Info: "app-1"/m, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, diff --git a/apache2/t/regression/config/10-request-directives.t b/apache2/t/regression/config/10-request-directives.t new file mode 100644 index 0000000..16094ca --- /dev/null +++ b/apache2/t/regression/config/10-request-directives.t @@ -0,0 +1,548 @@ +### Tests for directives altering how a request is handled + +# SecArgumentSeparator +{ + type => "config", + comment => "SecArgumentSeparator (get-pos)", + conf => q( + SecRuleEngine On + SecArgumentSeparator ";" + SecRule ARGS:a "@streq 1" "phase:1,deny,chain" + SecRule ARGS:b "@streq 2" + ), + match_log => { + error => [ qr/Access denied with code 403 \(phase 1\)\. String match "2" at ARGS:b\./, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt?a=1;b=2", + ), +}, +{ + type => "config", + comment => "SecArgumentSeparator (get-neg)", + conf => q( + SecRuleEngine On + SecRule ARGS:a "@streq 1" "phase:1,deny,chain" + SecRule ARGS:b "@streq 2" + ), + match_log => { + -error => [ qr/Access denied/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt?a=1;b=2", + ), +}, +{ + type => "config", + comment => "SecArgumentSeparator (post-pos)", + conf => q( + SecRuleEngine On + SecRequestBodyAccess On + SecArgumentSeparator ";" + SecRule ARGS:a "@streq 1" "phase:2,deny,chain" + SecRule ARGS:b "@streq 2" + ), + match_log => { + error => [ qr/Access denied with code 403 \(phase 2\)\. String match "2" at ARGS:b\./, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "application/x-www-form-urlencoded", + ], + "a=1;b=2", + ), +}, +{ + type => "config", + comment => "SecArgumentSeparator (post-neg)", + conf => q( + SecRuleEngine On + SecRequestBodyAccess On + SecRule ARGS:a "@streq 1" "phase:2,deny" + SecRule ARGS:b "@streq 2" "phase:2,deny" + ), + match_log => { + -error => [ qr/Access denied/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "application/x-www-form-urlencoded", + ], + "a=1;b=2", + ), +}, + +# SecRequestBodyAccess +{ + type => "config", + comment => "SecRequestBodyAccess (pos)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecRule ARGS:a "\@streq 1" "phase:2,deny,chain" + SecRule ARGS:b "\@streq 2" + ), + match_log => { + error => [ qr/Access denied with code 403 \(phase 2\)\. String match "2" at ARGS:b\./, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "application/x-www-form-urlencoded", + ], + "a=1&b=2", + ), +}, +{ + type => "config", + comment => "SecRequestBodyAccess (neg)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess Off + SecRule ARGS:a "\@streq 1" "phase:2,deny" + SecRule ARGS:b "\@streq 2" "phase:2,deny" + ), + match_log => { + -error => [ qr/Access denied/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "application/x-www-form-urlencoded", + ], + "a=1&b=2", + ), +}, + +# SecRequestBodyLimit +{ + type => "config", + comment => "SecRequestBodyLimit (equal)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecRequestBodyLimit 7 + ), + match_log => { + -error => [ qr/Request body is larger than the configured limit/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "application/x-www-form-urlencoded", + ], + "a=1&b=2", + ), +}, +{ + type => "config", + comment => "SecRequestBodyLimit (greater)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecRequestBodyLimit 5 + ), + match_log => { + error => [ qr/Request body .*is larger than the configured limit \(5\)\./, 1 ], + }, + match_response => { + status => qr/^413$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "application/x-www-form-urlencoded", + ], + "a=1&b=2", + ), +}, +{ + type => "config", + comment => "SecRequestBodyLimit (equal - chunked)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecRequestBodyLimit 276 + ), + match_log => { + -error => [ qr/Request body is larger than the configured limit/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => normalize_raw_request_data( + qq( + POST /test.txt HTTP/1.1 + Host: $ENV{SERVER_NAME}:$ENV{SERVER_PORT} + User-Agent: $ENV{USER_AGENT} + Content-Type: multipart/form-data; boundary=---------------------------69343412719991675451336310646 + Transfer-Encoding: chunked + + ), + ) + .encode_chunked( + normalize_raw_request_data( + q( + -----------------------------69343412719991675451336310646 + Content-Disposition: form-data; name="a" + + 1 + -----------------------------69343412719991675451336310646 + Content-Disposition: form-data; name="b" + + 2 + -----------------------------69343412719991675451336310646-- + ) + ), + 1024 + ), +}, +{ + type => "config", + comment => "SecRequestBodyLimit (greater - chunked)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecRequestBodyLimit 256 + ), + match_log => { + error => [ qr/Request body .*is larger than the configured limit \(256\)\./, 1 ], + }, + match_response => { + status => qr/^413$/, + }, + request => normalize_raw_request_data( + qq( + POST /test.txt HTTP/1.1 + Host: $ENV{SERVER_NAME}:$ENV{SERVER_PORT} + User-Agent: $ENV{USER_AGENT} + Content-Type: multipart/form-data; boundary=---------------------------69343412719991675451336310646 + Transfer-Encoding: chunked + + ), + ) + .encode_chunked( + normalize_raw_request_data( + q( + -----------------------------69343412719991675451336310646 + Content-Disposition: form-data; name="a" + + 1 + -----------------------------69343412719991675451336310646 + Content-Disposition: form-data; name="b" + + 2 + -----------------------------69343412719991675451336310646-- + ) + ), + 1024 + ), +}, +{ + type => "config", + comment => "SecRequestBodyLimit (ctl:ruleEngine=off)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecRequestBodyLimit 5 + + SecAction "phase:1,pass,nolog,ctl:ruleEngine=off" + SecRule REQUEST_BODY "." "phase:2,deny" + ), + match_log => { + -error => [ qr/Request body .*is larger than the configured limit/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "application/x-www-form-urlencoded", + ], + "a=1&b=2", + ), +}, +{ + type => "config", + comment => "SecRequestBodyLimit (ctl:requestBodyAccess=off)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecRequestBodyLimit 5 + + SecAction "phase:1,pass,nolog,ctl:requestBodyAccess=off" + SecRule REQUEST_BODY "." "phase:2,deny" + ), + match_log => { + -error => [ qr/Request body .*is larger than the configured limit/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "application/x-www-form-urlencoded", + ], + "a=1&b=2", + ), +}, +{ + type => "config", + comment => "SecRequestBodyLimit (ctl:ruleEngine=off - chunked)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecRequestBodyLimit 256 + + SecAction "phase:1,pass,nolog,ctl:ruleEngine=off" + SecRule REQUEST_BODY "." "phase:2,deny" + ), + match_log => { + -error => [ qr/Request body .*is larger than the configured limit/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => normalize_raw_request_data( + qq( + POST /test.txt HTTP/1.1 + Host: $ENV{SERVER_NAME}:$ENV{SERVER_PORT} + User-Agent: $ENV{USER_AGENT} + Content-Type: multipart/form-data; boundary=---------------------------69343412719991675451336310646 + Transfer-Encoding: chunked + + ), + ) + .encode_chunked( + normalize_raw_request_data( + q( + -----------------------------69343412719991675451336310646 + Content-Disposition: form-data; name="a" + + 1 + -----------------------------69343412719991675451336310646 + Content-Disposition: form-data; name="b" + + 2 + -----------------------------69343412719991675451336310646-- + ) + ), + 1024 + ), +}, +{ + type => "config", + comment => "SecRequestBodyLimit (ctl:requestBodyAccess=off - chunked)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecRequestBodyLimit 256 + + SecAction "phase:1,pass,nolog,ctl:requestBodyAccess=off" + SecRule REQUEST_BODY "." "phase:2,deny" + ), + match_log => { + -error => [ qr/Request body .*is larger than the configured limit \(256\)\./, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => normalize_raw_request_data( + qq( + POST /test.txt HTTP/1.1 + Host: $ENV{SERVER_NAME}:$ENV{SERVER_PORT} + User-Agent: $ENV{USER_AGENT} + Content-Type: multipart/form-data; boundary=---------------------------69343412719991675451336310646 + Transfer-Encoding: chunked + + ), + ) + .encode_chunked( + normalize_raw_request_data( + q( + -----------------------------69343412719991675451336310646 + Content-Disposition: form-data; name="a" + + 1 + -----------------------------69343412719991675451336310646 + Content-Disposition: form-data; name="b" + + 2 + -----------------------------69343412719991675451336310646-- + ) + ), + 1024 + ), +}, + +# SecRequestBodyInMemoryLimit +{ + type => "config", + comment => "SecRequestBodyInMemoryLimit (equal)", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRequestBodyAccess On + SecRequestBodyLimit 1000 + SecRequestBodyInMemoryLimit 276 + ), + match_log => { + -debug => [ qr/Input filter: Request too large to store in memory, switching to disk\./, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => normalize_raw_request_data( + qq( + POST /test.txt HTTP/1.1 + Host: $ENV{SERVER_NAME}:$ENV{SERVER_PORT} + User-Agent: $ENV{USER_AGENT} + Content-Type: multipart/form-data; boundary=---------------------------69343412719991675451336310646 + Transfer-Encoding: chunked + + ), + ) + .encode_chunked( + normalize_raw_request_data( + q( + -----------------------------69343412719991675451336310646 + Content-Disposition: form-data; name="a" + + 1 + -----------------------------69343412719991675451336310646 + Content-Disposition: form-data; name="b" + + 2 + -----------------------------69343412719991675451336310646-- + ) + ), + 1024 + ), +}, +{ + type => "config", + comment => "SecRequestBodyInMemoryLimit (greater)", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRequestBodyAccess On + SecRequestBodyLimit 1000 + SecRequestBodyInMemoryLimit 16 + ), + match_log => { + debug => [ qr/Input filter: Request too large to store in memory, switching to disk\./, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => normalize_raw_request_data( + qq( + POST /test.txt HTTP/1.1 + Host: $ENV{SERVER_NAME}:$ENV{SERVER_PORT} + User-Agent: $ENV{USER_AGENT} + Content-Type: multipart/form-data; boundary=---------------------------69343412719991675451336310646 + Transfer-Encoding: chunked + + ), + ) + .encode_chunked( + normalize_raw_request_data( + q( + -----------------------------69343412719991675451336310646 + Content-Disposition: form-data; name="a" + + 1 + -----------------------------69343412719991675451336310646 + Content-Disposition: form-data; name="b" + + 2 + -----------------------------69343412719991675451336310646-- + ) + ), + 1024 + ), +}, + +# SecCookieFormat +{ + type => "config", + comment => "SecCookieFormat (pos)", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 5 + SecCookieFormat 1 + SecRule REQUEST_COOKIES_NAMES "\@streq SESSIONID" "phase:1,deny,chain" + SecRule REQUEST_COOKIES:\$SESSIONID_PATH "\@streq /" "chain" + SecRule REQUEST_COOKIES:SESSIONID "\@streq cookieval" + ), + match_log => { + error => [ qr/Access denied with code 403 \(phase 1\)\. String match "cookieval" at REQUEST_COOKIES:SESSIONID\./, 1 ], + debug => [ qr(Adding request cookie: name "\$SESSIONID_PATH", value "/"), 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Cookie" => q($Version="1"; SESSIONID="cookieval"; $PATH="/"), + ], + undef, + ), +}, +{ + type => "config", + comment => "SecCookieFormat (neg)", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 5 + SecCookieFormat 0 + SecRule REQUEST_COOKIES_NAMES "\@streq SESSIONID" "phase:1,deny,chain" + SecRule REQUEST_COOKIES:\$SESSIONID_PATH "\@streq /" "chain" + SecRule REQUEST_COOKIES:SESSIONID "\@streq cookieval" + ), + match_log => { + -error => [ qr/Access denied/, 1 ], + -debug => [ qr(Adding request cookie: name "\$SESSIONID_PATH", value "/"), 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Cookie" => q($Version="1"; SESSIONID="cookieval"; $PATH="/"), + ], + undef, + ), +}, + diff --git a/apache2/t/regression/config/10-response-directives.t b/apache2/t/regression/config/10-response-directives.t new file mode 100644 index 0000000..60617a2 --- /dev/null +++ b/apache2/t/regression/config/10-response-directives.t @@ -0,0 +1,174 @@ +### Tests for directives altering how a response is handled + +# SecResponseBodyMimeTypesClear +{ + type => "config", + comment => "SecResponseBodyMimeTypesClear", + conf => qq( + SecRuleEngine On + SecResponseBodyAccess On + SecResponseBodyMimeTypesClear + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRule RESPONSE_BODY "TEST" "phase:4,deny" + ), + match_log => { + -error => [ qr/Access denied/, 1 ], + debug => [ qr/Not buffering response body for unconfigured MIME type/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, + +# SecResponseBodyAccess & SecResponseBodyMimeType +{ + type => "config", + comment => "SecResponseBodyAccess On", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecResponseBodyAccess On + SecResponseBodyMimeType text/plain null + SecRule RESPONSE_BODY "TEST" "phase:4,deny" + ), + match_log => { + error => [ qr/Access denied with code 403 \(phase 4\)\. Pattern match "TEST" at RESPONSE_BODY\./, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "config", + comment => "SecResponseBodyAccess Off", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecResponseBodyAccess Off + SecResponseBodyMimeType text/plain null + SecRule RESPONSE_BODY "TEST" "phase:4,deny" + ), + match_log => { + -error => [ qr/Access denied/, 1 ], + debug => [ qr/Response body buffering is not enabled\./, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, + +# SecResponseBodyLimit +{ + type => "config", + comment => "SecResponseBodyLimit (equal)", + conf => qq( + SecRuleEngine On + SecResponseBodyAccess On + SecResponseBodyMimeType text/plain null + SecResponseBodyLimit 8192 + ), + match_log => { + -error => [ qr/Content-Length \(\d+\) over the limit/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/8k.txt", + ), +}, +{ + type => "config", + comment => "SecResponseBodyLimit (less)", + conf => qq( + SecRuleEngine On + SecResponseBodyAccess On + SecResponseBodyMimeType text/plain null + SecResponseBodyLimit 9000 + ), + match_log => { + -error => [ qr/Content-Length \(\d+\) over the limit/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/8k.txt", + ), +}, +{ + type => "config", + comment => "SecResponseBodyLimit (greater)", + conf => qq( + SecRuleEngine On + SecResponseBodyAccess On + SecResponseBodyMimeType text/plain null + SecResponseBodyLimit 8000 + ), + match_log => { + error => [ qr/Content-Length \(\d+\) over the limit \(8000\)\./, 1 ], + }, + match_response => { + status => qr/^500$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/8k.txt", + ), +}, + +# ResponseBodyLimitAction +{ + type => "config", + comment => "SecResponseBodyLimitAction Reject", + conf => qq( + SecRuleEngine On + SecResponseBodyAccess On + SecResponseBodyMimeType text/plain null + SecResponseBodyLimit 5 + SecResponseBodyLimitAction Reject + ), + match_log => { + error => [ qr/Content-Length \(\d+\) over the limit \(5\)\./, 1 ], + }, + match_response => { + status => qr/^500$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/8k.txt", + ), +}, +{ + type => "config", + comment => "SecResponseBodyLimitAction ProcessPartial", + conf => qq( + SecRuleEngine On + SecResponseBodyAccess On + SecResponseBodyMimeType text/plain null + SecResponseBodyLimit 5 + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 4 + SecResponseBodyLimitAction ProcessPartial + ), + match_log => { + -error => [ qr/Content-Length \(\d+\) over the limit/, 1 ], + debug => [ qr/Processing partial response body \(limit 5\)/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/8k.txt", + ), +}, diff --git a/apache2/t/regression/config/20-chroot.t b/apache2/t/regression/config/20-chroot.t new file mode 100644 index 0000000..2147d2b --- /dev/null +++ b/apache2/t/regression/config/20-chroot.t @@ -0,0 +1,35 @@ +### SecChroot tests +# TODO: Will not work as we need root access + +#{ +# type => "config", +# comment => "SecChroot", +# httpd_opts => qw( +# -DCHROOT +# ), +# conf => qq( +# # These will be in the chroot +# PidFile /logs/httpd.pid +# ScoreBoardFile /logs/httpd.scoreboard +# User nobody +# Group nogroup +# +# SecAuditEngine On +# SecDebugLog $ENV{DEBUG_LOG} +# SecDebugLogLevel 9 +# SecAuditLog $ENV{AUDIT_LOG} +# SecAuditLogStorageDir "/logs/audit" +# SecAuditLogType Concurrent +# SecChrootDir "$ENV{TEST_SERVER_ROOT}" +# ), +# match_log => { +# debug => [ qr/./, 1 ], +# audit => [ qr/./, 1 ], +# }, +# match_response => { +# status => qr/^200$/, +# }, +# request => new HTTP::Request( +# GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", +# ), +#}, diff --git a/apache2/t/regression/misc/00-multipart-parser.t b/apache2/t/regression/misc/00-multipart-parser.t new file mode 100644 index 0000000..5d156e1 --- /dev/null +++ b/apache2/t/regression/misc/00-multipart-parser.t @@ -0,0 +1,485 @@ +### Multipart parser tests + +# Final CRLF or not, we should still work +{ + type => "misc", + comment => "multipart parser (final CRLF)", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRequestBodyAccess On + SecRule MULTIPART_STRICT_ERROR "\@eq 1" "phase:2,deny" + SecRule MULTIPART_UNMATCHED_BOUNDARY "\@eq 1" "phase:2,deny" + SecRule REQBODY_PROCESSOR_ERROR "\@eq 1" "phase:2,deny" + ), + match_log => { + debug => [ qr/Adding request argument \(BODY\): name "a", value "1".*Adding request argument \(BODY\): name "b", value "2"/s, 1 ], + -debug => [ qr/Multipart error:/, 1 ], + + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "multipart/form-data; boundary=---------------------------69343412719991675451336310646", + ], + normalize_raw_request_data( + q( + -----------------------------69343412719991675451336310646 + Content-Disposition: form-data; name="a" + + 1 + -----------------------------69343412719991675451336310646 + Content-Disposition: form-data; name="b" + + 2 + -----------------------------69343412719991675451336310646-- + ), + ), + ), +}, +{ + type => "misc", + comment => "multipart parser (no final CRLF)", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRequestBodyAccess On + SecRule MULTIPART_STRICT_ERROR "\@eq 1" "phase:2,deny" + SecRule MULTIPART_UNMATCHED_BOUNDARY "\@eq 1" "phase:2,deny" + SecRule REQBODY_PROCESSOR_ERROR "\@eq 1" "phase:2,deny" + ), + match_log => { + debug => [ qr/Adding request argument \(BODY\): name "a", value "1".*Adding request argument \(BODY\): name "b", value "2"/s, 1 ], + -debug => [ qr/Multipart error:/, 1 ], + + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "multipart/form-data; boundary=---------------------------69343412719991675451336310646", + ], + normalize_raw_request_data( + q( + -----------------------------69343412719991675451336310646 + Content-Disposition: form-data; name="a" + + 1 + -----------------------------69343412719991675451336310646 + Content-Disposition: form-data; name="b" + + 2 + -----------------------------69343412719991675451336310646--), + ), + ), +}, + +# Should work with a boundary of "boundary" +{ + type => "misc", + comment => "multipart parser (boundary contains \"boundary\")", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRequestBodyAccess On + SecRule MULTIPART_STRICT_ERROR "\@eq 1" "phase:2,deny" + SecRule MULTIPART_UNMATCHED_BOUNDARY "\@eq 1" "phase:2,deny" + SecRule REQBODY_PROCESSOR_ERROR "\@eq 1" "phase:2,deny" + ), + match_log => { + debug => [ qr/Adding request argument \(BODY\): name "a", value "1".*Adding request argument \(BODY\): name "b", value "2"/s, 1 ], + -debug => [ qr/Multipart error:/, 1 ], + + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "multipart/form-data; boundary=------------------------------------------------boundary", + ], + normalize_raw_request_data( + q( + --------------------------------------------------boundary + Content-Disposition: form-data; name="a" + + 1 + --------------------------------------------------boundary + Content-Disposition: form-data; name="b" + + 2 + --------------------------------------------------boundary-- + ), + ), + ), +}, +{ + type => "misc", + comment => "multipart parser (boundary contains \"bOuNdArY\")", + note => q( + KHTML Boundary + ), + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRequestBodyAccess On + SecRule MULTIPART_STRICT_ERROR "\@eq 1" "phase:2,deny" + SecRule MULTIPART_UNMATCHED_BOUNDARY "\@eq 1" "phase:2,deny" + SecRule REQBODY_PROCESSOR_ERROR "\@eq 1" "phase:2,deny" + ), + match_log => { + debug => [ qr/Adding request argument \(BODY\): name "a", value "1".*Adding request argument \(BODY\): name "b", value "2"/s, 1 ], + -debug => [ qr/Multipart error:/, 1 ], + + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "multipart/form-data; boundary=--------0xKhTmLbOuNdArY", + ], + normalize_raw_request_data( + q( + ----------0xKhTmLbOuNdArY + Content-Disposition: form-data; name="a" + + 1 + ----------0xKhTmLbOuNdArY + Content-Disposition: form-data; name="b" + + 2 + ----------0xKhTmLbOuNdArY-- + ), + ), + ), +}, + +# We should handle data starting with a "--" +{ + type => "misc", + comment => "multipart parser (data contains \"--\")", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRequestBodyAccess On + SecRule MULTIPART_STRICT_ERROR "\@eq 1" "phase:2,deny" + SecRule REQBODY_PROCESSOR_ERROR "\@eq 1" "phase:2,deny" + ), + match_log => { + debug => [ qr/Adding request argument \(BODY\): name "a", value "--test".*Adding request argument \(BODY\): name "b", value "--"/s, 1 ], + -debug => [ qr/Multipart error:/, 1 ], + + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "multipart/form-data; boundary=---------------------------69343412719991675451336310646", + ], + normalize_raw_request_data( + q( + -----------------------------69343412719991675451336310646 + Content-Disposition: form-data; name="a" + + --test + -----------------------------69343412719991675451336310646 + Content-Disposition: form-data; name="b" + + -- + -----------------------------69343412719991675451336310646--), + ), + ), +}, + +# We should emit warnings for parsing errors +{ + type => "misc", + comment => "multipart parser error (no final boundary)", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRequestBodyAccess On + SecAuditLog "$ENV{AUDIT_LOG}" + SecAuditEngine RelevantOnly + ), + match_log => { + audit => [ qr/Final boundary missing/, 1 ], + debug => [ qr/Final boundary missing/, 1 ], + + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "multipart/form-data; boundary=---------------------------69343412719991675451336310646", + ], + normalize_raw_request_data( + q( + -----------------------------69343412719991675451336310646 + Content-Disposition: form-data; name="a" + + 1 + -----------------------------69343412719991675451336310646 + Content-Disposition: form-data; name="b" + + 2 + ), + ), + ), +}, +{ + type => "misc", + comment => "multipart parser error (no disposition)", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRequestBodyAccess On + SecAuditLog "$ENV{AUDIT_LOG}" + SecAuditEngine RelevantOnly + ), + match_log => { + -debug => [ qr/Multipart error:/, 1 ], + audit => [ qr/Part missing Content-Disposition header/, 1 ], + debug => [ qr/Part missing Content-Disposition header/, 1 ], + + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "multipart/form-data; boundary=---------------------------69343412719991675451336310646", + ], + normalize_raw_request_data( + q( + -----------------------------69343412719991675451336310646 + + 1 + -----------------------------69343412719991675451336310646 + + 2 + -----------------------------69343412719991675451336310646-- + ), + ), + ), +}, +{ + type => "misc", + comment => "multipart parser error (bad disposition)", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRequestBodyAccess On + SecAuditLog "$ENV{AUDIT_LOG}" + SecAuditEngine RelevantOnly + ), + match_log => { + audit => [ qr/Invalid Content-Disposition header/, 1 ], + debug => [ qr/Invalid Content-Disposition header/, 1 ], + + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "multipart/form-data; boundary=---------------------------69343412719991675451336310646", + ], + normalize_raw_request_data( + q( + -----------------------------69343412719991675451336310646 + Content-Disposition: form-data name="a" + + 1 + -----------------------------69343412719991675451336310646 + Content-Disposition: form-data name="b" + + 2 + -----------------------------69343412719991675451336310646-- + ), + ), + ), +}, +{ + type => "misc", + comment => "multipart parser error (no disposition name)", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRequestBodyAccess On + SecAuditLog "$ENV{AUDIT_LOG}" + SecAuditEngine RelevantOnly + ), + match_log => { + -debug => [ qr/Multipart error:/, 1 ], + audit => [ qr/Content-Disposition header missing name field/, 1 ], + debug => [ qr/Content-Disposition header missing name field/, 1 ], + + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "multipart/form-data; boundary=---------------------------69343412719991675451336310646", + ], + normalize_raw_request_data( + q( + -----------------------------69343412719991675451336310646 + Content-Disposition: form-data; + + 1 + -----------------------------69343412719991675451336310646 + Content-Disposition: form-data; + + 2 + -----------------------------69343412719991675451336310646-- + ), + ), + ), +}, +# Zero length part name should not crash +{ + type => "misc", + comment => "multipart parser (zero length part name)", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRequestBodyAccess On + #SecRule MULTIPART_STRICT_ERROR "\@eq 1" "phase:2,deny,status:403" + SecRule MULTIPART_UNMATCHED_BOUNDARY "\@eq 1" "phase:2,deny,status:403" + SecRule REQBODY_PROCESSOR_ERROR "\@eq 1" "phase:2,deny,status:403" + ), + match_log => { + debug => [ qr/name: a.*variable: 1.*Invalid part header \(header name missing\)/s, 1 ], + -debug => [ qr/Adding request argument \(BODY\): name "b"/s, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "multipart/form-data; boundary=---------------------------69343412719991675451336310646", + ], + normalize_raw_request_data( + q( + -----------------------------69343412719991675451336310646 + Content-Disposition: form-data; name="a" + + 1 + -----------------------------69343412719991675451336310646 + : + -----------------------------69343412719991675451336310646 + Content-Disposition: form-data; name="b" + + 2 + -----------------------------69343412719991675451336310646-- + ), + ), + ), +}, +# Data following final boundary should set flag +{ + type => "misc", + comment => "multipart parser (data after final boundary)", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRequestBodyAccess On + SecRule MULTIPART_DATA_AFTER "\@eq 1" "phase:2,deny,status:403" + ), + match_log => { + debug => [ qr/name: a.*variable: 1.*Ignoring data after last boundary/s, 1 ], + -debug => [ qr/Adding request argument \(BODY\): name "b"/s, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "multipart/form-data; boundary=---------------------------69343412719991675451336310646", + ], + normalize_raw_request_data( + q( + -----------------------------69343412719991675451336310646 + Content-Disposition: form-data; name="a" + + 1 + -----------------------------69343412719991675451336310646-- + -----------------------------69343412719991675451336310646 + Content-Disposition: form-data; name="b" + + 2 + -----------------------------69343412719991675451336310646-- + ), + ), + ), +}, +# Single quoted data is invalid +{ + type => "misc", + comment => "multipart parser (C-D uses single quotes)", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRequestBodyAccess On + #SecRule MULTIPART_STRICT_ERROR "\@eq 1" "phase:2,deny,status:403" + SecRule MULTIPART_INVALID_QUOTING "\@eq 1" "chain,phase:2,deny,status:403" + SecRule REQBODY_PROCESSOR_ERROR "\@eq 1" + ), + match_log => { + debug => [ qr/name: a.*variable: 1.*Duplicate Content-Disposition name/s, 1 ], + -debug => [ qr/Adding request argument \(BODY\): name "b/s, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "multipart/form-data; boundary=---------------------------69343412719991675451336310646", + ], + normalize_raw_request_data( + q( + -----------------------------69343412719991675451336310646 + Content-Disposition: form-data; name="a" + + 1 + -----------------------------69343412719991675451336310646 + Content-Disposition: form-data; name=';filename="dummy';name=b;" + + 2 + -----------------------------69343412719991675451336310646-- + ), + ), + ), +}, diff --git a/apache2/t/regression/misc/00-phases.t b/apache2/t/regression/misc/00-phases.t new file mode 100644 index 0000000..97a40a5 --- /dev/null +++ b/apache2/t/regression/misc/00-phases.t @@ -0,0 +1,151 @@ +### Test the phases + +# Phase 1 (request headers) +{ + type => "misc", + comment => "phase 1", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType text/plain null + SecRule REQUEST_LINE "^POST" "phase:1,pass,log,auditlog" + SecRule ARGS "val1" "phase:1,pass,log,auditlog" + SecRule RESPONSE_HEADERS:Last-Modified "." "phase:1,pass,log,auditlog" + SecRule RESPONSE_BODY "TEST" "phase:1,pass,log,auditlog" + ), + match_log => { + error => [ qr/Pattern match "\^POST" at REQUEST_LINE/, 1 ], + -error => [ qr/Pattern match .* (ARGS|RESPONSE)/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "application/x-www-form-urlencoded", + ], + "arg1=val1&arg2=val2", + ), +}, + +# Phase 2 (request body) +{ + type => "misc", + comment => "phase 2", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType text/plain null + SecRule REQUEST_LINE "^POST" "phase:2,pass,log,auditlog" + SecRule ARGS "val1" "phase:2,pass,log,auditlog" + SecRule RESPONSE_HEADERS:Last-Modified "." "phase:2,pass,log,auditlog" + SecRule RESPONSE_BODY "TEST" "phase:2,pass,log,auditlog" + ), + match_log => { + error => [ qr/Pattern match "\^POST" at REQUEST_LINE.*Pattern match "val1" at ARGS/s, 1 ], + -error => [ qr/Pattern match .* RESPONSE/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "application/x-www-form-urlencoded", + ], + "arg1=val1&arg2=val2", + ), +}, + +# Phase 3 (response headers) +{ + type => "misc", + comment => "phase 3", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType text/plain null + SecRule REQUEST_LINE "^POST" "phase:3,pass,log,auditlog" + SecRule ARGS "val1" "phase:3,pass,log,auditlog" + SecRule RESPONSE_HEADERS:Last-Modified "." "phase:3,pass,log,auditlog" + SecRule RESPONSE_BODY "TEST" "phase:3,pass,log,auditlog" + ), + match_log => { + error => [ qr/Pattern match "\^POST" at REQUEST_LINE.*Pattern match "val1" at ARGS.*Pattern match "\." at RESPONSE_HEADERS/s, 1 ], + -error => [ qr/Pattern match .* RESPONSE_BODY/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "application/x-www-form-urlencoded", + ], + "arg1=val1&arg2=val2", + ), +}, + +# Phase 4 (response body) +{ + type => "misc", + comment => "phase 4", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType text/plain null + SecDebugLog "$ENV{DEBUG_LOG}" + SecDebugLogLevel 9 + SecRule REQUEST_LINE "^POST" "phase:4,pass,log,auditlog" + SecRule ARGS "val1" "phase:4,pass,log,auditlog" + SecRule RESPONSE_HEADERS:Last-Modified "." "phase:4,pass,log,auditlog" + SecRule RESPONSE_BODY "TEST" "phase:4,pass,log,auditlog" + ), + match_log => { + error => [ qr/Pattern match "\^POST" at REQUEST_LINE.*Pattern match "val1" at ARGS.*Pattern match "\." at RESPONSE_HEADERS.*Pattern match "TEST" at RESPONSE_BODY/s, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "application/x-www-form-urlencoded", + ], + "arg1=val1&arg2=val2", + ), +}, + +# Phase 5 (logging) +{ + type => "misc", + comment => "phase 5", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType text/plain null + SecRule REQUEST_LINE "^POST" "phase:5,pass,log,auditlog" + SecRule ARGS "val1" "phase:5,pass,log,auditlog" + SecRule RESPONSE_HEADERS:Last-Modified "." "phase:5,pass,log,auditlog" + SecRule RESPONSE_BODY "TEST" "phase:5,pass,log,auditlog" + ), + match_log => { + error => [ qr/Pattern match "\^POST" at REQUEST_LINE.*Pattern match "val1" at ARGS.*Pattern match "\." at RESPONSE_HEADERS.*Pattern match "TEST" at RESPONSE_BODY/s, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "application/x-www-form-urlencoded", + ], + "arg1=val1&arg2=val2", + ), +}, diff --git a/apache2/t/regression/misc/10-tfn-cache.t b/apache2/t/regression/misc/10-tfn-cache.t new file mode 100644 index 0000000..271834d --- /dev/null +++ b/apache2/t/regression/misc/10-tfn-cache.t @@ -0,0 +1,189 @@ +### Transformation Caching + +{ + type => "misc", + comment => "tfncache (simple fully cached)", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + + # We need to make this work no matter what the defaults may change to + SecCacheTransformations On "minlen:1,maxlen:0" + + # This should cache it + SecRule ARGS_GET "WillNotMatch" "phase:1,t:none,t:removeWhiteSpace,t:lowercase,pass,nolog" + + # This should use the cached value + SecRule ARGS_GET:test "foobar" "phase:1,t:none,t:removeWhiteSpace,t:lowercase,deny" + ), + match_log => { + debug => [ qr/removeWhiteSpace,lowercase: "foobar" .*cached/, 1 ], + -debug => [ qr/partially cached/, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/index.html?test=Foo+Bar", + ), +}, +{ + type => "misc", + comment => "tfncache (simple partially cached)", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + + # We need to make this work no matter what the defaults may change to + SecCacheTransformations On "minlen:1,maxlen:0,incremental:off,maxitems:0" + + # This should cache it + SecRule ARGS_GET "WillNotMatch" "phase:1,t:none,t:removeWhiteSpace,pass,nolog" + + # This should use the partially cached value + SecRule ARGS_GET:test "foobar" "phase:1,t:none,t:removeWhiteSpace,t:lowercase,deny" + ), + match_log => { + debug => [ qr/removeWhiteSpace: "FooBar" .*partially cached/, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/index.html?test=Foo+Bar", + ), +}, +{ + type => "misc", + comment => "tfncache (separate phases)", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + + # We need to make this work no matter what the defaults may change to + SecCacheTransformations On "minlen:1,maxlen:0" + + # This should cache it + SecRule ARGS_GET "WillNotMatch" "phase:1,t:none,t:removeWhiteSpace,t:lowercase,pass,nolog" + + # This should use the cached value + SecRule ARGS_GET:test "foobar" "phase:2,t:none,t:removeWhiteSpace,t:lowercase,deny" + ), + match_log => { + -debug => [ qr/removeWhiteSpace,lowercase: "foobar" .*cached/, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/index.html?test=Foo+Bar", + ), +}, +{ + type => "misc", + comment => "tfncache (non-modifying tfns cached)", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + + # We need to make this work no matter what the defaults may change to + SecCacheTransformations On "minlen:1,maxlen:0" + + # This should cache it + SecRule ARGS_GET "WillNotMatch" "phase:1,t:none,t:removeWhiteSpace,t:lowercase,pass,nolog" + + # This should use the cached value + SecRule ARGS_GET:test "foobar" "phase:1,t:none,t:removeWhiteSpace,t:lowercase,deny" + ), + match_log => { + debug => [ qr/removeWhiteSpace,lowercase: "foobar" .*cached/, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/index.html?test=foo+bar", + ), +}, +{ + type => "misc", + comment => "tfncache (unique keys)", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRequestBodyAccess On + + # We need to make this work no matter what the defaults may change to + SecCacheTransformations On "minlen:1,maxlen:0" + + # This should cache it + SecRule ARGS "WillNotMatch" "phase:2,t:none,t:removeWhiteSpace,t:lowercase,pass" + + # This should see cached versions of *both* ARGS_GET + SecRule ARGS:test "queryval" "phase:2,t:none,t:removeWhiteSpace,t:lowercase,deny,chain" + SecRule ARGS:test "firstval" "t:none,t:removeWhiteSpace,t:lowercase,chain" + SecRule ARGS:test "secondval" "t:none,t:removeWhiteSpace,t:lowercase" + ), + match_log => { + debug => [ qr/removeWhiteSpace,lowercase: "queryval" .*removeWhiteSpace,lowercase: "firstval" .*cached.*removeWhiteSpace,lowercase: "secondval" .*cached/s, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/index.html?test=Query+Val", + [ + "Content-Type" => "application/x-www-form-urlencoded", + ], + # Args + "test=First+Val&test=Second+Val", + ), +}, +{ + type => "misc", + comment => "tfncache (large cache)", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRequestBodyAccess On + + + SecRequestBodyNoFilesLimit 1048576 + + SecRequestBodyInMemoryLimit 131072 + SecResponseBodyLimit 1048576 + + # We need to make this work no matter what the defaults may change to + SecCacheTransformations On "minlen:1,maxlen:0,maxitems:0" + + # This should cache it in all phases + SecRule ARGS "WillNotMatch" "phase:1,t:none,t:removeWhiteSpace,t:lowercase,pass,nolog" + SecRule ARGS "WillNotMatch" "phase:2,t:none,t:removeWhiteSpace,t:lowercase,pass,nolog" + SecRule ARGS "WillNotMatch" "phase:3,t:none,t:removeWhiteSpace,t:lowercase,pass,nolog" + SecRule ARGS "WillNotMatch" "phase:4,t:none,t:removeWhiteSpace,t:lowercase,pass,nolog" + + # This should use the cached value + SecRule ARGS "foobar" "phase:4,t:none,t:removeWhiteSpace,t:lowercase,deny" + ), + match_log => { + debug => [ qr/Adding request argument \(BODY\): name "test", value "Foo Bar"/, 60, "Waiting for httpd to process request: "], + -error => [ qr/segmentation fault/i, 60 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/index.html", + [ + "Content-Type" => "application/x-www-form-urlencoded", + ], + # 1000 Args + join("&", map { sprintf "arg%08d=0123456789abcdef+0123456789ABCDEF+0123456789abcdef", $_ } (1 .. 1000))."&test=Foo+Bar", + ), +}, diff --git a/apache2/t/regression/misc/20-pdf-xss.t b/apache2/t/regression/misc/20-pdf-xss.t new file mode 100644 index 0000000..92d7230 --- /dev/null +++ b/apache2/t/regression/misc/20-pdf-xss.t @@ -0,0 +1,54 @@ +# PDF XSS Protection + +{ + type => "misc", + comment => "pdf-xss - GET", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + + SecPdfProtect On + SecPdfProtectMethod TokenRedirection + SecPdfProtectSecret FooBar + SecPdfProtectTimeout 10 + ), + match_log => { + debug => [ qr/PdfProtect: PDF request without a token - redirecting to/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.pdf", + ), +}, +{ + type => "misc", + comment => "pdf-xss - POST", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + + SecPdfProtect On + SecPdfProtectMethod TokenRedirection + SecPdfProtectSecret FooBar + SecPdfProtectTimeout 10 + ), + match_log => { + -error => [ qr/exit signal/, 1 ], + debug => [ qr/PdfProtect: Not intercepting.*method=POST\/2/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.pdf", + [ + "Content-Type" => "application/x-www-form-urlencoded", + ], + # Args + "a=1&b=2", + ), +}, diff --git a/apache2/t/regression/rule/00-basics.t b/apache2/t/regression/rule/00-basics.t new file mode 100644 index 0000000..295bbc9 --- /dev/null +++ b/apache2/t/regression/rule/00-basics.t @@ -0,0 +1,91 @@ +### Tests for basic rule components + +# SecAction +{ + type => "rule", + comment => "SecAction (override default)", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 4 + SecAction "nolog" + ), + match_log => { + -error => [ qr/ModSecurity: /, 1 ], + -audit => [ qr/./, 1 ], + debug => [ qr/Warning\. Unconditional match in SecAction\./, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, + +# SecRule +{ + type => "rule", + comment => "SecRule (no action)", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 5 + SecDefaultAction "phase:2,deny,status:403" + SecRule ARGS:test "value" + ), + match_log => { + error => [ qr/ModSecurity: /, 1 ], + debug => [ qr/Rule [0-9a-f]+: SecRule "ARGS:test" "\@rx value" "phase:2,deny,status:403"$/m, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt?test=value", + ), +}, +{ + type => "rule", + comment => "SecRule (action)", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 5 + SecDefaultAction "phase:2,pass" + SecRule ARGS:test "value" "deny,status:403" + ), + match_log => { + error => [ qr/ModSecurity: /, 1 ], + debug => [ qr/Rule [0-9a-f]+: SecRule "ARGS:test" "\@rx value" "phase:2,deny,status:403"$/m, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt?test=value", + ), +}, +{ + type => "rule", + comment => "SecRule (chain)", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 5 + SecDefaultAction "phase:2,log,noauditlog,pass,tag:foo" + SecRule ARGS:test "value" "chain,phase:2,deny,status:403" + SecRule &ARGS "\@eq 1" "chain,setenv:tx.foo=bar" + SecRule REQUEST_METHOD "\@streq GET" + ), + match_log => { + error => [ qr/ModSecurity: /, 1 ], + debug => [ qr/Rule [0-9a-f]+: SecRule "ARGS:test" "\@rx value" "phase:2,log,noauditlog,tag:foo,chain,deny,status:403"\r?\n.*Rule [0-9a-f]+: SecRule "&ARGS" "\@eq 1" "chain,setenv:tx.foo=bar"\r?\n.*Rule [0-9a-f]+: SecRule "REQUEST_METHOD" "\@streq GET"\r?\n/s, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt?test=value", + ), +}, diff --git a/apache2/t/regression/rule/00-inheritance.t b/apache2/t/regression/rule/00-inheritance.t new file mode 100644 index 0000000..c661c28 --- /dev/null +++ b/apache2/t/regression/rule/00-inheritance.t @@ -0,0 +1,4 @@ +### Tests for rule inheritance + +### TODO: +# SecRuleInheritance diff --git a/apache2/t/regression/rule/00-script.t b/apache2/t/regression/rule/00-script.t new file mode 100644 index 0000000..8af6d7b --- /dev/null +++ b/apache2/t/regression/rule/00-script.t @@ -0,0 +1,63 @@ +### Test for SecRuleScript + +# Lua +{ + type => "rule", + comment => "SecRuleScript (lua absolute nomatch)", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 1 + SecRuleScript "$ENV{CONF_DIR}/test.lua" "phase:2,deny" + ), + match_log => { + -error => [ qr/Lua script matched\./, 1 ], + debug => [ qr/Test message\./, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "rule", + comment => "SecRuleScript (lua relative nomatch)", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 1 + SecRuleScript "test.lua" "phase:2,deny" + ), + match_log => { + -error => [ qr/Lua script matched\./, 1 ], + debug => [ qr/Test message\./, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "rule", + comment => "SecRuleScript (lua relative match)", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 1 + SecRuleScript "match.lua" "phase:2,deny" + ), + match_log => { + error => [ qr/ModSecurity: Access denied with code 403 \(phase 2\)\. Lua script matched\./, 1 ], + debug => [ qr/Test message\./, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, diff --git a/apache2/t/regression/rule/10-xml.t b/apache2/t/regression/rule/10-xml.t new file mode 100644 index 0000000..4ec937d --- /dev/null +++ b/apache2/t/regression/rule/10-xml.t @@ -0,0 +1,419 @@ +### Test for XML operator rules + +### Validate Scheme +# OK +{ + type => "rule", + comment => "validateSchema (validate ok)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRule REQUEST_HEADERS:Content-Type "^text/xml\$" \\ + "phase:1,t:none,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML" + SecRule REQBODY_PROCESSOR "!^XML\$" nolog,pass,skipAfter:12345 + SecRule XML "\@validateSchema $ENV{CONF_DIR}/SoapEnvelope.xsd" \\ + "phase:2,deny,id:12345" + ), + match_log => { + debug => [ qr/XML: Initialising parser.*XML: Parsing complete \(well_formed 1\).*Target value: "\[XML document tree\]".*Successfully validated payload against Schema/s, 1 ], + -debug => [ qr/XML parser error|validation failed|Failed to load/, 1 ], + -error => [ qr/XML parser error|validation failed|Failed to load/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "text/xml", + ], + normalize_raw_request_data( + q( + + + + + 12123 + + + + ), + ), + ), +}, +# Failed attribute value +{ + type => "rule", + comment => "validateSchema (validate attribute value failed)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecAuditEngine RelevantOnly + SecAuditLog "$ENV{AUDIT_LOG}" + SecRule REQUEST_HEADERS:Content-Type "^text/xml\$" \\ + "phase:1,t:none,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML" + SecRule REQBODY_PROCESSOR "!^XML\$" nolog,pass,skipAfter:12345 + SecRule XML "\@validateSchema $ENV{CONF_DIR}/SoapEnvelope.xsd" \\ + "phase:2,deny,log,auditlog,id:12345" + ), + match_log => { + debug => [ qr/XML: Initialising parser.*XML: Parsing complete \(well_formed 1\).*Target value: "\[XML document tree\]".*'badval' is not a valid value of the local atomic type.*Schema validation failed/s, 1 ], + -debug => [ qr/Successfully validated payload against Schema|\n\r?\n/, 1 ], + audit => [ qr/^Message: Element.*'badval' is not a valid value of the local atomic type\.\nMessage:/m, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "text/xml", + ], + normalize_raw_request_data( + q( + + + + + 12123 + + + + ), + ), + ), +}, +# Failed validation +{ + type => "rule", + comment => "validateSchema (validate failed)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecAuditEngine RelevantOnly + SecAuditLog "$ENV{AUDIT_LOG}" + SecRule REQUEST_HEADERS:Content-Type "^text/xml\$" \\ + "phase:1,t:none,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML" + SecRule REQBODY_PROCESSOR "!^XML\$" nolog,pass,skipAfter:12345 + SecRule XML "\@validateSchema $ENV{CONF_DIR}/SoapEnvelope.xsd" \\ + "phase:2,deny,id:12345" + ), + match_log => { + debug => [ qr/XML: Initialising parser.*XML: Parsing complete \(well_formed 1\).*Target value: "\[XML document tree\]".*element is not expected/s, 1 ], + -debug => [ qr/XML parser error|Failed to load/, 1 ], + -error => [ qr/XML parser error|Failed to load/, 1 ], + audit => [ qr/^Message: Element.*This element is not expected.*\nMessage:/m, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "text/xml", + ], + normalize_raw_request_data( + q( + + + + + 12123 + + + + ), + ), + ), +}, +# Bad XML +{ + type => "rule", + comment => "validateSchema (bad XML)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecAuditEngine RelevantOnly + SecAuditLog "$ENV{AUDIT_LOG}" + SecRule REQUEST_HEADERS:Content-Type "^text/xml\$" \\ + "phase:1,t:none,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML" + SecRule REQBODY_PROCESSOR "!^XML\$" nolog,pass,skipAfter:12345 + SecRule XML "\@validateSchema $ENV{CONF_DIR}/SoapEnvelope.xsd" \\ + "phase:2,deny,id:12345" + ), + match_log => { + debug => [ qr/XML: Initialising parser.*XML: Parsing complete \(well_formed 0\).*XML parser error.*validation failed because content is not well formed/s, 1 ], + -debug => [ qr/Failed to load|Successfully validated/, 1 ], + -error => [ qr/Failed to load|Successfully validated/, 1 ], + audit => [ qr/^Message: .*Failed parsing document.*\nMessage:/m, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "text/xml", + ], + normalize_raw_request_data( + q( + + + + + 12123 + + + + ), + ), + ), +}, +# Bad schema +{ + type => "rule", + comment => "validateSchema (bad schema)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecAuditEngine RelevantOnly + SecAuditLog "$ENV{AUDIT_LOG}" + SecRule REQUEST_HEADERS:Content-Type "^text/xml\$" \\ + "phase:1,t:none,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML" + SecRule REQBODY_PROCESSOR "!^XML\$" nolog,pass,skipAfter:12345 + SecRule XML "\@validateSchema $ENV{CONF_DIR}/SoapEnvelope-bad.xsd" \\ + "phase:2,deny,id:12345" + ), + match_log => { + debug => [ qr/XML: Initialising parser.*XML: Parsing complete \(well_formed 1\).*Target value: "\[XML document tree\]".*Failed to parse the XML resource.*Failed to load Schema/s, 1 ], + audit => [ qr/^Message: .*Failed to parse the XML resource.*\nMessage: Rule processing failed/m, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "text/xml", + ], + normalize_raw_request_data( + q( + + + + + 12123 + + + + ), + ), + ), +}, + +# Validate DTD +# OK +{ + type => "rule", + comment => "validateDTD (validate ok)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRule REQUEST_HEADERS:Content-Type "^text/xml\$" \\ + "phase:1,t:none,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML" + SecRule REQBODY_PROCESSOR "!^XML\$" nolog,pass,skipAfter:12345 + SecRule XML "\@validateDTD $ENV{CONF_DIR}/SoapEnvelope.dtd" \\ + "phase:2,deny,id:12345" + ), + match_log => { + debug => [ qr/XML: Initialising parser.*XML: Parsing complete \(well_formed 1\).*Target value: "\[XML document tree\]".*Successfully validated payload against DTD/s, 1 ], + -debug => [ qr/XML parser error|validation failed|Failed to load/, 1 ], + -error => [ qr/XML parser error|validation failed|Failed to load/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "text/xml", + ], + normalize_raw_request_data( + q( + + + + + + 12123 + + + + ), + ), + ), +}, +# Failed validation +{ + type => "rule", + comment => "validateDTD (validate failed)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRule REQUEST_HEADERS:Content-Type "^text/xml\$" \\ + "phase:1,t:none,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML" + SecRule REQBODY_PROCESSOR "!^XML\$" nolog,pass,skipAfter:12345 + SecRule XML "\@validateDTD $ENV{CONF_DIR}/SoapEnvelope.dtd" \\ + "phase:2,deny,id:12345" + ), + match_log => { + debug => [ qr/XML: Initialising parser.*XML: Parsing complete \(well_formed 1\).*Target value: "\[XML document tree\]".*content does not follow the DTD/s, 1 ], + -debug => [ qr/XML parser error|Failed to load/, 1 ], + -error => [ qr/XML parser error|Failed to load/, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "text/xml", + ], + normalize_raw_request_data( + q( + + + + + + 12123 + + + + ), + ), + ), +}, +# Bad XML +{ + type => "rule", + comment => "validateDTD (bad XML)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRule REQUEST_HEADERS:Content-Type "^text/xml\$" \\ + "phase:1,t:none,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML" + SecRule REQBODY_PROCESSOR "!^XML\$" nolog,pass,skipAfter:12345 + SecRule XML "\@validateDTD $ENV{CONF_DIR}/SoapEnvelope.dtd" \\ + "phase:2,deny,id:12345" + ), + match_log => { + debug => [ qr/XML: Initialising parser.*XML: Parsing complete \(well_formed 0\).*XML parser error.*validation failed because content is not well formed/s, 1 ], + -debug => [ qr/Failed to load|Successfully validated/, 1 ], + -error => [ qr/Failed to load|Successfully validated/, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "text/xml", + ], + normalize_raw_request_data( + q( + + + + + + 12123 + + + + ), + ), + ), +}, +# Bad DTD +{ + type => "rule", + comment => "validateDTD (bad DTD)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRule REQUEST_HEADERS:Content-Type "^text/xml\$" \\ + "phase:1,t:none,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML" + SecRule REQBODY_PROCESSOR "!^XML\$" nolog,pass,skipAfter:12345 + SecRule XML "\@validateDTD $ENV{CONF_DIR}/SoapEnvelope-bad.dtd" \\ + "phase:2,deny,id:12345" + ), + match_log => { + debug => [ qr/XML: Initialising parser.*XML: Parsing complete \(well_formed 1\).*Target value: "\[XML document tree\]".*Failed to load DTD/s, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "text/xml", + ], + normalize_raw_request_data( + q( + + + + + + 12123 + + + + ), + ), + ), +}, diff --git a/apache2/t/regression/rule/20-exceptions.t b/apache2/t/regression/rule/20-exceptions.t new file mode 100644 index 0000000..12c058e --- /dev/null +++ b/apache2/t/regression/rule/20-exceptions.t @@ -0,0 +1,176 @@ +### Tests for rule exceptions + +# SecRuleRemoveById +{ + type => "rule", + comment => "SecRuleRemoveById (single)", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRule REQUEST_URI "test" "phase:1,deny,status:500,id:1" + SecRuleRemoveById 1 + ), + match_log => { + -error => [ qr/ModSecurity: /, 1 ], + -audit => [ qr/./, 1 ], + debug => [ qr/Starting phase REQUEST_HEADERS\..*This phase consists of 0 rule.*Starting phase RESPONSE_HEADERS\./s, 1 ], + -debug => [ qr/Access denied/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "rule", + comment => "SecRuleRemoveById (multiple)", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRule REQUEST_URI "test" "phase:1,deny,status:500,id:1" + SecRule REQUEST_URI "test" "phase:1,deny,status:500,id:2" + SecRule REQUEST_URI "test" "phase:1,deny,status:500,id:3" + SecRuleRemoveById 1 2 3 + ), + match_log => { + -error => [ qr/ModSecurity: /, 1 ], + -audit => [ qr/./, 1 ], + debug => [ qr/Starting phase REQUEST_HEADERS\..*This phase consists of 0 rule.*Starting phase RESPONSE_HEADERS\./s, 1 ], + -debug => [ qr/Access denied/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "rule", + comment => "SecRuleRemoveById (range)", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRule REQUEST_URI "test" "phase:1,deny,status:500,id:1" + SecRule REQUEST_URI "test" "phase:1,deny,status:500,id:2" + SecRule REQUEST_URI "test" "phase:1,deny,status:500,id:3" + SecRuleRemoveById 1-3 + ), + match_log => { + -error => [ qr/ModSecurity: /, 1 ], + -audit => [ qr/./, 1 ], + debug => [ qr/Starting phase REQUEST_HEADERS\..*This phase consists of 0 rule.*Starting phase RESPONSE_HEADERS\./s, 1 ], + -debug => [ qr/Access denied/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "rule", + comment => "SecRuleRemoveById (multiple + range)", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRule REQUEST_URI "test" "phase:1,deny,status:500,id:1" + SecRule REQUEST_URI "test" "phase:1,deny,status:500,id:2" + SecRule REQUEST_URI "test" "phase:1,deny,status:500,id:3" + SecRule REQUEST_URI "test" "phase:1,deny,status:500,id:4" + SecRuleRemoveById 1 2-4 + ), + match_log => { + -error => [ qr/ModSecurity: /, 1 ], + -audit => [ qr/./, 1 ], + debug => [ qr/Starting phase REQUEST_HEADERS\..*This phase consists of 0 rule.*Starting phase RESPONSE_HEADERS\./s, 1 ], + -debug => [ qr/Access denied/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, + +# SecRuleRemoveByMsg +{ + type => "rule", + comment => "SecRuleRemoveByMsg", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRule REQUEST_URI "test" "phase:1,deny,status:500,id:1,msg:'testing rule'" + SecRuleRemoveByMsg "testing rule" + ), + match_log => { + -error => [ qr/ModSecurity: /, 1 ], + -audit => [ qr/./, 1 ], + debug => [ qr/Starting phase REQUEST_HEADERS\..*This phase consists of 0 rule.*Starting phase RESPONSE_HEADERS\./s, 1 ], + -debug => [ qr/Access denied/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, + +# SecRuleUpdateActionById +{ + type => "rule", + comment => "SecRuleUpdateActionById", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRule REQUEST_URI "test" "phase:1,deny,status:500,id:1,msg:'testing rule'" + SecRuleUpdateActionById 1 "pass,nolog" + ), + match_log => { + -error => [ qr/ModSecurity: /, 1 ], + -audit => [ qr/./, 1 ], + debug => [ qr/id:1,.*,pass,nolog/, 1 ], + -debug => [ qr/Access denied/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + ), +}, +{ + type => "rule", + comment => "SecRuleUpdateActionById (chain)", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRule REQUEST_URI "test" "phase:1,deny,status:500,id:1,msg:'testing rule',chain" + SecRule ARGS "bar" + SecRuleUpdateActionById 1 "pass,nolog" + ), + match_log => { + -error => [ qr/ModSecurity: /, 1 ], + -audit => [ qr/./, 1 ], + debug => [ qr/id:1,.*,pass,nolog/, 1 ], + -debug => [ qr/Access denied/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt?foo=bar", + ), +}, diff --git a/apache2/t/regression/server_root/conf/SoapEnvelope-bad.dtd b/apache2/t/regression/server_root/conf/SoapEnvelope-bad.dtd new file mode 100644 index 0000000..7d6c19f --- /dev/null +++ b/apache2/t/regression/server_root/conf/SoapEnvelope-bad.dtd @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/apache2/t/regression/server_root/conf/SoapEnvelope-bad.xsd b/apache2/t/regression/server_root/conf/SoapEnvelope-bad.xsd new file mode 100644 index 0000000..2acfd1d --- /dev/null +++ b/apache2/t/regression/server_root/conf/SoapEnvelope-bad.xsd @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Prose in the spec does not specify that attributes are allowed on the Body element + + + + + + + + + + + + + + + + + + + + 'encodingStyle' indicates any canonicalization conventions followed in the contents of the containing element. For example, the value 'http://schemas.xmlsoap.org/soap/encoding/' indicates the pattern described in SOAP specification + + + + + + + + + + + + + + + Fault reporting structure + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apache2/t/regression/server_root/conf/SoapEnvelope.dtd b/apache2/t/regression/server_root/conf/SoapEnvelope.dtd new file mode 100644 index 0000000..0ad4a8a --- /dev/null +++ b/apache2/t/regression/server_root/conf/SoapEnvelope.dtd @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/apache2/t/regression/server_root/conf/SoapEnvelope.xsd b/apache2/t/regression/server_root/conf/SoapEnvelope.xsd new file mode 100644 index 0000000..2b4a8c0 --- /dev/null +++ b/apache2/t/regression/server_root/conf/SoapEnvelope.xsd @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Prose in the spec does not specify that attributes are allowed on the Body element + + + + + + + + + + + + + + + + + + + + 'encodingStyle' indicates any canonicalization conventions followed in the contents of the containing element. For example, the value 'http://schemas.xmlsoap.org/soap/encoding/' indicates the pattern described in SOAP specification + + + + + + + + + + + + + + + Fault reporting structure + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apache2/t/regression/server_root/conf/httpd.conf.in b/apache2/t/regression/server_root/conf/httpd.conf.in new file mode 100644 index 0000000..c24399e --- /dev/null +++ b/apache2/t/regression/server_root/conf/httpd.conf.in @@ -0,0 +1,37 @@ +### Base configuration for starting Apache httpd + + + # File locations + PidFile @MSC_REGRESSION_LOGS_DIR@/httpd.pid + ScoreBoardFile @MSC_REGRESSION_LOGS_DIR@/httpd.scoreboard + + + + LoadModule proxy_module @APXS_LIBEXECDIR@/mod_proxy.so + LoadModule proxy_http_module @APXS_LIBEXECDIR@/mod_proxy_http.so + + + LoadModule unique_id_module @APXS_LIBEXECDIR@/mod_unique_id.so + + + + # TODO: Need to have these configurable + LoadFile /usr/lib/libxml2.so + LoadFile /usr/lib/liblua5.1.so + LoadModule security2_module @APXS_LIBEXECDIR@/mod_security2.so + + +ServerName localhost + +CoreDumpDirectory @MSC_REGRESSION_SERVERROOT_DIR@/tmp + +LogLevel debug +ErrorLog @MSC_REGRESSION_LOGS_DIR@/error.log + + + DocumentRoot @MSC_REGRESSION_DOCROOT_DIR@ + + Options Indexes FollowSymLinks + AllowOverride None + + diff --git a/apache2/t/regression/server_root/conf/match.lua b/apache2/t/regression/server_root/conf/match.lua new file mode 100644 index 0000000..fafd39b --- /dev/null +++ b/apache2/t/regression/server_root/conf/match.lua @@ -0,0 +1,14 @@ +-- Test matching Lua Script to just print debug messages +function main() + m.log(1, "Test message."); + m.log(2, "Test message."); + m.log(3, "Test message."); + m.log(4, "Test message."); + m.log(5, "Test message."); + m.log(6, "Test message."); + m.log(7, "Test message."); + m.log(8, "Test message."); + m.log(9, "Test message."); + + return "Lua script matched."; +end diff --git a/apache2/t/regression/server_root/conf/test.lua b/apache2/t/regression/server_root/conf/test.lua new file mode 100644 index 0000000..1cff076 --- /dev/null +++ b/apache2/t/regression/server_root/conf/test.lua @@ -0,0 +1,14 @@ +-- Test Lua Script to just print debug messages +function main() + m.log(1, "Test message."); + m.log(2, "Test message."); + m.log(3, "Test message."); + m.log(4, "Test message."); + m.log(5, "Test message."); + m.log(6, "Test message."); + m.log(7, "Test message."); + m.log(8, "Test message."); + m.log(9, "Test message."); + + return nil; +end diff --git a/apache2/t/regression/server_root/data/.empty b/apache2/t/regression/server_root/data/.empty new file mode 100644 index 0000000..e69de29 diff --git a/apache2/t/regression/server_root/htdocs/8k.txt b/apache2/t/regression/server_root/htdocs/8k.txt new file mode 100644 index 0000000000000000000000000000000000000000..6d17cf9d15fb9f4a2358a2d079f3b8c755d005fa GIT binary patch literal 8192 zcmeIu0Sy2E0K%a6Pi+o2h(KY$fB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM GyblZ@00031 literal 0 HcmV?d00001 diff --git a/apache2/t/regression/server_root/htdocs/index.html b/apache2/t/regression/server_root/htdocs/index.html new file mode 100644 index 0000000..16c51c1 --- /dev/null +++ b/apache2/t/regression/server_root/htdocs/index.html @@ -0,0 +1 @@ +INDEX diff --git a/apache2/t/regression/server_root/htdocs/test.pdf b/apache2/t/regression/server_root/htdocs/test.pdf new file mode 100644 index 0000000000000000000000000000000000000000..a6ec2d04c7ff2428885770f29ac8164264ab53c7 GIT binary patch literal 15406 zcmaib1yr2PmM!k?PUBAF?rtGSaF@p2-5r8^2u^T!2=1;ygL|;xP9FUC&b66&^DXGA zI(4MZsa>^N)}~UDkYZwG=0Kq8EA0E;*VLDTzy@Fe*c)3R2nYZbKz8OX76A4)i3(84 z(#8ek1eCHdasf$zOzcfTLP7}6E>0jLTLh0RL4^r~UKXUz13D)hz9bu4Zd&N#t4&*_ z-+=Y!R`|2+<5g1@hz)xTD?I<-l48p?^}i(e_X4m2*f_aZIQ})=Qy*_# z-GSxbZSJZbF=dG;Qzu7jNKUpoEXYj&8u-@2ioImY6y>y;z zWq6wHXJnXXua5JEuSwW&gnY6fs->OgCyK#2Fm;5>OGE2zTR(+A+cIeS1tuIBe+~OG z6S$?*)q2GZH_{av&m+XbvCy^0c}pZl04b*B8=PlIs?o@gOm@J@GMFz~vc$qp9eRnW z>)#GKP*^7(%pJ&K&c9_m$2z@h$#HyJIo$e zh)=R!ssqSk=)m?*FR4Y z_K=#N8NsM;6-^~*ZT>D^qwu@zz4KTHuck8aI%3L{^EgUVFP>v?{TC5gr?6 zQDaGJ4d*<9&6-{B%`4}sye~daw!~aaoGluu1ktE;T3#b9T&018{Wg;B zD2xhpX;JBm(i6)g!;YC>zg!?Hw{~RPbmgI6{NV8+)*~E)Bh@R65Y!^W{l-9l@0S_c zHUghxLO@6OjL9J_^FWaTR}%8TA`rtzAFs=R}uaLMsH_XmV z^$d-4H!{EOx}%Y_lsManY^Bf}h)+c}pelvp`~qHsgpGDZ9_kLmx6232Rholsu4Ys= zJD^Jz`#<&!KBsuqn>j?#nGKJ7Gm5R-I2{nqn9=!)DhrHn~g9(+#tPzS8*LTAE= zR^?<-!C~wB?$!X090XGZZMlJR>SL+WiLSuOr2E@MD}LKl?<$ZlWHUH2rB z6J?*t%X?Lv@lnM)9;?EJci0F^5JBaheG-BM;R1(fs0(tECY@%9Lw#&zS*|JD)`Wiv zSnpmZY~;@z6^RnLj!}&TI}l#jlaY|2p)yfQh!%-~u~`o0sRUgH@pJ@hy@K#8xfPXX zJ?(0N+J=0x=jMV&9OOzW4a_yj-^fQ5g@n@yJYX3YLQ;39=tQo1xo3SQdL{D%?}`?t z#x)5Z8(=j4l@4Qu&))qLZt?3l{J!hH??V4=UHg(_%b7`z@dg%If=n_-T2G_cca7(o zUCC1UHn9~7@1wc7gQ!W@EN^d^iQP#bqy4Ik1GCrom2?8g*RR9TKHWzX-FtpDJ+NC| zSd15R*Ax+JUHRW%vDr0|aO}I?YG6<;Dp7z#3|rd4z;J6w-7mk*T7p_&QF|K^<92{s z#}~-=>d$IkYmnC7X#Rx4(2IA!SzG)fH+s&ugtxoc4EvD~7fwtO(v1gE8Eg$x*_p=q zT42)Qbd{+GZD5fF$BB$$*{bXDE0S*NMBND6b6%LA1fB?%82(XpegBnc%U^N%Hg z(fa5eWRDUy=-iR819y=*X?RrFiO7jeiQbfP^6P0n^eHkrMS`=|h1IgEY%~((qnJVY}0=h5*x2p zLaxXB$S!PJZC?FRFxsmBZp*#@jC$d+lP|>pu z90TY}{azn@+}i5MGx09-)A5bp_&&H2pL4d<$YGtSc806Ku&&=1(XevW1tan(%8DAuIli6`Gfw-LOZ zOFed)YJ3g|5(gSpFxE=={E_k&B>d?$wDYM+0dexCd*loKn))X#RPAs%C7LVpGVqOi zLEY0s>Q7;@fyjRNDJ*xn)+#$KsN1gu5jjYiy*f&)>S7J!FzaqTehC9h035fTia+2N ze~Qs=zFc$_5T`>;!hXG{Q=?sW#)w()nP)^bR9;pQ>Y#Sdb16_BLcqx(?cJ^Z=GHnJmIct9!Jv% z@3!Pe4NYf2Z)v+Sfn&@n?zQYYs zJBB68PeS#nyjj|VQbyrkuzJ~EJfI!~j&y>c;U^?7CHk->_So@lSja$;wZt(i+{OFy zavU}FUnA zuDNV#9rt^_;0O%=Fwv1+dNXT=?+snw136NawMCbwUwOjXoGF}hVT<|Hgzn|$-szQ2 zCFSX10Bd55v({ZUh~Nm$;uObV$61FPm+}E z7b!%}Ro--jXVUNzTrEy76fD~VKwjjj$J^Eve8UT|Z^XDc`-+fDLQ6RWv_BXl`o*f4 zFH+l1G2)VxdbEu50yE1dw92;Fv5MmM4Ant6Lj!tn_9w7amzp#DfMM>d=p12huWxVP z>Eq15*ift!Z|l4ogt4J7xJYf7ZVwhnBdHiaFUOz0-ZpVs2=UrK3A+8}aEIW)xyhO_ zGd)R=fkI*u!$^#9au?N_Ae*NrIf%haHUIkbt&okyP&>F4Bx`$zAatsvS^3AbxO5(W zHrni<9o|}Qp#?V;7f1^<{MZ-{9VYpp;Jmso=#7QAk}6uWQg5E|Ri~-g`=bLr=eo&3 z!>yq7vRjky$A(gG^%vDr6YtL>pk|kDau~Bz%Zg@cXyLD2H?|QieAd{B*sm+$wKvPBWbwOHdq6i{q11 zHRmdi6lGXWB66Hgu8YB0AE6Wx=M2&04gKX4`MIvea$!)+$M?Ta>{og))N|UGYpL5* z);DRMqi@*yNIb_Yk8TP$rw)`fuI%Cz3|gfToDBC`aIzg^u@eu+_q}`q@K-7p2X1L^ zdC-cf#vFUIwKDOKZF7Ar`UYuPh@a88&wM3XKkO6Z*h3=d8*+S1d6IK#V<8+hUV0=8 zq9V)rWJUk;4CRiFsUnyIW|ua%0xG@IA9X=i{g<1`DdGyQoV)|guYUa7=b&ewc0oaQ z{_^j-_LYpl;IE8pc1d!SD&Ap-ejhs7`q-x3ex`4z_?)#SevYkxZPUdrFMQCx_?2<6 zO2ny_leK0^=fua*k}i{y%IX5GFE)8$r8Kp%N#c(FSS{k{np>ixyjFRpTj*$YIaE$l zCOPu!=ojXX3Y{RG^7itALVBgoycv1ZSwaI=5Jz10d98*iACxT?s_JwQCmvL7w7bo# z8GrxKNM|5q)u@5X6Nr;RcrGrs#^!|y_Yn(BLa0!dz=p*FGDt+x?Joz+MOUEY46Ob- zy_M?7cRUYCll5Y~wCb2!$J9?~ZvU01CsFwI>#A`-#^eQWggm0g+ELqzOV^)*xt#5| zpTFstEb$Oc_cQz1BInZWF%HseKBY2Dup7lQz%BZ&xq9dzQLeTkQ-1BVQ1;YPcT3G4 z=8jG~Cnw)TKx_Lz{$Xm@TJ*3!Wfp=)AM-)wWu=6b;)60qx>i1FGM%QpiR@9Tn%AGY zjLfl<44BVU8U|TmuG_1VH@a&L7g5~>>{B+|NYvp40E2cM?sZp?qvTl3kzCHe*09ni zdsE=kV3cm9AcCI~A~PlQ1nt(z)v?HA2&6lIek}Zu=n#H*x^n|xI+!exp_=sQD7}Tg zUf;nwhEOxVCCTr-UG;!LHudHCP&4AgQb2JwyAGimZ&?gHeCj=VU1=dc-#`e_*b5`; ze3)D!G>2=-iF%6M*8(>@2)nMp`90>c(sY(hb;vU=31rN$;4pTWTBBK^2e2PgP3fz? znY4S1yR24|uEi!td|m3(C`%m5352E_ktQvS@;P+1tCtK6IG}O(%+Xdu_32Q_Xk1+E zAIzOx#SMPn@_NjZF-p;7rJJX^r}k+3Xf^%! zQD@Z^irb;F4f755QUp+u*)^ldAdW85U9ReqU}W~qhpnF?UI{%}R~0i^)*}Ney3A=K zRG)dL%o3!&C?3?5r;vXDpXfJxHrZuhrVnK~VNBfD|B_^qZkz_qRv$H?_%+c}HoW!> zbj-gXtfO^|^#xx^inB!r^M`_k<^+~L)-c`h#D$ir=02}dKs#bS^bRzmhLTD*7E$oi zXSQ)-JFXTozTm;dtk|zb%$_L5E2g7S{QS=YHU1yIvE&vjuN|pQ`?bZc4A7k(x#%^K zCP9(s_8K+w&yOlJYI{0oPJL}seF{c_ob~g#bumY>{+J^;v4d4)XX}Km&12gpVI|v~ zSyQNFCYH5eBc_tJ6oS5lePQ?8oazNRIb`=p!yb`uj7_-ww_aziKabJf-MZgy1!m?Up!?pvqsW#y zSWLef)~oI|4lhC%YMB7mu3ySRMY;Tr41~^g;mpT+B4M80rzCto{+v>PH+|nZtLbl( zqx)J8zH~8I)x&2JMd`;Zcnc1ZZx{92oZ|)5kXi7D^DJ=$7GOw6Sn*F+LVzzQ5ne}b z1WVUwXLa?Se;5FrW*>pDu#CZ93VkA!HWT(h%Z0iF3Yu5$y0tbG=0|NW1Lo4JVHJ-y zjX$i~s*5dE9rkUj@796L+N#-AKT4N|%>A5(Qq|V2H1g~{&$->txEY)-E_LkMe{Q(! zNqqL7Yx1t+w1k1PvjF|#XeSh?N75U#fs;u7Cb$=4_d;H=!}xm9CcXQSPV=iyGv+B{ z7yPN(S!MF>QJqzT>y9gVt7W4{V_~FqU1b&g{OM#8-E1LIU1k47RLW>d%7hv+Cj)S` zkVt8rwoBA8SYvfKy^&QC>P?9v{WA<=j4ZTMBCv5D!k2~PIB8us>>=SWWI0r4xy>tjXQ#=`tG;Tr@9No&Y zsAh&2$Hl)zx@{P5)8rs6{S;T|iPP$|>4Yc-DpeS5HD_7aj(u3~2po{P*U;BYt#_;A z_>G(eyw5%r-(GXUbx;3Nyqh~bVTOUd?#sz}oVy$ypl;_WDDzV0q(~UUVv{m%bmWp! zDZO^46$JK$xZo2+uY}m%4j6aAtBuj~=xXK7XEab}nFSY0saTVT!CnPLii+JX<>!-c zhp{@8*t*n*PAe4$dj#;W(Zal5OVBY+aHsI`mKH6mTE5bw;K=KWOV%ZUQ$blO9!J!0op(BqC^$1?!Z#F_uZYz2Sir&94V5A~rke3)h$8K@Ih-H6CRPtzVsv`=Q6U=5jw8f4Fn52l87x z3#`3j>+M3NW;`OQGI*ij&m2o9@ZI?3>hGQR>LID7H4FRtPddI_RFr1jITylS{yx+F znQx`+UfMQKir`(x5cTyB<+;YT|p_$xnCwRID~Hud#No3{h)! z4@n_U@+LmlD7`6aW$IBA0tntVW^r>x?q8EWU$GAysB18jgc%Gkbt2dq2-MYv8IfzE zleW>*%7fJX^M*Byl6Qw!*{jBXjjr3=i&bIOJ4JqCR*k%2plZ+1q2w;VwXh%e4&XKQ zVB6u`|1hDmQa`@2ghcF7tibSNw5@2Zj+STF?!kFB$6``Ojhs1)04j?Se$-8a*Zqe)Su?EZ#|Ws~%5Aeurv*^e^#ihN{( zv>)UoXTRnvd`c{$`EGXj+{XOE`~t3&BU8=YN#C1aIv+Wr&=s*EEJ4XwIsG76B)5kx zW#jTqz6dx{rz_P(jVN8`209%xuAekBiyd=_v=JLj9=;t}PpH+_5`mGArvlM{FqR7} zz0g-aWOLVL2UJlq#V=$I=5yE*qzz`v_F0Bt^1`uK_WbO&f3S<-v!1jq(D9=&EhcNR z7~vu<=SQx>mA}Kqw2wRNS+$fQcO3m_Z&p?wY01$bOeUIc)Z{uHAR)v-NhGO~u3&jr z4x!&gAR^@^nPxC*j**D}keFbPDTmNmxGC?XjZir9;$<5v94>!X&fCV>i@X+umq504 z*KA{)t^f)}IfJ}bWawC}lU?ui_2stjoUxwybDa(Q=Q^#p^R~d5dq=u|C2L*sxY``2 zD_Q1RKc)3aFJ|KzGqv;H;zN4@p9Asm49s1wofqn_9_u)A(i$h}51?B6`FIv;g~gWq z&g#rUldyB%*j7K==f)$ZaLQtlW9Pl6udhJ^RTvxlK@Otx+-It+3rr;3${~A-YqVUe=**B#b@CuFu|;t{}4Zi=$FWGv605igZX*4LTs;1QqR#S zaC{Otgn~&4%`3ULWZ95*MZ@W&F3zwz2%%j+VO0ynSswpsY`Vt?m!t{#D~PaBv4JV< zXpKN3DYUuUA<3{=Lwl?)q&*^N`3e#K_Fm`PGbi>zHuJ{eI0sGz-H^ZMFI>#7S6R!7 zPA9$f%{2x)3kG{oCl5QH-38CrAE{9M5;glH<)nNGO}cq4{@-8D_K~KGiDRcta;F$g zC4sP=xg7LYcC&tJPx6%>?QY)t6D!_qx5ox7o$+^>>Si*Fp#2Q3Qj(3VClLEiqAa77 zX`?KYRO63q+lkti+1Yso6bq;kg+?a67#D5gVul%L7vnX#_T0n(VrMs^M$(3yhI%(^ zt`nWR9j>cp%&1 zOc?8G$6!D!qgXg+U4&r`9)VtDjn0deYVTs2A>tE*n6^2V?S0akF=KGPaxcXE<>4V? z!qGg1a}worTVPU`ytdXRNeZz<}da5s<|78QLJD^Bg7-;#H zt^qk26y!tAprgL&CK!gmO3z4#ge8S28H$M!DH)|xc+Znn{q1)WIJ8`S#?{%?L=r!| z$*yVR=})@#!#^FW-c>j!B*sMkg+c8E!k%uF1;Q1(f)M`Ry`vB9}3*lwsRq?KiMb zkzLfi1M7MV@FOAD0Ve^^LZ`k*vemi_GjbVK`OMrViA91&scUw9AJdCeD;N!Hzo4ea zeZhBb>&y7OR_TDoOh-RoBrl?)y%h27cN@ji=5PK1AA!i|pQ@UKO6>@>ib+)+dIdcw zb)`f{XH~hLACPkve_XT{B<}|@CN&z9BPUgsFfe6ueRU)MkeIr|J1D0~w;k8@d{zr% z$2c|HC(C4d?wY-w!#}@}9sOhBYp{uZ?Ir=Axu}_Xr)tjmxKoCb=(k`2v~5z@0l+xe zI4a97T}VeA(PY$h&9F3HJ_R8W`pur#bNooF=}YSdPFw1}f?|_!E7MPXRijB}15oYm z6T~;vkcH^`4TaXXkNTUgZ-h3tKTUvw@3gRbU;uFwJ5F7q&8SXD{m# zw=TCCHe6pujkTahAUR(Luz9>y)|yK=31RDW>f7rJmNA!M1C`3?Ipj5#9rCnP45t{C z7R}Sy32)$JsSrYltx{N!{LNKcTa3j*b<|pPu+=`4pp;FP^p}lPc%s_g7hAeE9+1v; zqsKMWRbwUIMNZU$_i(r9=ved{SvamCR0Nz!XLC<$h=wr8UJ9t5M_y zByxof(24O2L}fuHuasfv6jz~KqeB$!eyZI@DU#5VGM~$(ipXIZJHzkBPC0)@4wZgoX#EPO}8At5O15cR(5A1;l>b(3EE+>B0far>L~Jld0}9fg&+32l^E2`RKPaF^(jON5Z1 z@SXrmlmZMsFiIR*DGFS17BC-92Mx<9KD_~}Nl}UVN*en~;O!fi1@SR7g0BUUbAN{M z(DxZ6{aWPWHM&PFYz43Jf_#Xt@xe$i8W#ERfGB9HrNY`{FXoat1!W- z53qCUfus^J!a4o=u;Z6z_4%+6btR1MTqiHq;YN6o2DVXxz$l$ll$Yl6AXmWxqql@G zKpf?s@@2$dG4WwRWCgE0={e5J_?5(1v^jrZX(TQ|GIG!Fh{trk_LOS1|1!oJ+6w-uUI6chT8K<%$(Us`5 zv5Ms2lJMB^2}k#JAUr86yLZAg!^!Zz#BeISP>{u}$Wvj4m*;rlbAK%E_{7%Z$r^lMt4{uX0j4A? zsKI^%Vr}T?=Xa3fCt+VK!Xgz!vXIM4BE=mxk&zUD=vIx}trzRgn)PzkOI>HJ*9 zd6mvw?s@(fPWJ~sF$QZYR=nT!r1$R+P7~AmBG9IA<+7Svh01)_+oVfF9ulOERvvhD zjxoA&WC?(f4V9_ zd=7Vz7qCl}Hby3Dl+!0QUF+ajK%TJlkclV|1QSngXEhoq;8?h%IL&1Wc4>gq^%+0G zc40^I_0Y11XcOY=O9vD@Toi`iuF?M|JPIb?|2m-(Bg$_+bB4eFZeo60+I=W*W?# zFsNCC=^`7%;T8W#U803b$NRz)^NXaDu|FBg_NDk$|R)n~>c1 zw@VYOF0aW2tv8t!Y~VF6F7tXHxx-E7AnZ#oYx#Nj6J$4sLzi;@PUR$zAt}@iIm{l_ z!K=MOG2+_(x*B@FAzt9Fxzu{^`I=yAHf72mLY#K5;-Qa}MY`wt@fU8zp7CWA+%Y)@ zB2z?Rz0lM0!()gHMnSePA1|A-H+{R$;0 zN2NGOnx%s}wdiw9f|E}P^j|N}5Aw~5`-W(Hc%|;LE~Gx&=&$Zv?@i`k7d@qe+%k88@vR4DJ0CMWe}3R_ZZRpWnfg*X|84JU$7wSZ?o+AE<=F%71sdzi6UG&nn zP^`Orb268}Nz&bGm1b{|YB69ee0$S|U%jC&+_*m@L)B2=O*a@F)~k_5gqJVOxP>YRGea$!tQj zAl+Iq?&+L%U};K;zV<)kYt^&>5Pb|W&J$u5=%os9>GP`MOy9h0ZQ|6G_wR~BjJnS;OF_U(!Wj1)ZZ18Sp)KMep25W-#djJhg{A4_z{Mhk4hDp4@{r(PI1u)A zM9ReI5XanvN?`yNF6)|l9Ed!~7-7A`#B`0-(_XeT1$v+hW|ZE(hm23kVvIK6sc>{P zEksr4z*s?#gDJ>M4?hmacS8#EhHZ5ST1Ag>_RaI~Fr=J6*l9_Dw?nhqE)cw!Zc^Sf zvWPi`zmW;f)yL;RZ8wP$eavMYiQ>y(APZ!hr}mVqiO15 zh<4o@S|t}EwY_yprfC{sfn8(4D5eRGZX1VWOOts>`dRcGPitD8yj9B=92Iv4PobFu z4^~Th_#Pm?X#{nmYe+=7ICK-#BJGVS!a+bIs3Tr$LCZ=|*fh(BMI;*{I%T9kZkS-A zYg!T)O*1Ic*b&^LiT2oQ5$Rx`b&S7vgL#4|H4+gC$1Spe-d4uV!6AVo0L8U}NrFH# zXt+Idh=z6wM+4IuCnvpgcS z8xlh);y2C;?h)}`noLBn_yru*G2&2xcn@o5oxL}0DqK?IBMfGw#RtcWSYm#kz94|F zA>Tl78 z?xkwu#l&j#e zW1+qC5S~e}R5!tzlULBQiV`ql-xDwwJa*u@p}dWhBgm+%FyWRRWyY@To1EiF?jJ2@_1K3@o!#ed9EEr=pm4QGT}^Jc>z{$}BE~7#!_fN$%uHgqeRygs zxSp_^o0`&=GKMmQ*0NbEds#`@NZrmne0q5~c?NnwC4KdF8IIZ`!;95`@b9)MS1A>G zoTUOkIPNiYuP?H8h{GSY@zncfOc04gg>qrjmYbHt{e7Q<`ERXHjBd4VdAgNv@t&57 za2e9{D|EeTosI?&+OCcFW}{Q&f$Gd1nyvrq;KBcLU^J+h^xy(e)TO!Fj(ZKyQx4W}N5OpP)(y>^cW9y|FHTDImGt2?LU~!NU@h~cgBCH~arADZ=;Q>>yBVBdk+DK^NORxYj z+miyNu9U(PiW3~u;Lhe6cXGj9?`3|ASEgZSvOm=GU&y*hM=6B?$>*V24gMcWHcESoHjC#EOClfh~N*5H@E0^0Z^gUAL> zZcfm?9(T*PtQ^Xm0 zS{IUIG2oNj63;j;jR7d&6Jj@b4d9Mv`0G3k*;g1I(PR4n7l=&&T`j*zY-slnJGZgI zF$gIxhkjDpa_`JjSY_CyR|;NF(9>kvE`o7Hd@+1$*mRhM^%sYb6N-3O?qt*Y1=Q?IL{ zDwHQsqCj7qLX*5*XsYcb=A_~zMZQl-l^9T{Hp>(#H%Nt<7>vRDAcr$o8ACsmQlUOV zC!Y)sDp#>d*bctot`poXM~b%s&j-TWqdcfkD7aIj{fT(FWqXg4LF08ku67%K`2x-d6z8xh%YgOCKqod1&8ujbMb&^kGEjZuU zyS9Ew?KyYYxS5BEc`P{Jx17|#*XL%eTvD%`qTIdGtbF*clzNQ{#L>(v`?_nYXs4C( z?UilcQBx7O5Eg75+%Vy9a3&Uk5*ZgzwC;jz+z4Db&&3H~24lT`M1g0G*AC%Q@egQ1 zk7-~>T+z~eHc8^#W4b9PJ8=Ui0y8u^8OnWOm76e$n|q`zq_Omk7V(c?z@$g)wh_jF z;+}J8#{cQSUIuvx5dje~Gj>9KjRF>fQVI<~_{|d#v4*rr?S^?p+(KePVj>9cTDl%o zS7-P%T{PBkqb&v9lsgzVeNB>i_RW&`194!3+OIf`(ylH!-#L0$a6k+q7Z+z|(zk_x zI{g=kj>1!FEmFodm*@-);iC=&I(%Lrxt7{YxkXHhg$BGr7?0CGqp`968if530~a7 zJ0XcIs{+SN7n}lBv@`4cC&v+42f+xGYKzgVK7tnb)+N4;bfpX5Sm9S@Hq_-KG-}gg z1;T`+eM?R83=Imx2~g7Qu_4w7=A>$B*P_q|oLHgW%#kO?E^nBHX7s2(h}BsFrk;DW z=!=DWpeZajA<#qXi{%(9v8u;TA!vo2DmZK>n+`_Uk{3x#5rQc=r%vDuzs6@sQHQia zoT21Vq;k=z+P5Cmg*lp(dMq%7#x>1S;X%RS?vbjgzDQEX=&WdDfimA~3LaWCNK${F z*XD&#E#Ne)@++OZBDotcJi897C+5LzbTq8YM1d-CdnQ0SGyYbFTMn4UoSG`%p`w^c z!zs%S;>%D^rB)rmV#`n<#~i`KPXs0A2s_Rhz$I85ePoW7q0etgC8HDX(htXDH0gFv z#J6Fe`|d}l_$yP{d3Dw_rQK65Q#-A~jhhBkX<#87b74!YB*$iu-CI&gjFkLo&4N<6 z$rH;+*Jr0vD$&4sr;?bsg_n0NI@7ylcj(xNIBJZWX5h96Cb_X=QmI%c@yuYsBcV`7 z=HO*8$f&2f4(~G2owM5hqfq8z0waYCeRTnEYu2;EfwCDPrlpm@sD$joj31W4gpIYf z^skE_pNXAKhX*ABk$xn`#1o5hiG|tR!%^vc80l89{qQ;5mMip$hn>F=O zT%>#(Htv@vE&!UZLy`Q40(d#aju#w;&=ANJkeO32dd2=XnA(p(v>l3`jq964Qu)&+ z?ohC{B=2Tag2Wv`BKMYa?%wK>efPU-ltckMxz|AwD}~!-!q&c?^=OW}#Qofk3zlED zR@TBl3E?;uVIX^`y=!WBhQ-?nGI7Tnz3r;P^lj;k<*>V z?U@;rk_F=C4jYp;8}wD?RiRbz)g3N)%a;6?Qjt^e)g0RsT1`yF?&8vfNnQlr=LBP8 z4n-k2>Ilf+bFI>A$fq}4^N7XzNHi|MQLq}wWXK9wv;zO&Yqfw4@MmO^kgD)&lmJ+; z*m#14F|RL3TW>#2hkt=0hSYH@EUc^WLbx;(&Z*uQKlot%@V%*X9PGhVuQgx4FVX%Z zY4CM1m_7J2`eqkczYV^Q6fEgpWfMj0wjI(*l7WwGJms0<^oDhn(G`5V=Tm51veWFPK-l6^jT zI)H#u_I553AZHUNO9vPGH#XDTP|?U11QZi}e;7Vl+Jc-FLGCK{wnlbJsvkZfyc3?x zodFzgoi|-EF?$akCQdFM024b47l4h0jT^wq!osBolyxz(u{062Gq(W&SP+1s&L$u` z7XS}0D+2I6-ur-wjg<=lC~o8+1F|%?aQVv+0jTN%vQ-E0yxF`5cwbBi-#J-qJly{WBTFw~!Y%}W6?!KCJ$7VF&c`Pl$(q5(9vS^w*o2zv&`605 zx82(e)cs~V3%%RE?p);{^J{;W_9#)K+!HYtMFk$QUY`+mrH>X{mYtr`{SLuh$Tf^| zeYL7SxKufqSw8Xm!}`gI9JhI%w+CP(8r!gl;Ap?V&UcM@(5DA#R9UJl3IXpqt9Vkt z9h35Kg{!x@NT+%IlE%XTc^c`MgCx`%y#9!1N%6CY+#tR7x*aw+)$7fyfc9gczuSVm zDiBmL%rJ$2`HJU(`}U?qTId7dt4^RZ!#-~Nmf4~M9#L)d`^P%ynxg?Y*hit z14b)~&*wjF+mdHAC>jVEetlQ&i#;2kU~2>*hfw^09}^hvP--V^=zdDefKf6MI+n187Nm7MHNR6#B} zz&Dm4@Ds?xMepC-{?qEO(kL03gMdm#PVZ3Xcy|C)0Xf^dI+=i+0j%#KRDd5qrj|zU zN9a8O7b_cpo0m-wDD7nL>hMN4RDCP6k)5-{y9*Ofpt$PW$#JtZ0jWrf0c8O$Z(ATF z1QdT;;9CS|z&lUzU(d*U$oKRA=I9^GaYp!WYe4wtBHj$%Hi4HDz{A1zURZfcQ)eB( zUn_kdirc%s*WzCb`7hkazha0Ry`6e{^S7+c-;(?*X$0U$2auhpiHoJZozCBU0X4O> z0d}r7Hh+6zdGoDcWM@tbvSU(HrTe#%{uf{IEeY{AX64%zB_Jg!CB?$R$<4yT&GvTF z@V>PiZ|xg+xY>jd-uKAV)dcikdK_=MZ>oRIb4jwWypOrK{{H`F%f4?oUBYN+%zmKG<5$`8xJRt z83GI74d!p2{{8^CI62ul0cL=|$yhnqdEaj7_XlA2ciCH?^$n2!A!B2EtL4ARSUEV^ z{|7ye|E9;z$@+GC{<|$ZC;Qte`41WQ+sgh!#=*k-wqyUU$HC6>pK;&v;P~%)T}t+EryGe(c9(j^bSx}OE1t{semf>_HPLL3&{vTSvxa(0PA05+qZ!PKnEbeDE!6hmx z!Og=hDkUx|Df+hMtP)&2;-V}P;#?A}JW}s~bapXva`|gZSvh#w*bu0wBtJ?a{6Avz B`Q`us literal 0 HcmV?d00001 diff --git a/apache2/t/regression/server_root/htdocs/test.txt b/apache2/t/regression/server_root/htdocs/test.txt new file mode 100644 index 0000000..2a02d41 --- /dev/null +++ b/apache2/t/regression/server_root/htdocs/test.txt @@ -0,0 +1 @@ +TEST diff --git a/apache2/t/regression/server_root/htdocs/test2.txt b/apache2/t/regression/server_root/htdocs/test2.txt new file mode 100644 index 0000000..55d8fa4 --- /dev/null +++ b/apache2/t/regression/server_root/htdocs/test2.txt @@ -0,0 +1 @@ +TEST 2 diff --git a/apache2/t/regression/server_root/logs/audit/.empty b/apache2/t/regression/server_root/logs/audit/.empty new file mode 100644 index 0000000..e69de29 diff --git a/apache2/t/regression/server_root/logs/subdir/.empty b/apache2/t/regression/server_root/logs/subdir/.empty new file mode 100644 index 0000000..e69de29 diff --git a/apache2/t/regression/server_root/tmp/.empty b/apache2/t/regression/server_root/tmp/.empty new file mode 100644 index 0000000..e69de29 diff --git a/apache2/t/regression/server_root/upload/.empty b/apache2/t/regression/server_root/upload/.empty new file mode 100644 index 0000000..e69de29 diff --git a/apache2/t/regression/target/00-targets.t b/apache2/t/regression/target/00-targets.t new file mode 100644 index 0000000..d24f377 --- /dev/null +++ b/apache2/t/regression/target/00-targets.t @@ -0,0 +1,577 @@ +### Test basic targets + +# ARGS +{ + type => "target", + comment => "ARGS (get)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRule ARGS "val1" "phase:2,log,pass" + SecRule ARGS "val2" "phase:2,log,pass" + ), + match_log => { + error => [ qr/Pattern match "val1" at ARGS.*Pattern match "val2" at ARGS/s, 1 ], + debug => [ qr/Adding request argument \(QUERY_STRING\): name "arg1", value "val1".*Adding request argument \(QUERY_STRING\): name "arg2", value "val2"/s, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt?arg1=val1&arg2=val2", + ), +}, +{ + type => "target", + comment => "ARGS (post)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRule ARGS "val1" "phase:2,log,pass" + SecRule ARGS "val2" "phase:2,log,pass" + ), + match_log => { + error => [ qr/Pattern match "val1" at ARGS.*Pattern match "val2" at ARGS/s, 1 ], + debug => [ qr/Adding request argument \(BODY\): name "arg1", value "val1".*Adding request argument \(BODY\): name "arg2", value "val2"/s, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "application/x-www-form-urlencoded", + ], + "arg1=val1&arg2=val2", + ), +}, + +# ARGS_COMBINED_SIZE +{ + type => "target", + comment => "ARGS_COMBINED_SIZE (get)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecRule ARGS_COMBINED_SIZE "\@eq 16" "phase:2,log,pass" + ), + match_log => { + error => [ qr/Operator EQ matched 16 at ARGS_COMBINED_SIZE\./s, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt?arg1=val1&arg2=val2", + ), +}, +{ + type => "target", + comment => "ARGS_COMBINED_SIZE (post)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecRule ARGS_COMBINED_SIZE "\@eq 16" "phase:2,log,pass" + ), + match_log => { + error => [ qr/Operator EQ matched 16 at ARGS_COMBINED_SIZE\./s, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "application/x-www-form-urlencoded", + ], + "arg1=val1&arg2=val2", + ), +}, + +# ARGS_NAMES +{ + type => "target", + comment => "ARGS_NAMES (get)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRule ARGS_NAMES "arg1" "phase:2,log,pass" + SecRule ARGS_NAMES "arg2" "phase:2,log,pass" + ), + match_log => { + error => [ qr/Pattern match "arg1" at ARGS.*Pattern match "arg2" at ARGS/s, 1 ], + debug => [ qr/Adding request argument \(QUERY_STRING\): name "arg1", value "val1".*Adding request argument \(QUERY_STRING\): name "arg2", value "val2"/s, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt?arg1=val1&arg2=val2", + ), +}, +{ + type => "target", + comment => "ARGS_NAMES (post)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRule ARGS_NAMES "arg1" "phase:2,log,pass" + SecRule ARGS_NAMES "arg2" "phase:2,log,pass" + ), + match_log => { + error => [ qr/Pattern match "arg1" at ARGS_NAMES.*Pattern match "arg2" at ARGS_NAMES/s, 1 ], + debug => [ qr/Adding request argument \(BODY\): name "arg1", value "val1".*Adding request argument \(BODY\): name "arg2", value "val2"/s, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "application/x-www-form-urlencoded", + ], + "arg1=val1&arg2=val2", + ), +}, + +# ARGS_GET +{ + type => "target", + comment => "ARGS_GET (get)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRule ARGS_GET "val1" "phase:2,log,pass" + SecRule ARGS_GET "val2" "phase:2,log,pass" + ), + match_log => { + error => [ qr/Pattern match "val1" at ARGS_GET.*Pattern match "val2" at ARGS_GET/s, 1 ], + debug => [ qr/Adding request argument \(QUERY_STRING\): name "arg1", value "val1".*Adding request argument \(QUERY_STRING\): name "arg2", value "val2"/s, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt?arg1=val1&arg2=val2", + ), +}, +{ + type => "target", + comment => "ARGS_GET (post)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRule ARGS_GET "val1" "phase:2,log,pass" + SecRule ARGS_GET "val2" "phase:2,log,pass" + ), + match_log => { + -error => [ qr/Pattern match/, 1 ], + debug => [ qr/Adding request argument \(BODY\): name "arg1", value "val1".*Adding request argument \(BODY\): name "arg2", value "val2"/s, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "application/x-www-form-urlencoded", + ], + "arg1=val1&arg2=val2", + ), +}, + +# ARGS_GET_NAMES +{ + type => "target", + comment => "ARGS_GET_NAMES (get)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRule ARGS_GET_NAMES "arg1" "phase:2,log,pass" + SecRule ARGS_GET_NAMES "arg2" "phase:2,log,pass" + ), + match_log => { + error => [ qr/Pattern match "arg1" at ARGS_GET.*Pattern match "arg2" at ARGS_GET/s, 1 ], + debug => [ qr/Adding request argument \(QUERY_STRING\): name "arg1", value "val1".*Adding request argument \(QUERY_STRING\): name "arg2", value "val2"/s, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt?arg1=val1&arg2=val2", + ), +}, +{ + type => "target", + comment => "ARGS_GET_NAMES (post)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRule ARGS_GET_NAMES "arg1" "phase:2,log,pass" + SecRule ARGS_GET_NAMES "arg2" "phase:2,log,pass" + ), + match_log => { + -error => [ qr/Pattern match/, 1 ], + debug => [ qr/Adding request argument \(BODY\): name "arg1", value "val1".*Adding request argument \(BODY\): name "arg2", value "val2"/s, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "application/x-www-form-urlencoded", + ], + "arg1=val1&arg2=val2", + ), +}, + +# ARGS_POST +{ + type => "target", + comment => "ARGS_POST (get)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRule ARGS_POST "val1" "phase:2,log,pass" + SecRule ARGS_POST "val2" "phase:2,log,pass" + ), + match_log => { + -error => [ qr/Pattern match/, 1 ], + debug => [ qr/Adding request argument \(QUERY_STRING\): name "arg1", value "val1".*Adding request argument \(QUERY_STRING\): name "arg2", value "val2"/s, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt?arg1=val1&arg2=val2", + ), +}, +{ + type => "target", + comment => "ARGS_POST (post)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRule ARGS_POST "val1" "phase:2,log,pass" + SecRule ARGS_POST "val2" "phase:2,log,pass" + ), + match_log => { + error => [ qr/Pattern match "val1" at ARGS_POST.*Pattern match "val2" at ARGS_POST/s, 1 ], + debug => [ qr/Adding request argument \(BODY\): name "arg1", value "val1".*Adding request argument \(BODY\): name "arg2", value "val2"/s, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "application/x-www-form-urlencoded", + ], + "arg1=val1&arg2=val2", + ), +}, + +# ARGS_POST_NAMES +{ + type => "target", + comment => "ARGS_POST_NAMES (get)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRule ARGS_POST_NAMES "arg1" "phase:2,log,pass" + SecRule ARGS_POST_NAMES "arg2" "phase:2,log,pass" + ), + match_log => { + -error => [ qr/Pattern match/, 1 ], + debug => [ qr/Adding request argument \(QUERY_STRING\): name "arg1", value "val1".*Adding request argument \(QUERY_STRING\): name "arg2", value "val2"/s, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt?arg1=val1&arg2=val2", + ), +}, +{ + type => "target", + comment => "ARGS_POST_NAMES (post)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRule ARGS_POST_NAMES "arg1" "phase:2,log,pass" + SecRule ARGS_POST_NAMES "arg2" "phase:2,log,pass" + ), + match_log => { + error => [ qr/Pattern match "arg1" at ARGS_POST.*Pattern match "arg2" at ARGS_POST/s, 1 ], + debug => [ qr/Adding request argument \(BODY\): name "arg1", value "val1".*Adding request argument \(BODY\): name "arg2", value "val2"/s, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "application/x-www-form-urlencoded", + ], + "arg1=val1&arg2=val2", + ), +}, + +# AUTH_TYPE +#{ +# type => "target", +# comment => "AUTH_TYPE", +# conf => qq( +# = 2.2> +# +# LoadModule authn_file_module modules/mod_authn_file.so +# +# +## +## +## LoadModule auth_module modules/mod_auth.so +## +## +# +# AuthType Basic +# AuthName Test +# AuthUserFile "$ENV{CONF_DIR}/htpasswd" +# Require user nobody +# +# SecRuleEngine On +# SecRequestBodyAccess On +# SecResponseBodyAccess On +# SecResponseBodyMimeType null +## SecDebugLog $ENV{DEBUG_LOG} +## SecDebugLogLevel 9 +# SecRule REQUEST_HEADERS:Authorization "Basic (.*)" "phase:2,log,pass,capture,chain" +# SecRule TX:1 "nobody:test" "t:none,t:base64Decode,chain" +# SecRule AUTH_TYPE "Basic" +# ), +# match_log => { +# error => [ qr/Pattern match "Basic" at AUTH_TYPE/s, 1 ], +# }, +# match_response => { +# status => qr/^200$/, +# }, +# request => new HTTP::Request( +# GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", +# [ +# "Authorization" => "Basic bm9ib2R5OnRlc3Q=" +# ], +# ), +#}, + +## ENH: We cannot include this test as we cannot distribute the database. +## Instead we should create a simple test DB of our own. +## GEO +#{ +# type => "target", +# comment => "GEO (ip)", +# conf => qq( +# SecRuleEngine On +# SecDebugLog $ENV{DEBUG_LOG} +# SecDebugLogLevel 9 +# SecGeoLookupDB GeoLiteCity.dat +# SecRule ARGS:ip "\@geoLookup" "phase:2,log,pass,t:none" +# SecRule GEO:COUNTRY_CODE "\@streq US" "phase:2,log,pass,t:none" +# SecRule GEO:COUNTRY_CODE3 "\@streq USA" "phase:2,log,pass,t:none" +# SecRule GEO:COUNTRY_NAME "\@streq United States" "phase:2,log,pass,t:none" +# # ENH: Not in this database? +# SecRule GEO:COUNTRY_CONTINENT "\@streq NA" "phase:2,log,pass,t:none" +# SecRule GEO:REGION "\@streq CA" "phase:2,log,pass,t:none" +# SecRule GEO:CITY "\@streq San Diego" "phase:2,log,pass,t:none" +# SecRule GEO:POSTAL_CODE "\@streq 92123" "phase:2,log,pass,t:none" +# SecRule GEO:LATITUDE "\@beginsWith 32.8" "phase:2,log,pass,t:none" +# SecRule GEO:LONGITUDE "\@beginsWith 117.1" "phase:2,log,pass,t:none" +# SecRule GEO:DMA_CODE "\@streq 825" "phase:2,log,pass,t:none" +# SecRule GEO:AREA_CODE "\@streq 858" "phase:2,log,pass,t:none" +# ), +# match_log => { +# debug => [ qr/Geo lookup for "216.75.21.122" succeeded.*match "US" at GEO:COUNTRY_CODE.*match "USA" at GEO:COUNTRY_CODE3.*match "United States" at GEO:COUNTRY_NAME.*match "NA" at GEO:COUNTRY_CONTINENT.*match "CA" at GEO:REGION.*match "San Diego" at GEO:CITY.*match "92123" at GEO:POSTAL_CODE.*match "32.8" at GEO:LATITUDE.*match "825" at GEO:DMA_CODE.*match "858" at GEO:AREA_CODE/si, 1 ], +# }, +# match_response => { +# status => qr/^200$/, +# }, +# request => new HTTP::Request( +# GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt?ip=216.75.21.122", +# ), +#}, +#{ +# type => "target", +# comment => "GEO (host)", +# conf => qq( +# SecRuleEngine On +# SecDebugLog $ENV{DEBUG_LOG} +# SecDebugLogLevel 9 +# SecGeoLookupDB GeoLiteCity.dat +# SecRule ARGS:host "\@geoLookup" "phase:2,log,pass,t:none" +# SecRule GEO:COUNTRY_CODE "\@streq US" "phase:2,log,pass,t:none" +# SecRule GEO:COUNTRY_CODE3 "\@streq USA" "phase:2,log,pass,t:none" +# SecRule GEO:COUNTRY_NAME "\@streq United States" "phase:2,log,pass,t:none" +# # ENH: Not in this database? +# SecRule GEO:COUNTRY_CONTINENT "\@streq NA" "phase:2,log,pass,t:none" +# SecRule GEO:REGION "\@streq CA" "phase:2,log,pass,t:none" +# SecRule GEO:CITY "\@streq San Diego" "phase:2,log,pass,t:none" +# SecRule GEO:POSTAL_CODE "\@streq 92123" "phase:2,log,pass,t:none" +# SecRule GEO:LATITUDE "\@beginsWith 32.8" "phase:2,log,pass,t:none" +# SecRule GEO:LONGITUDE "\@beginsWith 117.1" "phase:2,log,pass,t:none" +# SecRule GEO:DMA_CODE "\@streq 825" "phase:2,log,pass,t:none" +# SecRule GEO:AREA_CODE "\@streq 858" "phase:2,log,pass,t:none" +# ), +# match_log => { +# debug => [ qr/Using address "\d+\.\d+\.\d+\.\d+".*Geo lookup for "www\.modsecurity\.org" succeeded.*match "US" at GEO:COUNTRY_CODE.*match "USA" at GEO:COUNTRY_CODE3.*match "United States" at GEO:COUNTRY_NAME.*match "NA" at GEO:COUNTRY_CONTINENT.*match "CA" at GEO:REGION.*match "San Diego" at GEO:CITY.*match "92123" at GEO:POSTAL_CODE.*match "32.8" at GEO:LATITUDE.*match "825" at GEO:DMA_CODE.*match "858" at GEO:AREA_CODE/si, 1 ], +# }, +# match_response => { +# status => qr/^200$/, +# }, +# request => new HTTP::Request( +# GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt?host=www.modsecurity.org", +# ), +#}, +#{ +# type => "target", +# comment => "GEO (failed lookup)", +# conf => qq( +# SecRuleEngine On +# SecDebugLog $ENV{DEBUG_LOG} +# SecDebugLogLevel 9 +# SecGeoLookupDB GeoLiteCity.dat +# SecRule ARGS:ip "\@geoLookup" "phase:2,log,pass,t:none" +# SecRule \&GEO "\@eq 0" "phase:2,log,deny,status:403,t:none" +# SecRule ARGS:badip "\@geoLookup" "phase:2,log,pass,t:none" +# SecRule \&GEO "!\@eq 0" "phase:2,log,deny,status:403,t:none" +# ), +# match_log => { +# -debug => [ qr/Geo lookup for "127\.0\.0\.1" succeeded/si, 1 ], +# }, +# match_response => { +# status => qr/^200$/, +# }, +# request => new HTTP::Request( +# GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt?ip=216.75.21.122&badip=127.0.0.1", +# ), +#}, + +# TODO: ENV +# TODO: FILES +# TODO: FILES_COMBINED_SIZE +# TODO: FILES_NAMES +# TODO: FILES_SIZES +# TODO: FILES_TMPNAMES +# TODO: HIGHEST_SEVERITY +# TODO: MATCHED_VAR +# TODO: MATCHED_VAR_NAME +# TODO: MODSEC_BUILD +# TODO: MULTIPART_CRLF_LF_LINES +# TODO: MULTIPART_STRICT_ERROR +# TODO: MULTIPART_UNMATCHED_BOUNDARY +# TODO: PATH_INFO +# TODO: QUERY_STRING +# TODO: REMOTE_ADDR +# TODO: REMOTE_HOST +# TODO: REMOTE_PORT +# TODO: REMOTE_USER +# TODO: REQBODY_PROCESSOR +# TODO: REQBODY_PROCESSOR_ERROR +# TODO: REQBODY_PROCESSOR_ERROR_MSG +# TODO: REQUEST_BASENAME +# TODO: REQUEST_BODY +# TODO: REQUEST_COOKIES +# TODO: REQUEST_COOKIES_NAMES +# TODO: REQUEST_FILENAME +# TODO: REQUEST_HEADERS +# TODO: REQUEST_HEADERS_NAMES +# TODO: REQUEST_LINE +# TODO: REQUEST_METHOD +# TODO: REQUEST_PROTOCOL +# TODO: REQUEST_URI +# TODO: REQUEST_URI_RAW +# TODO: RESPONSE_BODY +# TODO: RESPONSE_CONTENT_LENGTH +# TODO: RESPONSE_CONTENT_TYPE +# TODO: RESPONSE_HEADERS +# TODO: RESPONSE_HEADERS_NAMES +# TODO: RESPONSE_PROTOCOL +# TODO: RESPONSE_STATUS +# TODO: RULE +# TODO: SCRIPT_BASENAME +# TODO: SCRIPT_FILENAME +# TODO: SCRIPT_GID +# TODO: SCRIPT_GROUPNAME +# TODO: SCRIPT_MODE +# TODO: SCRIPT_UID +# TODO: SCRIPT_USERNAME +# TODO: SERVER_ADDR +# TODO: SERVER_NAME +# TODO: SERVER_PORT +# TODO: SESSION +# TODO: SESSIONID +# TODO: TIME +# TODO: TIME_DAY +# TODO: TIME_EPOCH +# TODO: TIME_HOUR +# TODO: TIME_MIN +# TODO: TIME_MON +# TODO: TIME_SEC +# TODO: TIME_WDAY +# TODO: TIME_YEAR +# TODO: TX +# TODO: USERID +# TODO: WEBAPPID +# TODO: WEBSERVER_ERROR_LOG +# TODO: XML + diff --git a/apache2/t/run-regression-tests.pl.in b/apache2/t/run-regression-tests.pl.in new file mode 100755 index 0000000..15614e9 --- /dev/null +++ b/apache2/t/run-regression-tests.pl.in @@ -0,0 +1,779 @@ +#!@PERL@ +# +# Run regression tests. +# +# Syntax: run-regression-tests.pl [options] [file [N]] +# +# All: run-regression-tests.pl +# All in file: run-regression-tests.pl file +# Nth in file: run-regression-tests.pl file N +# +use strict; +use Time::HiRes qw(gettimeofday sleep); +use POSIX qw(WIFEXITED WEXITSTATUS WIFSIGNALED WTERMSIG); +use File::Spec qw(rel2abs); +use File::Basename qw(basename dirname); +use FileHandle; +use IPC::Open2 qw(open2); +use IPC::Open3 qw(open3); +use Getopt::Std; +use Data::Dumper; +use IO::Socket; +use LWP::UserAgent; + +my @TYPES = qw(config misc action target rule); +my $SCRIPT = basename($0); +my $SCRIPT_DIR = File::Spec->rel2abs(dirname($0)); +my $REG_DIR = "$SCRIPT_DIR/regression"; +my $SROOT_DIR = "$REG_DIR/server_root"; +my $DATA_DIR = "$SROOT_DIR/data"; +my $TEMP_DIR = "$SROOT_DIR/tmp"; +my $UPLOAD_DIR = "$SROOT_DIR/upload"; +my $CONF_DIR = "$SROOT_DIR/conf"; +my $MODULES_DIR = q(@APXS_LIBEXECDIR@); +my $FILES_DIR = "$SROOT_DIR/logs"; +my $PID_FILE = "$FILES_DIR/httpd.pid"; +my $HTTPD = q(@APXS_HTTPD@); +my $PASSED = 0; +my $TOTAL = 0; +my $BUFSIZ = 32768; +my %C = (); +my %FILE = (); +my $UA_NAME = "ModSecurity Regression Tests/1.2.3"; +my $UA = LWP::UserAgent->new; +$UA->agent($UA_NAME); + +# Hack for testing the script w/o configure +if ($HTTPD eq "\@APXS_HTTPD\@") { + $HTTPD = "/usr/local/apache2/bin/httpd"; + $MODULES_DIR = "/usr/local/apache2/modules"; +} + +$SIG{TERM} = $SIG{INT} = \&handle_interrupt; + +my %opt; +getopts('A:E:D:C:T:H:a:p:dvh', \%opt); + +if ($opt{d}) { + $Data::Dumper::Indent = 1; + $Data::Dumper::Terse = 1; + $Data::Dumper::Pad = ""; + $Data::Dumper::Quotekeys = 0; +} + +sub usage { + print stderr <<"EOT"; +@_ +Usage: $SCRIPT [options] [file [N]] + + Options: + -A file Specify ModSecurity audit log to read. + -D file Specify ModSecurity debug log to read. + -E file Specify Apache httpd error log to read. + -C file Specify Apache httpd base conf file to generate/reload. + -H path Specify Apache httpd htdocs path. + -S path Specify Apache httpd server root path. + -a file Specify Apache httpd binary (default: httpd) + -p port Specify Apache httpd port (default: 8088) + -v Enable verbose output (details on failure). + -d Enable debugging output. + -h This help. + +EOT + + exit(1); +} + +usage() if ($opt{h}); + +### Check httpd binary +if (defined $opt{a}) { + $HTTPD = $opt{a}; +} +else { + $opt{a} = $HTTPD; +} +usage("Invalid Apache startup script: $HTTPD\n") unless (-e $HTTPD); + +### Defaults +$opt{A} = "$FILES_DIR/modsec_audit.log" unless (defined $opt{A}); +$opt{D} = "$FILES_DIR/modsec_debug.log" unless (defined $opt{D}); +$opt{E} = "$FILES_DIR/error.log" unless (defined $opt{E}); +$opt{C} = "$CONF_DIR/httpd.conf" unless (defined $opt{C}); +$opt{H} = "$SROOT_DIR/htdocs" unless (defined $opt{H}); +$opt{p} = 8088 unless (defined $opt{p}); +$opt{v} = 1 if ($opt{d}); + +unless (defined $opt{S}) { + my $httpd_root = `$HTTPD -V`; + ($opt{S} = $httpd_root) =~ s/.*-D HTTPD_ROOT="([^"]*)".*/$1/sm; +} + +%ENV = ( + %ENV, + SERVER_ROOT => $opt{S}, + SERVER_PORT => $opt{p}, + SERVER_NAME => "localhost", + TEST_SERVER_ROOT => $SROOT_DIR, + DATA_DIR => $DATA_DIR, + TEMP_DIR => $TEMP_DIR, + UPLOAD_DIR => $UPLOAD_DIR, + CONF_DIR => $CONF_DIR, + MODULES_DIR => $MODULES_DIR, + LOGS_DIR => $FILES_DIR, + SCRIPT_DIR => $SCRIPT_DIR, + REGRESSION_DIR => $REG_DIR, + DIST_ROOT => File::Spec->rel2abs(dirname("$SCRIPT_DIR/../../..")), + AUDIT_LOG => $opt{A}, + DEBUG_LOG => $opt{D}, + ERROR_LOG => $opt{E}, + HTTPD_CONF => $opt{C}, + HTDOCS => $opt{H}, + USER_AGENT => $UA_NAME, +); + +#dbg("OPTIONS: ", \%opt); + +if (-e "$PID_FILE") { + msg("Shutting down previous instance: $PID_FILE"); + httpd_stop(); +} + +if (defined $ARGV[0]) { + runfile(dirname($ARGV[0]), basename($ARGV[0]), $ARGV[1]); + done(); +} + +for my $type (@TYPES) { + my $dir = "$SCRIPT_DIR/regression/$type"; + my @cfg = (); + + # Get test names + opendir(DIR, "$dir") or quit(1, "Failed to open \"$dir\": $!"); + @cfg = grep { /\.t$/ && -f "$dir/$_" } readdir(DIR); + closedir(DIR); + + for my $cfg (sort @cfg) { + runfile($dir, $cfg); + } +} +done(); + + +sub runfile { + my($dir, $cfg, $testnum) = @_; + my $fn = "$dir/$cfg"; + my @data = (); + my $edata; + my @C = (); + my @test = (); + my $teststr; + my $n = 0; + my $pass = 0; + + open(CFG, "<$fn") or quit(1, "Failed to open \"$fn\": $!"); + @data = ; + + $edata = q/@C = (/ . join("", @data) . q/)/; + eval $edata; + quit(1, "Failed to read test data \"$cfg\": $@") if ($@); + + unless (@C) { + msg("\nNo tests defined for $fn"); + return; + } + + msg("\nLoaded ".@C." tests from $fn"); + for my $t (@C) { + $n++; + next if (defined $testnum and $n != $testnum); + + my $httpd_up = 0; + my %t = %{$t || {}}; + my $id = sprintf("%3d", $n); + my $out = ""; + my $rc = 0; + my $conf_fn; + + # Startup httpd with optionally included conf. + if (exists $t{conf} and defined $t{conf}) { + $conf_fn = sprintf "%s/%s_%s_%06d.conf", + $CONF_DIR, $t{type}, $cfg, $n; + #dbg("Writing test config to: $conf_fn"); + open(CONF, ">$conf_fn") or die "Failed to open conf \"$conf_fn\": $!\n"; + print CONF (ref $t{conf} eq "CODE" ? eval { &{$t{conf}} } : $t{conf}); + msg("$@") if ($@); + close CONF; + $httpd_up = httpd_start(\%t, "Include $conf_fn") ? 0 : 1; + } + else { + $httpd_up = httpd_start(\%t) ? 0 : 1; + } + + # Run any prerun setup + if ($rc == 0 and exists $t{prerun} and defined $t{prerun}) { + vrb("Executing perl prerun..."); + $rc = &{$t{prerun}}; + vrb("Perl prerun returned: $rc"); + } + + if ($httpd_up) { + # Perform the request and check response + if (exists $t{request}) { + my $resp = do_request($t{request}); + if (!$resp) { + msg("invalid response"); + vrb("RESPONSE: ", $resp); + $rc = 1; + } + else { + for my $key (keys %{ $t{match_response} || {}}) { + my($neg,$mtype) = ($key =~ m/^(-?)(.*)$/); + my $m = $t{match_response}{$key}; + my $match = match_response($mtype, $resp, $m); + if ($neg and defined $match) { + $rc = 1; + msg("response $mtype matched: $m"); + vrb($resp); + last; + } + elsif (!$neg and !defined $match) { + $rc = 1; + msg("response $mtype failed to match: $m"); + vrb($resp); + last; + } + } + } + } + + # Run any arbitrary perl tests + if ($rc == 0 and exists $t{test} and defined $t{test}) { + dbg("Executing perl test(s)..."); + $rc = eval { &{$t{test}} }; + if (! defined $rc) { + msg("Error running test: $@"); + $rc = -1; + } + dbg("Perl tests returned: $rc"); + } + + # Search for all log matches + if ($rc == 0 and exists $t{match_log} and defined $t{match_log}) { + for my $key (keys %{ $t{match_log} || {}}) { + my($neg,$mtype) = ($key =~ m/^(-?)(.*)$/); + my $m = $t{match_log}{$key}; + my $match = match_log($mtype, @{$m || []}); + if ($neg and defined $match) { + $rc = 1; + msg("$mtype log matched: $m->[0]"); + last; + } + elsif (!$neg and !defined $match) { + $rc = 1; + msg("$mtype log failed to match: $m->[0]"); + last; + } + } + } + + # Search for all file matches + if ($rc == 0 and exists $t{match_file} and defined $t{match_file}) { + sleep 1; # Make sure the file exists + for my $key (keys %{ $t{match_file} || {}}) { + my($neg,$fn) = ($key =~ m/^(-?)(.*)$/); + my $m = $t{match_file}{$key}; + my $match = match_file($fn, $m); + if ($neg and defined $match) { + $rc = 1; + msg("$fn file matched: $m"); + last; + } + elsif (!$neg and !defined $match) { + $rc = 1; + msg("$fn file failed match: $m"); + last; + } + } + } + } + else { + msg("Failed to start httpd."); + $rc = 1; + } + + if ($rc == 0) { + $pass++; + } + else { + vrb("Test Config: $conf_fn"); + vrb("Debug Log: $FILE{debug}{fn}"); + dbg(escape("$FILE{debug}{buf}")); + vrb("Error Log: $FILE{error}{fn}"); + dbg(escape("$FILE{error}{buf}")); + } + + msg(sprintf("%s) %s%s: %s%s", $id, $t{type}, (exists($t{comment}) ? " - $t{comment}" : ""), ($rc ? "failed" : "passed"), ((defined($out) && $out ne "")? " ($out)" : ""))); + + if ($httpd_up) { + $httpd_up = httpd_stop(\%t) ? 0 : 1; + } + + } + + $TOTAL += $testnum ? 1 : $n; + $PASSED += $pass; + + msg(sprintf("Passed: %2d; Failed: %2d", $pass, $testnum ? (1 - $pass) : ($n - $pass))); +} + +# Take out any indenting and translate LF -> CRLF +sub normalize_raw_request_data { + my $r = $_[0]; + + # Allow for indenting in test file + $r =~ s/^[ \t]*\x0d?\x0a//s; + my($indention) = ($r =~ m/^([ \t]*)/s); # indention taken from first line + $r =~ s/^$indention//mg; + $r =~ s/(\x0d?\x0a)[ \t]+$/$1/s; + + # Translate LF to CRLF + $r =~ s/^\x0a/\x0d\x0a/mg; + $r =~ s/([^\x0d])\x0a/$1\x0d\x0a/mg; + + return $r; +} + +sub do_raw_request { + my $sock = new IO::Socket::INET( + Proto => "tcp", + PeerAddr => "localhost", + PeerPort => $opt{p}, + ) or msg("Failed to connect to localhost:$opt{p}: $@"); + return unless ($sock); + + # Join togeather the request + my $r = join("", @_); + dbg($r); + + # Write to socket + print $sock "$r"; + $sock->shutdown(1); + + # Read from socket + my @resp = <$sock>; + $sock->close(); + + return HTTP::Response->parse(join("", @resp)); +} + +sub do_request { + my $r = $_[0]; + + # Allow test to execute code + if (ref $r eq "CODE") { + $r = eval { &$r }; + msg("$@") unless (defined $r); + } + + if (ref $r eq "HTTP::Request") { + my $resp = $UA->request($r); + dbg($resp->request()->as_string()) if ($opt{d}); + return $resp + } + else { + return do_raw_request($r); + } + + return; +} + + +sub match_response { + my($name, $resp, $re) = @_; + + msg("Warning: Empty regular expression.") if (!defined $re or $re eq ""); + + if ($name eq "status") { + return $& if ($resp->code =~ m/$re/); + } + elsif ($name eq "content") { + return $& if ($resp->content =~ m/$re/m); + } + elsif ($name eq "raw") { + return $& if ($resp->as_string =~ m/$re/m); + } + + return; +} + +sub read_log { + my($name, $timeout, $graph) = @_; + return match_log($name, undef, $timeout, $graph); +} + +sub match_log { + my($name, $re, $timeout, $graph) = @_; + my $t0 = gettimeofday; + my($fh,$rbuf) = ($FILE{$name}{fd}, \$FILE{$name}{buf}); + my $n = length($$rbuf); + my $rc = undef; + + unless (defined $fh) { + msg("Error: File \"$name\" is not opened for matching."); + return; + } + + $timeout = 0 unless (defined $timeout); + + my $i = 0; + my $graphed = 0; + READ: { + do { + my $nbytes = $fh->sysread($$rbuf, $BUFSIZ, $n); + if (!defined($nbytes)) { + msg("Error: Could not read \"$name\" log: $!"); + last; + } + elsif (!defined($re) and $nbytes == 0) { + last; + } + + # Remove APR pool debugging + $$rbuf =~ s/POOL DEBUG:[^\n]+PALLOC[^\n]+\n//sg; + + $n = length($$rbuf); + + #dbg("Match \"$re\" in $name \"$$rbuf\" ($n)"); + if ($$rbuf =~ m/$re/m) { + $rc = $&; + last; + } + # TODO: Use select()/poll() + sleep 0.1 unless ($nbytes == $BUFSIZ); + if ($graph and $opt{d}) { + $i++; + if ($i == 10) { + $graphed++; + $i=0; + print STDERR $graph if ($graphed == 1); + print STDERR "." + } + } + } while (gettimeofday - $t0 < $timeout); + } + print STDERR "\n" if ($graphed); + + return $rc; +} + +sub match_file { + my($neg,$fn) = ($_[0] =~ m/^(-?)(.*)$/); + unless (exists $FILE{$fn}) { + eval { + $FILE{$fn}{fn} = $fn; + $FILE{$fn}{fd} = new FileHandle($fn, O_RDONLY) or die "$!\n"; + $FILE{$fn}{fd}->blocking(0); + $FILE{$fn}{buf} = ""; + }; + if ($@) { + msg("Warning: Failed to open file \"$fn\": $@"); + return; + } + } + return match_log($_[0], $_[1]); # timeout makes no sense +} + +sub quote_shell { + my($s) = @_; + return $s unless ($s =~ m|[^\w!%+,\-./:@^]|); + $s =~ s/(['\\])/\\$1/g; + return "'$s'"; +} + +sub escape { + my @new = (); + for my $c (split(//, $_[0])) { + my $oc = ord($c); + push @new, ((($oc >= 0x20 and $oc <= 0x7e) or $oc == 0x0a or $oc == 0x0d) ? $c : sprintf("\\x%02x", ord($c))); + } + join('', @new); +} + +sub dbg { + return unless(@_ and $opt{d}); + my $out = join "", map { + (ref $_ ne "" ? Dumper($_) : $_) + } @_; + $out =~ s/^/DBG: /mg; + print STDOUT "$out\n"; +} + +sub vrb { + return unless(@_ and $opt{v}); + msg(@_); +} + +sub msg { + return unless(@_); + my $out = join "", map { + (ref $_ ne "" ? Dumper($_) : $_) + } @_; + print STDOUT "$out\n"; +} + +sub handle_interrupt { + $SIG{TERM} = $SIG{INT} = \&handle_interrupt; + + msg("Interrupted via SIG$_[0]. Shutting down tests..."); + httpd_stop(); + + quit(1); +} + +sub quit { + my($ec,$msg) = @_; + $ec = 0 unless (defined $_[0]); + + msg("$msg") if (defined $msg); + + exit $ec; +} + +sub done { + if ($PASSED != $TOTAL) { + quit(1, "\n$PASSED/$TOTAL tests passed."); + } + + quit(0, "\nAll tests passed ($TOTAL)."); +} + +sub httpd_start { + my $t = shift; + httpd_reset_fd($t); + my @p = ( + $HTTPD, + -d => $opt{S}, + -f => $opt{C}, + (map { (-c => $_) } ("Listen localhost:$opt{p}", @_)), + -k => "start", + ); + + my $httpd_out; + my $httpd_pid = open3(undef, $httpd_out, undef, @p) or quit(1); + my $out = join("\\n", grep(!/POOL DEBUG/, (<$httpd_out>))); + close $httpd_out; + waitpid($httpd_pid, 0); + + my $rc = $?; + if ( WIFEXITED($rc) ) { + $rc = WEXITSTATUS($rc); + vrb("Httpd start returned with $rc.") if ($rc); + } + elsif( WIFSIGNALED($rc) ) { + msg("Httpd start failed with signal " . WTERMSIG($rc) . "."); + $rc = -1; + } + else { + msg("Httpd start failed with unknown error."); + $rc = -1; + } + + if (defined $out and $out ne "") { + vrb(join(" ", map { quote_shell($_) } @p)); + msg("Httpd start failed with error messages:\n$out"); + return -1 + } + + # Look for startup msg + unless (defined match_log("error", qr/resuming normal operations/, 60, "Waiting on httpd to start: ")) { + vrb(join(" ", map { quote_shell($_) } @p)); + vrb(match_log("error", qr/(^.*ModSecurity: .*)/sm, 10)); + msg("Httpd server failed to start."); + return -1; + } + + return $rc; +} + +sub httpd_stop { + my $t = shift; + my @p = ( + $HTTPD, + -d => $opt{S}, + -f => $opt{C}, + (map { (-c => $_) } ("Listen localhost:$opt{p}", @_)), + -k => "stop", + ); + + my $httpd_out; + my $httpd_pid = open3(undef, $httpd_out, undef, @p) or quit(1); + my $out = join("\\n", grep(!/POOL DEBUG/, (<$httpd_out>))); + close $httpd_out; + waitpid($httpd_pid, 0); + + if (defined $out and $out ne "") { + msg("Httpd stop failed with error messages:\n$out"); + return -1 + } + + my $rc = $?; + if ( WIFEXITED($rc) ) { + $rc = WEXITSTATUS($rc); + vrb("Httpd stop returned with $rc.") if ($rc); + } + elsif( WIFSIGNALED($rc) ) { + msg("Httpd stop failed with signal " . WTERMSIG($rc) . "."); + $rc = -1; + } + else { + msg("Httpd stop failed with unknown error."); + $rc = -1; + } + + # Look for startup msg + unless (defined match_log("error", qr/caught SIG[A-Z]+, shutting down/, 60, "Waiting on httpd to stop: ")) { + vrb(join(" ", map { quote_shell($_) } @p)); + msg("Httpd server failed to shutdown."); + sleep 0.5; + return -1; + } + + sleep 0.5; + + return $rc; +} + +sub httpd_reload { + my $t = shift; + httpd_reset_fd($t); + my @p = ( + $HTTPD, + -d => $opt{S}, + -f => $opt{C}, + (map { (-c => $_) } ("Listen localhost:$opt{p}", @_)), + -k => "graceful", + ); + + my $httpd_out; + my $httpd_pid = open3(undef, $httpd_out, undef, @p) or quit(1); + my $out = join("\\n", grep(!/POOL DEBUG/, (<$httpd_out>))); + close $httpd_out; + waitpid($httpd_pid, 0); + + if (defined $out and $out ne "") { + msg("Httpd reload failed with error messages:\n$out"); + return -1 + } + + my $rc = $?; + if ( WIFEXITED($rc) ) { + $rc = WEXITSTATUS($rc); + vrb("Httpd reload returned with $rc.") if ($rc); + } + elsif( WIFSIGNALED($rc) ) { + msg("Httpd reload failed with signal " . WTERMSIG($rc) . "."); + $rc = -1; + } + else { + msg("Httpd reload failed with unknown error."); + $rc = -1; + } + + # Look for startup msg + unless (defined match_log("error", qr/resuming normal operations/, 60, "Waiting on httpd to restart: ")) { + vrb(join(" ", map { quote_shell($_) } @p)); + msg("Httpd server failed to reload."); + return -1; + } + + return $rc; +} + +sub httpd_reset_fd { + my($t) = @_; + + # Cleanup + for my $key (keys %FILE) { + if (exists $FILE{$key}{fd} and defined $FILE{$key}{fd}) { + $FILE{$key}{fd}->close(); + } + delete $FILE{$key}; + } + + # Error + eval { + $FILE{error}{fn} = $opt{E}; + $FILE{error}{fd} = new FileHandle($opt{E}, O_RDWR|O_CREAT) or die "$!\n"; + $FILE{error}{fd}->blocking(0); + $FILE{error}{fd}->sysseek(0, 2); + $FILE{error}{buf} = ""; + }; + if ($@) { + msg("Warning: Failed to open file \"$opt{E}\": $@"); + return undef; + } + + # Audit + eval { + $FILE{audit}{fn} = $opt{A}; + $FILE{audit}{fd} = new FileHandle($opt{A}, O_RDWR|O_CREAT) or die "$!\n"; + $FILE{audit}{fd}->blocking(0); + $FILE{audit}{fd}->sysseek(0, 2); + $FILE{audit}{buf} = ""; + }; + if ($@) { + msg("Warning: Failed to open file \"$opt{A}\": $@"); + return undef; + } + + # Debug + eval { + $FILE{debug}{fn} = $opt{D}; + $FILE{debug}{fd} = new FileHandle($opt{D}, O_RDWR|O_CREAT) or die "$!\n"; + $FILE{debug}{fd}->blocking(0); + $FILE{debug}{fd}->sysseek(0, 2); + $FILE{debug}{buf} = ""; + }; + if ($@) { + msg("Warning: Failed to open file \"$opt{D}\": $@"); + return undef; + } + + # Any extras listed in "match_log" + if ($t and exists $t->{match_log}) { + for my $k (keys %{ $t->{match_log} || {} }) { + my($neg,$fn) = ($k =~ m/^(-?)(.*)$/); + next if (!$fn or exists $FILE{$fn}); + eval { + $FILE{$fn}{fn} = $fn; + $FILE{$fn}{fd} = new FileHandle($fn, O_RDWR|O_CREAT) or die "$!\n"; + $FILE{$fn}{fd}->blocking(0); + $FILE{$fn}{fd}->sysseek(0, 2); + $FILE{$fn}{buf} = ""; + }; + if ($@) { + msg("Warning: Failed to open file \"$fn\": $@"); + return undef; + } + } + } +} + +sub encode_chunked { + my($data, $size) = @_; + $size = 128 unless ($size); + my $chunked = ""; + + my $n = 0; + my $bytes = length($data); + while ($bytes >= $size) { + $chunked .= sprintf "%x\x0d\x0a%s\x0d\x0a", $size, substr($data, $n, $size); + $n += $size; + $bytes -= $size; + } + if ($bytes) { + $chunked .= sprintf "%x\x0d\x0a%s\x0d\x0a", $bytes, substr($data, $n, $bytes); + } + $chunked .= "0\x0d\x0a\x0d\x0a" +} diff --git a/apache2/t/run-unit-tests.pl.in b/apache2/t/run-unit-tests.pl.in new file mode 100755 index 0000000..66212c1 --- /dev/null +++ b/apache2/t/run-unit-tests.pl.in @@ -0,0 +1,161 @@ +#!@PERL@ +# +# Run unit tests. +# +# Syntax: +# All: run-tests.pl +# All in file: run-tests.pl file +# Nth in file: run-tests.pl file N +# +use strict; +use POSIX qw(WIFEXITED WEXITSTATUS WIFSIGNALED WTERMSIG); +use File::Basename qw(basename dirname); +use FileHandle; +use IPC::Open2 qw(open2); + +my @TYPES = qw(tfn op action); +my $TEST = "./msc_test"; +my $SCRIPT = basename($0); +my $SCRIPTDIR = dirname($0); +my $PASSED = 0; +my $TOTAL = 0; +my $DEBUG = $ENV{MSC_TEST_DEBUG} || 0; + +if (defined $ARGV[0]) { + runfile(dirname($ARGV[0]), basename($ARGV[0]), $ARGV[1]); + done(); +} + +for my $type (sort @TYPES) { + my $dir = "$SCRIPTDIR/$type"; + my @cfg = (); + + # Get test names + opendir(DIR, "$dir") or quit(1, "Failed to open \"$dir\": $!"); + @cfg = grep { /\.t$/ && -f "$dir/$_" } readdir(DIR); + closedir(DIR); + + for my $cfg (sort @cfg) { + runfile($dir, $cfg); + } + +} +done(); + + +sub runfile { + my($dir, $cfg, $testnum) = @_; + my $fn = "$dir/$cfg"; + my @data = (); + my $edata; + my @C = (); + my @test = (); + my $teststr; + my $n = 0; + my $pass = 0; + + open(CFG, "<$fn") or quit(1, "Failed to open \"$fn\": $!"); + @data = ; + + $edata = q/@C = (/ . join("", @data) . q/)/; + eval $edata; + quit(1, "Failed to read test data \"$cfg\": $@") if ($@); + + unless (@C) { + msg("\nNo tests defined for $fn"); + return; + } + + msg("\nLoaded ".@C." tests from $fn"); + for my $t (@C) { + $n++; + next if (defined $testnum and $n != $testnum); + + my %t = %{$t || {}}; + my $id = sprintf("%6d", $n); + my $in = (exists($t{input}) and defined($t{input})) ? $t{input} : ""; + my $out; + my $test_in = new FileHandle(); + my $test_out = new FileHandle(); + my $test_pid; + my $rc = 0; + my $param; + + if ($t{type} eq "tfn") { + $param = escape($t{output}); + } + elsif ($t{type} eq "op") { + $param = escape($t{param}); + } + elsif ($t{type} eq "action") { + $param = escape($t{param}); + } + else { + quit(1, "Unknown type \"$t{type}\" - should be one of: " . join(",",@TYPES)); + } + + @test = ("-t", $t{type}, "-n", $t{name}, "-p", $param, "-D", "$DEBUG", (exists($t{ret}) ? ("-r", $t{ret}) : ()), (exists($t{iterations}) ? ("-I", $t{iterations}) : ()), (exists($t{prerun}) ? ("-P", $t{prerun}) : ())); + $teststr = "$TEST " . join(" ", map { "\"$_\"" } @test); + $test_pid = open2($test_out, $test_in, $TEST, @test) or quit(1, "Failed to execute test: $teststr\": $!"); + print $test_in "$in"; + close $test_in; + $out = join("\\n", split(/\n/, <$test_out>)); + close $test_out; + waitpid($test_pid, 0); + + $rc = $?; + if ( WIFEXITED($rc) ) { + $rc = WEXITSTATUS($rc); + } + elsif( WIFSIGNALED($rc) ) { + msg("Test exited with signal " . WTERMSIG($rc) . "."); + msg("Executed: $teststr"); + $rc = -1; + } + else { + msg("Test exited with unknown error."); + $rc = -1; + } + + if ($rc == 0) { + $pass++; + } + + msg(sprintf("%s) %s \"%s\"%s: %s%s", $id, $t{type}, $t{name}, (exists($t{comment}) ? " $t{comment}" : ""), ($rc ? "failed" : "passed"), ((defined($out) && $out ne "")? " ($out)" : ""))); + + } + + $TOTAL += $testnum ? 1 : $n; + $PASSED += $pass; + + msg(sprintf("Passed: %2d; Failed: %2d", $pass, $testnum ? (1 - $pass) : ($n - $pass))); +} + +sub escape { + my @new = (); + for my $c (split(//, $_[0])) { + push @new, ((ord($c) >= 0x20 and ord($c) <= 0x7e) ? $c : sprintf("\\x%02x", ord($c))); + } + join('', @new); +} + +sub msg { + print STDOUT "@_\n" if (@_); +} + +sub quit { + my($ec,$msg) = @_; + $ec = 0 unless (defined $_[0]); + + msg("$msg") if (defined $msg); + + exit $ec; +} + +sub done { + if ($PASSED != $TOTAL) { + quit(1, "\n$PASSED/$TOTAL tests passed."); + } + + quit(0, "\nAll tests passed ($TOTAL)."); +} diff --git a/apache2/t/tfn/base64Decode.t b/apache2/t/tfn/base64Decode.t new file mode 100644 index 0000000..59d8802 --- /dev/null +++ b/apache2/t/tfn/base64Decode.t @@ -0,0 +1,51 @@ +### Empty +{ + type => "tfn", + name => "base64Decode", + input => "", + output => "", + ret => 0, +}, + +### Test values with varying lengths to check padding +{ + type => "tfn", + name => "base64Decode", + input => "VGVzdENhc2U=", + output => "TestCase", + ret => 1, +}, +{ + type => "tfn", + name => "base64Decode", + input => "VGVzdENhc2Ux", + output => "TestCase1", + ret => 1, +}, +{ + type => "tfn", + name => "base64Decode", + input => "VGVzdENhc2UxMg==", + output => "TestCase12", + ret => 1, +}, + + +### Check with a NUL +{ + type => "tfn", + name => "base64Decode", + input => "VGVzdABDYXNl", + output => "Test\0Case", + ret => 1, +}, + +### Invalid +# What should happen here? Probably just fail and leave alone. +{ + type => "tfn", + name => "base64Decode", + input => "VGVzdENhc2U=\0VGVzdENhc2U=", + output => "TestCase", + ret => 1, +}, diff --git a/apache2/t/tfn/base64Encode.t b/apache2/t/tfn/base64Encode.t new file mode 100644 index 0000000..a5a6f83 --- /dev/null +++ b/apache2/t/tfn/base64Encode.t @@ -0,0 +1,40 @@ +### Empty +{ + type => "tfn", + name => "base64Encode", + input => "", + output => "", + ret => 0, +}, + +### Test values with varying lengths to check padding +{ + type => "tfn", + name => "base64Encode", + input => "TestCase", + output => "VGVzdENhc2U=", + ret => 1, +}, +{ + type => "tfn", + name => "base64Encode", + input => "TestCase1", + output => "VGVzdENhc2Ux", + ret => 1, +}, +{ + type => "tfn", + name => "base64Encode", + input => "TestCase12", + output => "VGVzdENhc2UxMg==", + ret => 1, +}, + +### Check with a NUL +{ + type => "tfn", + name => "base64Encode", + input => "Test\0Case", + output => "VGVzdABDYXNl", + ret => 1, +}, diff --git a/apache2/t/tfn/compressWhitespace.t b/apache2/t/tfn/compressWhitespace.t new file mode 100644 index 0000000..fe6179e --- /dev/null +++ b/apache2/t/tfn/compressWhitespace.t @@ -0,0 +1,50 @@ +### Empty +{ + type => "tfn", + name => "compressWhitespace", + input => "", + output => "", + ret => 0, +}, + +### Nothing +{ + type => "tfn", + name => "compressWhitespace", + input => "TestCase", + output => "TestCase", + ret => 0, +}, +{ + type => "tfn", + name => "compressWhitespace", + input => "Test\0Case", + output => "Test\0Case", + ret => 0, +}, +{ + type => "tfn", + name => "compressWhitespace", + input => "Test Case", + output => "Test Case", + ret => 0, +}, + + +### Compress space/tab +{ + type => "tfn", + name => "compressWhitespace", + input => " Test \t Case ", + output => " Test Case ", + ret => 1, +}, + +### Pretty much everything in one +{ + type => "tfn", + name => "compressWhitespace", + input => "This is a test case with a tab \t, vtab \x0b, newline \x0a, return \x0d, formfeed \f, and a NUL\0 in it with a CRLF at the end.\x0d\x0a", + output => "This is a test case with a tab , vtab , newline , return , formfeed , and a NUL\0 in it with a CRLF at the end. ", + ret => 1, +}, diff --git a/apache2/t/tfn/cssDecode.t b/apache2/t/tfn/cssDecode.t new file mode 100644 index 0000000..180186b --- /dev/null +++ b/apache2/t/tfn/cssDecode.t @@ -0,0 +1,58 @@ +### Empty +{ + type => "tfn", + name => "cssDecode", + input => "", + output => "", + ret => 0, +}, + +### Nothing +{ + type => "tfn", + name => "cssDecode", + input => "TestCase", + output => "TestCase", + ret => 0, +}, +{ + type => "tfn", + name => "cssDecode", + input => "Test\0Case", + output => "Test\0Case", + ret => 0, +}, + +### Valid Sequences +{ + type => "tfn", + name => "cssDecode", + input => "test\\a\\b\\f\\n\\r\\t\\v\\?\\'\\\"\\0\\12\\123\\1234\\12345\\123456\\ff01\\ff5e\\\n\\0 string", + output => qq(test\x0a\x0b\x0fnrtv?'"\x00\x12\x23\x34\x45\x56\x21\x7e\x00 string), + ret => 1, +}, + +### Invalid Sequences +# Trailing escape == line continuation with no line following (ie nothing) +{ + type => "tfn", + name => "cssDecode", + input => "test\\", + output => "test", + ret => 1, +}, + +# Edge cases +# "\1A" == "\x1A" +# "\1 A" == "\x01A" +# "\1234567" == "\x567" +# "\123456 7" == "\x567" +# "\1x" == "\x01x" +# "\1 x" == "\x01 x" +{ + type => "tfn", + name => "cssDecode", + input => "\\1A\\1 A\\1234567\\123456 7\\1x\\1 x", + output => "\x1A\x01A\x567\x567\x01x\x01x", + ret => 1, +}, diff --git a/apache2/t/tfn/escapeSeqDecode.t b/apache2/t/tfn/escapeSeqDecode.t new file mode 100644 index 0000000..7f362e9 --- /dev/null +++ b/apache2/t/tfn/escapeSeqDecode.t @@ -0,0 +1,114 @@ +### Empty +{ + type => "tfn", + name => "escapeSeqDecode", + input => "", + output => "", + ret => 0, +}, + +### Nothing +{ + type => "tfn", + name => "escapeSeqDecode", + input => "TestCase", + output => "TestCase", + ret => 0, +}, +{ + type => "tfn", + name => "escapeSeqDecode", + input => "Test\0Case", + output => "Test\0Case", + ret => 0, +}, + +### Valid Sequences +{ + type => "tfn", + name => "escapeSeqDecode", + input => "\\a\\b\\f\\n\\r\\t\\v\\?\\'\\\"\\0\\12\\123\\x00\\xff", + output => "\a\b\f\x0a\x0d\t\x0b?'\"\x00\x0a\x53\x00\xff", + ret => 1, +}, +{ + type => "tfn", + name => "escapeSeqDecode", + input => "\\a\\b\\f\\n\\r\\t\\v\0\\?\\'\\\"\\0\\12\\123\\x00\\xff", + output => "\a\b\f\x0a\x0d\t\x0b\0?'\"\x00\x0a\x53\x00\xff", + ret => 1, +}, + +### Invalid Sequences +# \8 and \9 are not octal +# \666 is a byte overflow (0x1b6) and should be truncated to a byte as 0xb6 +# \xag and \xga are not hex, +# \0123 is \012 + '3' +{ + type => "tfn", + name => "escapeSeqDecode", + input => "\\8\\9\\666\\xag\\xga\\0123", + output => "89\xb6xagxga\x0a3", + ret => 1, +}, + +# \x, \x0 lack enough hex digits +{ + type => "tfn", + name => "escapeSeqDecode", + input => "\\x", + output => "x", + ret => 1, +}, +{ + type => "tfn", + name => "escapeSeqDecode", + input => "\\x\\x0", + output => "xx0", + ret => 1, +}, +{ + type => "tfn", + name => "escapeSeqDecode", + input => "\\x\\x0\0", + output => "xx0\0", + ret => 1, +}, +# Octal at end +{ + type => "tfn", + name => "escapeSeqDecode", + input => "\\0", + output => "\x00", + ret => 1, +}, +{ + type => "tfn", + name => "escapeSeqDecode", + input => "\\01", + output => "\x01", + ret => 1, +}, +{ + type => "tfn", + name => "escapeSeqDecode", + input => "\\012", + output => "\x0a", + ret => 1, +}, +# A forward slash with nothing after +{ + type => "tfn", + name => "escapeSeqDecode", + input => "\\", + output => "\\", + ret => 0, +}, +# A forward slash with NUL after +{ + type => "tfn", + name => "escapeSeqDecode", + input => "\\\0", + output => "\0", + ret => 1, +}, diff --git a/apache2/t/tfn/hexDecode.t b/apache2/t/tfn/hexDecode.t new file mode 100644 index 0000000..ac6b423 --- /dev/null +++ b/apache2/t/tfn/hexDecode.t @@ -0,0 +1,50 @@ +### Empty +{ + type => "tfn", + name => "hexDecode", + input => "", + output => "", + ret => 1, +}, + +### Basic +{ + type => "tfn", + name => "hexDecode", + input => "5465737443617365", + output => "TestCase", + ret => 1, +}, + +### Basic w/NULL +{ + type => "tfn", + name => "hexDecode", + input => "546573740043617365", + output => "Test\0Case", + ret => 1, +}, + +### Invalid +# What should happen here? Probably just fail and leave alone. +{ + type => "tfn", + name => "hexDecode", + input => "01234567890a0z01234567890a", + output => "\x01#Eg\x89\x0a#\x01#Eg\x89\x0a", + ret => 1, +}, +{ + type => "tfn", + name => "hexDecode", + input => "01234567890az", + output => "\x01#Eg\x89\x0a", + ret => 1, +}, +{ + type => "tfn", + name => "hexDecode", + input => "01234567890a0", + output => "\x01#Eg\x89\x0a", + ret => 1, +}, diff --git a/apache2/t/tfn/hexEncode.t b/apache2/t/tfn/hexEncode.t new file mode 100644 index 0000000..16dc43d --- /dev/null +++ b/apache2/t/tfn/hexEncode.t @@ -0,0 +1,26 @@ +### Empty +{ + type => "tfn", + name => "hexEncode", + input => "", + output => "", + ret => 1, +}, + +### Basic +{ + type => "tfn", + name => "hexEncode", + input => "TestCase", + output => "5465737443617365", + ret => 1, +}, + +### Basic w/NULL +{ + type => "tfn", + name => "hexEncode", + input => "Test\0Case", + output => "546573740043617365", + ret => 1, +}, diff --git a/apache2/t/tfn/htmlEntityDecode.t b/apache2/t/tfn/htmlEntityDecode.t new file mode 100644 index 0000000..201bd6b --- /dev/null +++ b/apache2/t/tfn/htmlEntityDecode.t @@ -0,0 +1,58 @@ +### Empty +{ + type => "tfn", + name => "htmlEntityDecode", + input => "", + output => "", + ret => 0, +}, + +### Nothing +{ + type => "tfn", + name => "htmlEntityDecode", + input => "TestCase", + output => "TestCase", + ret => 0, +}, +{ + type => "tfn", + name => "htmlEntityDecode", + input => "Test\0Case", + output => "Test\0Case", + ret => 0, +}, + +### Valid +# With ; +{ + type => "tfn", + name => "htmlEntityDecode", + input => "�� � \0d"&<> ", + output => "\0\0\x20\x20\0\x20\0\x64\"&<>\xa0", + ret => 1, +}, +# Without ; +{ + type => "tfn", + name => "htmlEntityDecode", + input => "�� � \0d"&<> ", + output => "\0\0\x20\x20\0\x20\0\x64\"&<>\xa0", + ret => 1, +}, + +### Invalid +{ + type => "tfn", + name => "htmlEntityDecode", + input => "&#xg;&#Xg;&#xg0;g;&#a;\0&#a2;a&#a00;a0; a;&foo;", + output => "&#xg;&#Xg;&#xg0;\x02g;&#a;\0&#a2;\x03a&#a00;\x01a0;\x0aa;&foo;", + ret => 1, +}, +{ + type => "tfn", + name => "htmlEntityDecode", + input => "&#xg&#Xg&#xg0g&#a\0&#a2a&#a00a0 a&foo", + output => "&#xg&#Xg&#xg0\x02g&#a\0&#a2\x03a&#a00\x01a0\x0aa&foo", + ret => 1, +}, diff --git a/apache2/t/tfn/jsDecode.t b/apache2/t/tfn/jsDecode.t new file mode 100644 index 0000000..9774b7f --- /dev/null +++ b/apache2/t/tfn/jsDecode.t @@ -0,0 +1,129 @@ +### Empty +{ + type => "tfn", + name => "jsDecode", + input => "", + output => "", + ret => 0, +}, + +### Nothing +{ + type => "tfn", + name => "jsDecode", + input => "TestCase", + output => "TestCase", + ret => 0, +}, +{ + type => "tfn", + name => "jsDecode", + input => "Test\0Case", + output => "Test\0Case", + ret => 0, +}, + +### Valid Sequences +{ + type => "tfn", + name => "jsDecode", + input => "\\a\\b\\f\\n\\r\\t\\v\\?\\'\\\"\\0\\12\\123\\x00\\xff\\u0021\\uff01", + output => "\a\b\f\x0a\x0d\t\x0b?'\"\x00\x0a\x53\x00\xff\x21\x21", + ret => 1, +}, +{ + type => "tfn", + name => "jsDecode", + input => "\\a\\b\\f\\n\\r\\t\\v\0\\?\\'\\\"\\0\\12\\123\\x00\\xff\\u0021\\uff01", + output => "\a\b\f\x0a\x0d\t\x0b\0?'\"\x00\x0a\x53\x00\xff\x21\x21", + ret => 1, +}, + +### Invalid Sequences +# \8 and \9 are not octal +# \666 is \66 + '6' (JS does not allow the overflow as C does) +# \u00ag, \u00ga, \u0zaa, \uz0aa are not hex +# \xag and \xga are not hex, +# \0123 is \012 + '3' +{ + type => "tfn", + name => "jsDecode", + input => "\\8\\9\\666\\u00ag\\u00ga\\u0zaa\\uz0aa\\xag\\xga\\0123\\u00a", + output => "89\x366u00agu00gau0zaauz0aaxagxga\x0a3u00a", + ret => 1, +}, + +# \x, \x0 lack enough hex digits +{ + type => "tfn", + name => "jsDecode", + input => "\\x", + output => "x", + ret => 1, +}, +{ + type => "tfn", + name => "jsDecode", + input => "\\x\\x0", + output => "xx0", + ret => 1, +}, +{ + type => "tfn", + name => "jsDecode", + input => "\\x\\x0\0", + output => "xx0\0", + ret => 1, +}, +# \u, \u0 \u01, \u012 lack enough hex digits +{ + type => "tfn", + name => "jsDecode", + input => "\\u", + output => "u", + ret => 1, +}, +{ + type => "tfn", + name => "jsDecode", + input => "\\u\\u0", + output => "uu0", + ret => 1, +}, +{ + type => "tfn", + name => "jsDecode", + input => "\\u\\u0\\u01", + output => "uu0u01", + ret => 1, +}, +{ + type => "tfn", + name => "jsDecode", + input => "\\u\\u0\\u01\\u012", + output => "uu0u01u012", + ret => 1, +}, +{ + type => "tfn", + name => "jsDecode", + input => "\\u\\u0\\u01\\u012\0", + output => "uu0u01u012\0", + ret => 1, +}, +# A forward slash with nothing after +{ + type => "tfn", + name => "jsDecode", + input => "\\", + output => "\\", + ret => 0, +}, +# A forward slash with NUL after +{ + type => "tfn", + name => "jsDecode", + input => "\\\0", + output => "\0", + ret => 1, +}, diff --git a/apache2/t/tfn/length.t b/apache2/t/tfn/length.t new file mode 100644 index 0000000..53f1602 --- /dev/null +++ b/apache2/t/tfn/length.t @@ -0,0 +1,44 @@ +### Empty +{ + type => "tfn", + name => "length", + input => "", + output => "0", + ret => 1, +}, + + +### Basic normal and large +{ + type => "tfn", + name => "length", + input => "0123456789abcdef", + output => "16", + ret => 1, +}, +# ENH: This sometimes fails w/4096 length +#{ +# type => "tfn", +# name => "length", +# input => ('x' x 8192), +# output => "8192", +# ret => 1, +#}, + +### With TAB +{ + type => "tfn", + name => "length", + input => "0123456789\tabcdef", + output => "17", + ret => 1, +}, + +### With NUL +{ + type => "tfn", + name => "length", + input => "Test\0Case", + output => "9", + ret => 1, +}, diff --git a/apache2/t/tfn/lowercase.t b/apache2/t/tfn/lowercase.t new file mode 100644 index 0000000..bd55f4a --- /dev/null +++ b/apache2/t/tfn/lowercase.t @@ -0,0 +1,40 @@ +### Empty +{ + type => "tfn", + name => "lowercase", + input => "", + output => "", + ret => 0, +}, + +### Nothing +{ + type => "tfn", + name => "lowercase", + input => "testcase", + output => "testcase", + ret => 0, +}, +{ + type => "tfn", + name => "lowercase", + input => "test\0case", + output => "test\0case", + ret => 0, +}, + +### Basic +{ + type => "tfn", + name => "lowercase", + input => "TestCase", + output => "testcase", + ret => 1, +}, +{ + type => "tfn", + name => "lowercase", + input => "Test\0Case", + output => "test\0case", + ret => 1, +}, diff --git a/apache2/t/tfn/md5.t b/apache2/t/tfn/md5.t new file mode 100644 index 0000000..f9956d6 --- /dev/null +++ b/apache2/t/tfn/md5.t @@ -0,0 +1,26 @@ +### Empty +{ + type => "tfn", + name => "md5", + input => "", + output => "\xd4\x1d\x8c\xd9\x8f\x00\xb2\x04\xe9\x80\x09\x98\xec\xf8\x42\x7e", + ret => 1, +}, + +### Basic +{ + type => "tfn", + name => "md5", + input => "TestCase", + output => "\xc9\xab\xa2\xc3\xe6\x01\x26\x16\x9e\x80\xe9\xa2\x6b\xa2\x73\xc1", + ret => 1, +}, + +### Binary w/NUL +{ + type => "tfn", + name => "md5", + input => "\x00\x01\x02\x03\x04\x05\x06\x07\x08", + output => "\xa6\xe7\xd3\xb4\x6f\xdf\xaf\x0b\xde\x2a\x1f\x83\x2a\x00\xd2\xde", + ret => 1, +}, diff --git a/apache2/t/tfn/normalisePath.t b/apache2/t/tfn/normalisePath.t new file mode 100644 index 0000000..851e667 --- /dev/null +++ b/apache2/t/tfn/normalisePath.t @@ -0,0 +1,98 @@ +### Empty +{ + type => "tfn", + name => "normalisePath", + input => "", + output => "", + ret => 0, +}, + +### Nothing +{ + type => "tfn", + name => "normalisePath", + input => "/foo/bar/baz", + output => "/foo/bar/baz", + ret => 0, +}, +{ + type => "tfn", + name => "normalisePath", + input => "/foo/bar\0/baz", + output => "/foo/bar\0/baz", + ret => 0, +}, + +### Basic +{ + type => "tfn", + name => "normalisePath", + input => "/foo/bar//baz", + output => "/foo/bar/baz", + ret => 1, +}, +{ + type => "tfn", + name => "normalisePath", + input => "/foo/bar baz/././././boo//eek/././../whoa", + output => "/foo/bar baz/boo/whoa", + ret => 1, +}, +{ + type => "tfn", + name => "normalisePath", + input => "./foo/bar baz/././././boo//eek/././../whoa", + output => "./foo/bar baz/boo/whoa", + ret => 1, +}, +{ + type => "tfn", + name => "normalisePath", + input => "/./foo/bar baz/././././boo//eek/././../whoa", + output => "/foo/bar baz/boo/whoa", + ret => 1, +}, +{ + type => "tfn", + name => "normalisePath", + input => "//foo/bar baz/././././boo//eek/././../whoa", + output => "/foo/bar baz/boo/whoa", + ret => 1, +}, +{ + type => "tfn", + name => "normalisePath", + input => "//foo/bar baz/././././boo//eek/././../whoa/./", + output => "/foo/bar baz/boo/whoa/", + ret => 1, +}, +{ + type => "tfn", + name => "normalisePath", + input => "/./foo/bar baz/././././boo//eek/././../whoa//", + output => "/foo/bar baz/boo/whoa/", + ret => 1, +}, +{ + type => "tfn", + name => "normalisePath", + input => "/./../../../../../../../../etc/passwd", + output => "/etc/passwd", + ret => 1, +}, +{ + type => "tfn", + name => "normalisePath", + input => "/./.././../../../../../../../etc/../etc/./passwd", + output => "/etc/passwd", + ret => 1, +}, + +### With NUL +{ + type => "tfn", + name => "normalisePath", + input => "/./.././../../../../../../../\0/../etc/./passwd", + output => "/etc/passwd", + ret => 1, +}, diff --git a/apache2/t/tfn/normalisePathWin.t b/apache2/t/tfn/normalisePathWin.t new file mode 100644 index 0000000..a3845bf --- /dev/null +++ b/apache2/t/tfn/normalisePathWin.t @@ -0,0 +1,98 @@ +### Empty +{ + type => "tfn", + name => "normalisePathWin", + input => "", + output => "", + ret => 0, +}, + +### Nothing but switch slashes +{ + type => "tfn", + name => "normalisePathWin", + input => "\\foo\\bar\\baz", + output => "/foo/bar/baz", + ret => 1, +}, +{ + type => "tfn", + name => "normalisePathWin", + input => "\\foo\\bar\0\\baz", + output => "/foo/bar\0/baz", + ret => 1, +}, + +### Basics +{ + type => "tfn", + name => "normalisePathWin", + input => "\\foo\\bar\\\\baz", + output => "/foo/bar/baz", + ret => 1, +}, +{ + type => "tfn", + name => "normalisePathWin", + input => "\\foo\\bar baz\\.\\.\\.\\.\\boo\\\\eek\\.\\.\\..\\whoa", + output => "/foo/bar baz/boo/whoa", + ret => 1, +}, +{ + type => "tfn", + name => "normalisePathWin", + input => ".\\foo\\bar baz\\.\\.\\.\\.\\boo\\\\eek\\.\\.\\..\\whoa", + output => "./foo/bar baz/boo/whoa", + ret => 1, +}, +{ + type => "tfn", + name => "normalisePathWin", + input => "\\.\\foo\\bar baz\\.\\.\\.\\.\\boo\\\\eek\\.\\.\\..\\whoa", + output => "/foo/bar baz/boo/whoa", + ret => 1, +}, +{ + type => "tfn", + name => "normalisePathWin", + input => "\\\\foo\\bar baz\\.\\.\\.\\.\\boo\\\\eek\\.\\.\\..\\whoa", + output => "/foo/bar baz/boo/whoa", + ret => 1, +}, +{ + type => "tfn", + name => "normalisePathWin", + input => "\\\\foo\\bar baz\\.\\.\\.\\.\\boo\\\\eek\\.\\.\\..\\whoa\\.\\", + output => "/foo/bar baz/boo/whoa/", + ret => 1, +}, +{ + type => "tfn", + name => "normalisePathWin", + input => "\\.\\foo\\bar baz\\.\\.\\.\\.\\boo\\\\eek\\.\\.\\..\\whoa\\\\", + output => "/foo/bar baz/boo/whoa/", + ret => 1, +}, +{ + type => "tfn", + name => "normalisePathWin", + input => "\\.\\..\\..\\..\\..\\..\\..\\..\\..\\etc\\passwd", + output => "/etc/passwd", + ret => 1, +}, +{ + type => "tfn", + name => "normalisePathWin", + input => "\\.\\..\\.\\..\\..\\..\\..\\..\\..\\..\\etc\\..\\etc\\.\\passwd", + output => "/etc/passwd", + ret => 1, +}, + +### With NUL +{ + type => "tfn", + name => "normalisePathWin", + input => "\\.\\..\\.\\..\\..\\..\\..\\..\\..\\..\\\0\\..\\etc\\.\\passwd", + output => "/etc/passwd", + ret => 1, +}, diff --git a/apache2/t/tfn/parityEven7bit.t b/apache2/t/tfn/parityEven7bit.t new file mode 100644 index 0000000..3d02cc4 --- /dev/null +++ b/apache2/t/tfn/parityEven7bit.t @@ -0,0 +1,34 @@ +### Empty +{ + type => "tfn", + name => "parityEven7bit", + input => "", + output => "", + ret => 0, +}, + +### Nothing +{ + type => "tfn", + name => "parityEven7bit", + input => "cefijloqrtwx03569ABDGHKMNPSUVYZ", + output => "cefijloqrtwx03569ABDGHKMNPSUVYZ", + ret => 0, +}, + +### Parity +{ + type => "tfn", + name => "parityEven7bit", + input => "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", + output => "\xe1\xe2c\xe4ef\xe7\xe8ij\xebl\xed\xeeo\xf0qr\xf3t\xf5\xf6wx\xf9\xfa0\xb1\xb23\xb456\xb7\xb89AB\xc3D\xc5\xc6GH\xc9\xcaK\xccMN\xcfP\xd1\xd2S\xd4UV\xd7\xd8YZ", + ret => 1, +}, +{ + type => "tfn", + name => "parityEven7bit", + input => "abcdefghijklmnopqrstuvwxyz\x000123456789\x00ABCDEFGHIJKLMNOPQRSTUVWXYZ", + output => "\xe1\xe2c\xe4ef\xe7\xe8ij\xebl\xed\xeeo\xf0qr\xf3t\xf5\xf6wx\xf9\xfa\x000\xb1\xb23\xb456\xb7\xb89\x00AB\xc3D\xc5\xc6GH\xc9\xcaK\xccMN\xcfP\xd1\xd2S\xd4UV\xd7\xd8YZ", + ret => 1, +}, + diff --git a/apache2/t/tfn/parityOdd7bit.t b/apache2/t/tfn/parityOdd7bit.t new file mode 100644 index 0000000..61a7eac --- /dev/null +++ b/apache2/t/tfn/parityOdd7bit.t @@ -0,0 +1,34 @@ +### Empty +{ + type => "tfn", + name => "parityOdd7bit", + input => "", + output => "", + ret => 0, +}, + +### Nothing +{ + type => "tfn", + name => "parityOdd7bit", + input => "abdghkmnpsuvyz12478CEFIJLOQRTW", + output => "abdghkmnpsuvyz12478CEFIJLOQRTW", + ret => 0, +}, + +### Parity +{ + type => "tfn", + name => "parityOdd7bit", + input => "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", + output => "ab\xe3d\xe5\xe6gh\xe9\xeak\xecmn\xefp\xf1\xf2s\xf4uv\xf7\xf8yz\xb012\xb34\xb5\xb678\xb9\xc1\xc2C\xc4EF\xc7\xc8IJ\xcbL\xcd\xceO\xd0QR\xd3T\xd5\xd6WX\xd9\xda", + ret => 1, +}, +{ + type => "tfn", + name => "parityOdd7bit", + input => "abcdefghijklmnopqrstuvwxyz\x000123456789\x00ABCDEFGHIJKLMNOPQRSTUVWXYZ", + output => "ab\xe3d\xe5\xe6gh\xe9\xeak\xecmn\xefp\xf1\xf2s\xf4uv\xf7\xf8yz\x80\xb012\xb34\xb5\xb678\xb9\x80\xc1\xc2C\xc4EF\xc7\xc8IJ\xcbL\xcd\xceO\xd0QR\xd3T\xd5\xd6WX\xd9\xda", + ret => 1, +}, + diff --git a/apache2/t/tfn/parityZero7bit.t b/apache2/t/tfn/parityZero7bit.t new file mode 100644 index 0000000..41862b5 --- /dev/null +++ b/apache2/t/tfn/parityZero7bit.t @@ -0,0 +1,33 @@ +### Empty +{ + type => "tfn", + name => "parityZero7bit", + input => "", + output => "", + ret => 0, +}, + +### Nothing +{ + type => "tfn", + name => "parityZero7bit", + input => "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", + output => "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", + ret => 0, +}, +{ + type => "tfn", + name => "parityZero7bit", + input => "abcdefghijklmnopqrstuvwxyz\x000123456789\x00ABCDEFGHIJKLMNOPQRSTUVWXYZ", + output => "abcdefghijklmnopqrstuvwxyz\x000123456789\x00ABCDEFGHIJKLMNOPQRSTUVWXYZ", + ret => 0, +}, + +### Basic +{ + type => "tfn", + name => "parityZero7bit", + input => "\x80\x00\x8f\xff", + output => "\x00\x00\x0f\x7f", + ret => 1, +}, diff --git a/apache2/t/tfn/removeNulls.t b/apache2/t/tfn/removeNulls.t new file mode 100644 index 0000000..c538b93 --- /dev/null +++ b/apache2/t/tfn/removeNulls.t @@ -0,0 +1,62 @@ +### Empty +{ + type => "tfn", + name => "removeNulls", + input => "", + output => "", + ret => 0, +}, + +### Nothing +{ + type => "tfn", + name => "removeNulls", + input => "TestCase", + output => "TestCase", + ret => 0, +}, +{ + type => "tfn", + name => "removeNulls", + input => "Test\x01Case", + output => "Test\x01Case", + ret => 0, +}, + + +### Basics +{ + type => "tfn", + name => "removeNulls", + input => "\0TestCase", + output => "TestCase", + ret => 1, +}, +{ + type => "tfn", + name => "removeNulls", + input => "Test\0Case", + output => "TestCase", + ret => 1, +}, +{ + type => "tfn", + name => "removeNulls", + input => "Test\0\0Case", + output => "TestCase", + ret => 1, +}, +{ + type => "tfn", + name => "removeNulls", + input => "TestCase\0", + output => "TestCase", + ret => 1, +}, +{ + type => "tfn", + name => "removeNulls", + input => "\0Test\0Case\0", + output => "TestCase", + ret => 1, +}, diff --git a/apache2/t/tfn/removeWhitespace.t b/apache2/t/tfn/removeWhitespace.t new file mode 100644 index 0000000..69cecae --- /dev/null +++ b/apache2/t/tfn/removeWhitespace.t @@ -0,0 +1,43 @@ +### Empty +{ + type => "tfn", + name => "removeWhitespace", + input => "", + output => "", + ret => 0, +}, + +### Nothing +{ + type => "tfn", + name => "removeWhitespace", + input => "TestCase", + output => "TestCase", + ret => 0, +}, +{ + type => "tfn", + name => "removeWhitespace", + input => "Test\0Case", + output => "Test\0Case", + ret => 0, +}, + + +### Remove space/tab +{ + type => "tfn", + name => "removeWhitespace", + input => " Test \t Case ", + output => "TestCase", + ret => 1, +}, + +### Pretty much everything in one +{ + type => "tfn", + name => "removeWhitespace", + input => "This is a test case with a tab \t, vtab \x0b, newline \x0a, return \x0d, formfeed \f, and a NUL\0 in it with a CRLF at the end.\x0d\x0a", + output => "Thisisatestcasewithatab,vtab,newline,return,formfeed,andaNUL\0initwithaCRLFattheend.", + ret => 1, +}, diff --git a/apache2/t/tfn/replaceComments.t b/apache2/t/tfn/replaceComments.t new file mode 100644 index 0000000..332436e --- /dev/null +++ b/apache2/t/tfn/replaceComments.t @@ -0,0 +1,155 @@ +### Empty +{ + type => "tfn", + name => "replaceComments", + input => "", + output => "", + ret => 0, +}, + +### Nothing +{ + type => "tfn", + name => "replaceComments", + input => "TestCase", + output => "TestCase", + ret => 0, +}, +{ + type => "tfn", + name => "replaceComments", + input => "Test\0Case", + output => "Test\0Case", + ret => 0, +}, + + +### Basics +{ + type => "tfn", + name => "replaceComments", + input => "/* TestCase */", + output => " ", + ret => 1, +}, +{ + type => "tfn", + name => "replaceComments", + input => "/*TestCase*/", + output => " ", + ret => 1, +}, +{ + type => "tfn", + name => "replaceComments", + input => "/* TestCase*/", + output => " ", + ret => 1, +}, +{ + type => "tfn", + name => "replaceComments", + input => "/*TestCase */", + output => " ", + ret => 1, +}, +{ + type => "tfn", + name => "replaceComments", + input => "Before/* TestCase */After", + output => "Before After", + ret => 1, +}, +{ + type => "tfn", + name => "replaceComments", + input => "Before /* TestCase */ After", + output => "Before After", + ret => 1, +}, +{ + type => "tfn", + name => "replaceComments", + input => "/* Test\nCase */", + output => " ", + ret => 1, +}, +{ + type => "tfn", + name => "replaceComments", + input => "/* Test\x0d\x0aCase */", + output => " ", + ret => 1, +}, +{ + type => "tfn", + name => "replaceComments", + input => "/* Test\x0aCase */", + output => " ", + ret => 1, +}, +{ + type => "tfn", + name => "replaceComments", + input => "/* Test\x0dCase */", + output => " ", + ret => 1, +}, + +### Broken Comments +{ + type => "tfn", + name => "replaceComments", + input => "Before/* Test\x0d\x0aCase ", + output => "Before ", + ret => 1, +}, +{ + type => "tfn", + name => "replaceComments", + input => "Before /* Test\x0aCase ", + output => "Before ", + ret => 1, +}, +{ + type => "tfn", + name => "replaceComments", + input => "Before/* Test\x0d\x0aCase ", + output => "Before ", + ret => 1, +}, +{ + type => "tfn", + name => "replaceComments", + input => "Before /* Test\x0aCase ", + output => "Before ", + ret => 1, +}, +{ + type => "tfn", + name => "replaceComments", + input => "Test\x0d\x0aCase */After", + output => "Test\x0d\x0aCase */After", + ret => 0, +}, +{ + type => "tfn", + name => "replaceComments", + input => "Test\x0aCase */ After", + output => "Test\x0aCase */ After", + ret => 0, +}, +{ + type => "tfn", + name => "replaceComments", + input => "Test\x0d\x0aCase */After", + output => "Test\x0d\x0aCase */After", + ret => 0, +}, +{ + type => "tfn", + name => "replaceComments", + input => "Test\x0aCase */ After", + output => "Test\x0aCase */ After", + ret => 0, +}, diff --git a/apache2/t/tfn/replaceNulls.t b/apache2/t/tfn/replaceNulls.t new file mode 100644 index 0000000..3be063c --- /dev/null +++ b/apache2/t/tfn/replaceNulls.t @@ -0,0 +1,55 @@ +### Empty +{ + type => "tfn", + name => "replaceNulls", + input => "", + output => "", + ret => 0, +}, + +### Nothing +{ + type => "tfn", + name => "replaceNulls", + input => "TestCase", + output => "TestCase", + ret => 0, +}, + + +### Basics +{ + type => "tfn", + name => "replaceNulls", + input => "\0TestCase", + output => " TestCase", + ret => 1, +}, +{ + type => "tfn", + name => "replaceNulls", + input => "Test\0Case", + output => "Test Case", + ret => 1, +}, +{ + type => "tfn", + name => "replaceNulls", + input => "Test\0\0Case", + output => "Test Case", + ret => 1, +}, +{ + type => "tfn", + name => "replaceNulls", + input => "TestCase\0", + output => "TestCase ", + ret => 1, +}, +{ + type => "tfn", + name => "replaceNulls", + input => "\0Test\0Case\0", + output => " Test Case ", + ret => 1, +}, diff --git a/apache2/t/tfn/sha1.t b/apache2/t/tfn/sha1.t new file mode 100644 index 0000000..84d38de --- /dev/null +++ b/apache2/t/tfn/sha1.t @@ -0,0 +1,26 @@ +### Empty +{ + type => "tfn", + name => "sha1", + input => "", + output => "\xda\x39\xa3\xee\x5e\x6b\x4b\x0d\x32\x55\xbf\xef\x95\x60\x18\x90\xaf\xd8\x07\x09", + ret => 1, +}, + +### Basic +{ + type => "tfn", + name => "sha1", + input => "TestCase", + output => "\xa7\x0c\xe3\x83\x89\xe3\x18\xbd\x2b\xe1\x8a\x01\x11\xc6\xdc\x76\xbd\x2c\xd9\xed", + ret => 1, +}, + +### Binary w/NUL +{ + type => "tfn", + name => "sha1", + input => "\x00\x01\x02\x03\x04\x05\x06\x07\x08", + output => "\x63\xbf\x60\xc7\x10\x5a\x07\xa2\xb1\x25\xbb\xf8\x9e\x61\xab\xda\xbc\x69\x78\xc2", + ret => 1, +}, diff --git a/apache2/t/tfn/trim.t b/apache2/t/tfn/trim.t new file mode 100644 index 0000000..7ac3f7f --- /dev/null +++ b/apache2/t/tfn/trim.t @@ -0,0 +1,68 @@ +### Empty +{ + type => "tfn", + name => "trim", + input => "", + output => "", + ret => 0, +}, + +### Nothing +{ + type => "tfn", + name => "trim", + input => "TestCase", + output => "TestCase", + ret => 0, +}, +{ + type => "tfn", + name => "trim", + input => "Test\0Case", + output => "Test\0Case", + ret => 0, +}, + +### Basics +{ + type => "tfn", + name => "trim", + input => " TestCase", + output => "TestCase", + ret => 1, +}, +{ + type => "tfn", + name => "trim", + input => "TestCase ", + output => "TestCase", + ret => 1, +}, +{ + type => "tfn", + name => "trim", + input => " TestCase ", + output => "TestCase", + ret => 1, +}, +{ + type => "tfn", + name => "trim", + input => " Test Case ", + output => "Test Case", + ret => 1, +}, +{ + type => "tfn", + name => "trim", + input => " Test \0 Case ", + output => "Test \0 Case", + ret => 1, +}, +{ + type => "tfn", + name => "trim", + input => " Test \0 Case \r\n ", + output => "Test \0 Case", + ret => 1, +}, diff --git a/apache2/t/tfn/trimLeft.t b/apache2/t/tfn/trimLeft.t new file mode 100644 index 0000000..e2c2951 --- /dev/null +++ b/apache2/t/tfn/trimLeft.t @@ -0,0 +1,69 @@ +### Empty +{ + type => "tfn", + name => "trimLeft", + input => "", + output => "", + ret => 0, +}, + +### Nothing +{ + type => "tfn", + name => "trimLeft", + input => "TestCase", + output => "TestCase", + ret => 0, +}, +{ + type => "tfn", + name => "trimLeft", + input => "Test\0Case", + output => "Test\0Case", + ret => 0, +}, +{ + type => "tfn", + name => "trimLeft", + input => "TestCase ", + output => "TestCase ", + ret => 0, +}, + + +### Basics +{ + type => "tfn", + name => "trimLeft", + input => " TestCase", + output => "TestCase", + ret => 1, +}, +{ + type => "tfn", + name => "trimLeft", + input => " TestCase ", + output => "TestCase ", + ret => 1, +}, +{ + type => "tfn", + name => "trimLeft", + input => " Test Case ", + output => "Test Case ", + ret => 1, +}, +{ + type => "tfn", + name => "trimLeft", + input => " Test \0 Case ", + output => "Test \0 Case ", + ret => 1, +}, +{ + type => "tfn", + name => "trimLeft", + input => " Test \0 Case \r\n ", + output => "Test \0 Case \r\n ", + ret => 1, +}, diff --git a/apache2/t/tfn/trimRight.t b/apache2/t/tfn/trimRight.t new file mode 100644 index 0000000..f356333 --- /dev/null +++ b/apache2/t/tfn/trimRight.t @@ -0,0 +1,68 @@ +### Empty +{ + type => "tfn", + name => "trimRight", + input => "", + output => "", + ret => 0, +}, + +### Nothing +{ + type => "tfn", + name => "trimRight", + input => "TestCase", + output => "TestCase", + ret => 0, +}, +{ + type => "tfn", + name => "trimRight", + input => "Test\0Case", + output => "Test\0Case", + ret => 0, +}, +{ + type => "tfn", + name => "trimRight", + input => " TestCase", + output => " TestCase", + ret => 0, +}, + +### Basics +{ + type => "tfn", + name => "trimRight", + input => "TestCase ", + output => "TestCase", + ret => 1, +}, +{ + type => "tfn", + name => "trimRight", + input => " TestCase ", + output => " TestCase", + ret => 1, +}, +{ + type => "tfn", + name => "trimRight", + input => " Test Case ", + output => " Test Case", + ret => 1, +}, +{ + type => "tfn", + name => "trimRight", + input => " Test \0 Case ", + output => " Test \0 Case", + ret => 1, +}, +{ + type => "tfn", + name => "trimRight", + input => " Test \0 Case \r\n ", + output => " Test \0 Case", + ret => 1, +}, diff --git a/apache2/t/tfn/urlDecode.t b/apache2/t/tfn/urlDecode.t new file mode 100644 index 0000000..b0ea007 --- /dev/null +++ b/apache2/t/tfn/urlDecode.t @@ -0,0 +1,143 @@ +### Empty +{ + type => "tfn", + name => "urlDecode", + input => "", + output => "", + ret => 0, +}, + +### Nothing +{ + type => "tfn", + name => "urlDecode", + input => "TestCase", + output => "TestCase", + ret => 0, +}, +{ + type => "tfn", + name => "urlDecode", + input => "Test\0Case", + output => "Test\0Case", + ret => 0, +}, + +### Valid +{ + type => "tfn", + name => "urlDecode", + input => "+%00%01%02%03%04%05%06%07%08%09%0a%0b%0c%0d%0e%0f%10%11%12%13%14%15%16%17%18%19%1a%1b%1c%1d%1e%1f%20%21%22%23%24%25%26%27%28%29%2a%2b%2c%2d%2e%2f%30%31%32%33%34%35%36%37%38%39%3a%3b%3c%3d%3e%3f%40%41%42%43%44%45%46%47%48%49%4a%4b%4c%4d%4e%4f%50%51%52%53%54%55%56%57%58%59%5a%5b%5c%5d%5e%5f%60%61%62%63%64%65%66%67%68%69%6a%6b%6c%6d%6e%6f%70%71%72%73%74%75%76%77%78%79%7a%7b%7c%7d%7e%7f%80%81%82%83%84%85%86%87%88%89%8a%8b%8c%8d%8e%8f%90%91%92%93%94%95%96%97%98%99%9a%9b%9c%9d%9e%9f%a0%a1%a2%a3%a4%a5%a6%a7%a8%a9%aa%ab%ac%ad%ae%af%b0%b1%b2%b3%b4%b5%b6%b7%b8%b9%ba%bb%bc%bd%be%bf%c0%c1%c2%c3%c4%c5%c6%c7%c8%c9%ca%cb%cc%cd%ce%cf%d0%d1%d2%d3%d4%d5%d6%d7%d8%d9%da%db%dc%dd%de%df%e0%e1%e2%e3%e4%e5%e6%e7%e8%e9%ea%eb%ec%ed%ee%ef%f0%f1%f2%f3%f4%f5%f6%f7%f8%f9%fa%fb%fc%fd%fe%ff", + output => " \x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f \x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", + ret => 1, +}, +{ + type => "tfn", + name => "urlDecode", + input => "Test+Case", + output => "Test Case", + ret => 1, +}, + + +### Partial Invalid +{ + type => "tfn", + name => "urlDecode", + input => "%+", + output => "% ", + ret => 1, +}, +{ + type => "tfn", + name => "urlDecode", + input => "%%20", + output => "% ", + ret => 1, +}, +{ + type => "tfn", + name => "urlDecode", + input => "%0g%20", + output => "%0g ", + ret => 1, +}, +{ + type => "tfn", + name => "urlDecode", + input => "%0%20", + output => "%0 ", + ret => 1, +}, +{ + type => "tfn", + name => "urlDecode", + input => "%g0%20", + output => "%g0 ", + ret => 1, +}, +{ + type => "tfn", + name => "urlDecode", + input => "%g%20", + output => "%g ", + ret => 1, +}, + +### Invalid +{ + type => "tfn", + name => "urlDecode", + input => "%0%1%2%3%4%5%6%7%8%9%0%a%b%c%d%e%f", + output => "%0%1%2%3%4%5%6%7%8%9%0%a%b%c%d%e%f", + ret => 0, +}, +{ + type => "tfn", + name => "urlDecode", + input => "%g0%g1%g2%g3%g4%g5%g6%g7%g8%g9%g0%ga%gb%gc%gd%ge%gf", + output => "%g0%g1%g2%g3%g4%g5%g6%g7%g8%g9%g0%ga%gb%gc%gd%ge%gf", + ret => 0, +}, +{ + type => "tfn", + name => "urlDecode", + input => "%0g%1g%2g%3g%4g%5g%6g%7g%8g%9g%0g%ag%bg%cg%dg%eg%fg", + output => "%0g%1g%2g%3g%4g%5g%6g%7g%8g%9g%0g%ag%bg%cg%dg%eg%fg", + ret => 0, +}, +{ + type => "tfn", + name => "urlDecode", + input => "%", + output => "%", + ret => 0, +}, +{ + type => "tfn", + name => "urlDecode", + input => "%0", + output => "%0", + ret => 0, +}, +{ + type => "tfn", + name => "urlDecode", + input => "%%", + output => "%%", + ret => 0, +}, +{ + type => "tfn", + name => "urlDecode", + input => "%0g", + output => "%0g", + ret => 0, +}, +{ + type => "tfn", + name => "urlDecode", + input => "%gg", + output => "%gg", + ret => 0, +}, diff --git a/apache2/t/tfn/urlDecodeUni.t b/apache2/t/tfn/urlDecodeUni.t new file mode 100644 index 0000000..798542c --- /dev/null +++ b/apache2/t/tfn/urlDecodeUni.t @@ -0,0 +1,235 @@ +### Empty +{ + type => "tfn", + name => "urlDecodeUni", + input => "", + output => "", + ret => 0, +}, + +### Nothing +{ + type => "tfn", + name => "urlDecodeUni", + input => "TestCase", + output => "TestCase", + ret => 0, +}, +{ + type => "tfn", + name => "urlDecodeUni", + input => "Test\0Case", + output => "Test\0Case", + ret => 0, +}, + +### Valid +{ + type => "tfn", + name => "urlDecodeUni", + input => "+%00%01%02%03%04%05%06%07%08%09%0a%0b%0c%0d%0e%0f%10%11%12%13%14%15%16%17%18%19%1a%1b%1c%1d%1e%1f%20%21%22%23%24%25%26%27%28%29%2a%2b%2c%2d%2e%2f%30%31%32%33%34%35%36%37%38%39%3a%3b%3c%3d%3e%3f%40%41%42%43%44%45%46%47%48%49%4a%4b%4c%4d%4e%4f%50%51%52%53%54%55%56%57%58%59%5a%5b%5c%5d%5e%5f%60%61%62%63%64%65%66%67%68%69%6a%6b%6c%6d%6e%6f%70%71%72%73%74%75%76%77%78%79%7a%7b%7c%7d%7e%7f%80%81%82%83%84%85%86%87%88%89%8a%8b%8c%8d%8e%8f%90%91%92%93%94%95%96%97%98%99%9a%9b%9c%9d%9e%9f%a0%a1%a2%a3%a4%a5%a6%a7%a8%a9%aa%ab%ac%ad%ae%af%b0%b1%b2%b3%b4%b5%b6%b7%b8%b9%ba%bb%bc%bd%be%bf%c0%c1%c2%c3%c4%c5%c6%c7%c8%c9%ca%cb%cc%cd%ce%cf%d0%d1%d2%d3%d4%d5%d6%d7%d8%d9%da%db%dc%dd%de%df%e0%e1%e2%e3%e4%e5%e6%e7%e8%e9%ea%eb%ec%ed%ee%ef%f0%f1%f2%f3%f4%f5%f6%f7%f8%f9%fa%fb%fc%fd%fe%ff", + output => " \x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f \x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", + ret => 1, +}, +{ + type => "tfn", + name => "urlDecodeUni", + input => "Test+Case", + output => "Test Case", + ret => 1, +}, +{ + type => "tfn", + name => "urlDecodeUni", + input => "+%u0000%u0001%u0002%u0003%u0004%u0005%u0006%u0007%u0008%u0009%u000a%u000b%u000c%u000d%u000e%u000f%u0010%u0011%u0012%u0013%u0014%u0015%u0016%u0017%u0018%u0019%u001a%u001b%u001c%u001d%u001e%u001f%u0020%u0021%u0022%u0023%u0024%u0025%u0026%u0027%u0028%u0029%u002a%u002b%u002c%u002d%u002e%u002f%u0030%u0031%u0032%u0033%u0034%u0035%u0036%u0037%u0038%u0039%u003a%u003b%u003c%u003d%u003e%u003f%u0040%u0041%u0042%u0043%u0044%u0045%u0046%u0047%u0048%u0049%u004a%u004b%u004c%u004d%u004e%u004f%u0050%u0051%u0052%u0053%u0054%u0055%u0056%u0057%u0058%u0059%u005a%u005b%u005c%u005d%u005e%u005f%u0060%u0061%u0062%u0063%u0064%u0065%u0066%u0067%u0068%u0069%u006a%u006b%u006c%u006d%u006e%u006f%u0070%u0071%u0072%u0073%u0074%u0075%u0076%u0077%u0078%u0079%u007a%u007b%u007c%u007d%u007e%u007f%u0080%u0081%u0082%u0083%u0084%u0085%u0086%u0087%u0088%u0089%u008a%u008b%u008c%u008d%u008e%u008f%u0090%u0091%u0092%u0093%u0094%u0095%u0096%u0097%u0098%u0099%u009a%u009b%u009c%u009d%u009e%u009f%u00a0%u00a1%u00a2%u00a3%u00a4%u00a5%u00a6%u00a7%u00a8%u00a9%u00aa%u00ab%u00ac%u00ad%u00ae%u00af%u00b0%u00b1%u00b2%u00b3%u00b4%u00b5%u00b6%u00b7%u00b8%u00b9%u00ba%u00bb%u00bc%u00bd%u00be%u00bf%u00c0%u00c1%u00c2%u00c3%u00c4%u00c5%u00c6%u00c7%u00c8%u00c9%u00ca%u00cb%u00cc%u00cd%u00ce%u00cf%u00d0%u00d1%u00d2%u00d3%u00d4%u00d5%u00d6%u00d7%u00d8%u00d9%u00da%u00db%u00dc%u00dd%u00de%u00df%u00e0%u00e1%u00e2%u00e3%u00e4%u00e5%u00e6%u00e7%u00e8%u00e9%u00ea%u00eb%u00ec%u00ed%u00ee%u00ef%u00f0%u00f1%u00f2%u00f3%u00f4%u00f5%u00f6%u00f7%u00f8%u00f9%u00fa%u00fb%u00fc%u00fd%u00fe%u00ff", + output => " \x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f \x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", + ret => 1, +}, +{ + type => "tfn", + name => "urlDecodeUni", + input => "+%u1100%u1101%u1102%u1103%u1104%u1105%u1106%u1107%u1108%u1109%u110a%u110b%u110c%u110d%u110e%u110f%u1110%u1111%u1112%u1113%u1114%u1115%u1116%u1117%u1118%u1119%u111a%u111b%u111c%u111d%u111e%u111f%u1120%u1121%u1122%u1123%u1124%u1125%u1126%u1127%u1128%u1129%u112a%u112b%u112c%u112d%u112e%u112f%u1130%u1131%u1132%u1133%u1134%u1135%u1136%u1137%u1138%u1139%u113a%u113b%u113c%u113d%u113e%u113f%u1140%u1141%u1142%u1143%u1144%u1145%u1146%u1147%u1148%u1149%u114a%u114b%u114c%u114d%u114e%u114f%u1150%u1151%u1152%u1153%u1154%u1155%u1156%u1157%u1158%u1159%u115a%u115b%u115c%u115d%u115e%u115f%u1160%u1161%u1162%u1163%u1164%u1165%u1166%u1167%u1168%u1169%u116a%u116b%u116c%u116d%u116e%u116f%u1170%u1171%u1172%u1173%u1174%u1175%u1176%u1177%u1178%u1179%u117a%u117b%u117c%u117d%u117e%u117f%u1180%u1181%u1182%u1183%u1184%u1185%u1186%u1187%u1188%u1189%u118a%u118b%u118c%u118d%u118e%u118f%u1190%u1191%u1192%u1193%u1194%u1195%u1196%u1197%u1198%u1199%u119a%u119b%u119c%u119d%u119e%u119f%u11a0%u11a1%u11a2%u11a3%u11a4%u11a5%u11a6%u11a7%u11a8%u11a9%u11aa%u11ab%u11ac%u11ad%u11ae%u11af%u11b0%u11b1%u11b2%u11b3%u11b4%u11b5%u11b6%u11b7%u11b8%u11b9%u11ba%u11bb%u11bc%u11bd%u11be%u11bf%u11c0%u11c1%u11c2%u11c3%u11c4%u11c5%u11c6%u11c7%u11c8%u11c9%u11ca%u11cb%u11cc%u11cd%u11ce%u11cf%u11d0%u11d1%u11d2%u11d3%u11d4%u11d5%u11d6%u11d7%u11d8%u11d9%u11da%u11db%u11dc%u11dd%u11de%u11df%u11e0%u11e1%u11e2%u11e3%u11e4%u11e5%u11e6%u11e7%u11e8%u11e9%u11ea%u11eb%u11ec%u11ed%u11ee%u11ef%u11f0%u11f1%u11f2%u11f3%u11f4%u11f5%u11f6%u11f7%u11f8%u11f9%u11fa%u11fb%u11fc%u11fd%u11fe%u11ff", + output => " \x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f \x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", + ret => 1, +}, +# Full Width ASCII +{ + type => "tfn", + name => "urlDecodeUni", + input => "%uff01%uff02%uff03%uff04%uff05%uff06%uff07%uff08%uff09%uff0a%uff0b%uff0c%uff0d%uff0e%uff0f%uff10%uff11%uff12%uff13%uff14%uff15%uff16%uff17%uff18%uff19%uff1a%uff1b%uff1c%uff1d%uff1e%uff1f%uff20%uff21%uff22%uff23%uff24%uff25%uff26%uff27%uff28%uff29%uff2a%uff2b%uff2c%uff2d%uff2e%uff2f%uff30%uff31%uff32%uff33%uff34%uff35%uff36%uff37%uff38%uff39%uff3a%uff3b%uff3c%uff3d%uff3e%uff3f%uff40%uff41%uff42%uff43%uff44%uff45%uff46%uff47%uff48%uff49%uff4a%uff4b%uff4c%uff4d%uff4e%uff4f%uff50%uff51%uff52%uff53%uff54%uff55%uff56%uff57%uff58%uff59%uff5a%uff5b%uff5c%uff5d%uff5e", + output => "\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e", + ret => 1, +}, +# Invalid Full Width ASCII +{ + type => "tfn", + name => "urlDecodeUni", + input => "%uff00%uff7f%uff80%uff81%uff82%uff83%uff84%uff85%uff86%uff87%uff88%uff89%uff8a%uff8b%uff8c%uff8d%uff8e%uff8f%uff90%uff91%uff92%uff93%uff94%uff95%uff96%uff97%uff98%uff99%uff9a%uff9b%uff9c%uff9d%uff9e%uff9f%uffa0%uffa1%uffa2%uffa3%uffa4%uffa5%uffa6%uffa7%uffa8%uffa9%uffaa%uffab%uffac%uffad%uffae%uffaf%uffb0%uffb1%uffb2%uffb3%uffb4%uffb5%uffb6%uffb7%uffb8%uffb9%uffba%uffbb%uffbc%uffbd%uffbe%uffbf%uffc0%uffc1%uffc2%uffc3%uffc4%uffc5%uffc6%uffc7%uffc8%uffc9%uffca%uffcb%uffcc%uffcd%uffce%uffcf%uffd0%uffd1%uffd2%uffd3%uffd4%uffd5%uffd6%uffd7%uffd8%uffd9%uffda%uffdb%uffdc%uffdd%uffde%uffdf%uffe0%uffe1%uffe2%uffe3%uffe4%uffe5%uffe6%uffe7%uffe8%uffe9%uffea%uffeb%uffec%uffed%uffee%uffef%ufff0%ufff1%ufff2%ufff3%ufff4%ufff5%ufff6%ufff7%ufff8%ufff9%ufffa%ufffb%ufffc%ufffd%ufffe%uffff", + output => "\x00\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", + ret => 1, +}, + +### Partial Invalid +{ + type => "tfn", + name => "urlDecodeUni", + input => "%+", + output => "% ", + ret => 1, +}, +{ + type => "tfn", + name => "urlDecodeUni", + input => "%%20", + output => "% ", + ret => 1, +}, +{ + type => "tfn", + name => "urlDecodeUni", + input => "%0g%20", + output => "%0g ", + ret => 1, +}, +{ + type => "tfn", + name => "urlDecodeUni", + input => "%0%20", + output => "%0 ", + ret => 1, +}, +{ + type => "tfn", + name => "urlDecodeUni", + input => "%g0%20", + output => "%g0 ", + ret => 1, +}, +{ + type => "tfn", + name => "urlDecodeUni", + input => "%g%20", + output => "%g ", + ret => 1, +}, +{ + type => "tfn", + name => "urlDecodeUni", + input => "%%u0020", + output => "% ", + ret => 1, +}, +{ + type => "tfn", + name => "urlDecodeUni", + input => "%0g%u0020", + output => "%0g ", + ret => 1, +}, +{ + type => "tfn", + name => "urlDecodeUni", + input => "%0%u0020", + output => "%0 ", + ret => 1, +}, +{ + type => "tfn", + name => "urlDecodeUni", + input => "%g0%u0020", + output => "%g0 ", + ret => 1, +}, +{ + type => "tfn", + name => "urlDecodeUni", + input => "%u%u0020", + output => "%u ", + ret => 1, +}, +{ + type => "tfn", + name => "urlDecodeUni", + input => "%u0%u0020", + output => "%u0 ", + ret => 1, +}, +{ + type => "tfn", + name => "urlDecodeUni", + input => "%u00%u0020", + output => "%u00 ", + ret => 1, +}, +{ + type => "tfn", + name => "urlDecodeUni", + input => "%u000%u0020", + output => "%u000 ", + ret => 1, +}, +{ + type => "tfn", + name => "urlDecodeUni", + input => "%u000g%u0020", + output => "%u000g ", + ret => 1, +}, + +### Invalid +{ + type => "tfn", + name => "urlDecodeUni", + input => "%0%1%2%3%4%5%6%7%8%9%0%a%b%c%d%e%f", + output => "%0%1%2%3%4%5%6%7%8%9%0%a%b%c%d%e%f", + ret => 0, +}, +{ + type => "tfn", + name => "urlDecodeUni", + input => "%g0%g1%g2%g3%g4%g5%g6%g7%g8%g9%g0%ga%gb%gc%gd%ge%gf", + output => "%g0%g1%g2%g3%g4%g5%g6%g7%g8%g9%g0%ga%gb%gc%gd%ge%gf", + ret => 0, +}, +{ + type => "tfn", + name => "urlDecodeUni", + input => "%0g%1g%2g%3g%4g%5g%6g%7g%8g%9g%0g%ag%bg%cg%dg%eg%fg", + output => "%0g%1g%2g%3g%4g%5g%6g%7g%8g%9g%0g%ag%bg%cg%dg%eg%fg", + ret => 0, +}, +{ + type => "tfn", + name => "urlDecodeUni", + input => "%", + output => "%", + ret => 0, +}, +{ + type => "tfn", + name => "urlDecodeUni", + input => "%0", + output => "%0", + ret => 0, +}, +{ + type => "tfn", + name => "urlDecodeUni", + input => "%%", + output => "%%", + ret => 0, +}, +{ + type => "tfn", + name => "urlDecodeUni", + input => "%0g", + output => "%0g", + ret => 0, +}, +{ + type => "tfn", + name => "urlDecodeUni", + input => "%gg", + output => "%gg", + ret => 0, +}, diff --git a/apache2/t/tfn/urlEncode.t b/apache2/t/tfn/urlEncode.t new file mode 100644 index 0000000..10f9bca --- /dev/null +++ b/apache2/t/tfn/urlEncode.t @@ -0,0 +1,129 @@ +### Empty +{ + type => "tfn", + name => "urlEncode", + input => "", + output => "", + ret => 0, +}, + +### Nothing +{ + type => "tfn", + name => "urlEncode", + input => "TestCase", + output => "TestCase", + ret => 0, +}, + +### Valid +{ + type => "tfn", + name => "urlEncode", + input => " \x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", + output => "+%00%01%02%03%04%05%06%07%08%09%0a%0b%0c%0d%0e%0f%10%11%12%13%14%15%16%17%18%19%1a%1b%1c%1d%1e%1f+%21%22%23%24%25%26%27%28%29*%2b%2c%2d%2e%2f0123456789%3a%3b%3c%3d%3e%3f%40ABCDEFGHIJKLMNOPQRSTUVWXYZ%5b%5c%5d%5e%5f%60abcdefghijklmnopqrstuvwxyz%7b%7c%7d%7e%7f%80%81%82%83%84%85%86%87%88%89%8a%8b%8c%8d%8e%8f%90%91%92%93%94%95%96%97%98%99%9a%9b%9c%9d%9e%9f%a0%a1%a2%a3%a4%a5%a6%a7%a8%a9%aa%ab%ac%ad%ae%af%b0%b1%b2%b3%b4%b5%b6%b7%b8%b9%ba%bb%bc%bd%be%bf%c0%c1%c2%c3%c4%c5%c6%c7%c8%c9%ca%cb%cc%cd%ce%cf%d0%d1%d2%d3%d4%d5%d6%d7%d8%d9%da%db%dc%dd%de%df%e0%e1%e2%e3%e4%e5%e6%e7%e8%e9%ea%eb%ec%ed%ee%ef%f0%f1%f2%f3%f4%f5%f6%f7%f8%f9%fa%fb%fc%fd%fe%ff", + ret => 1, +}, +{ + type => "tfn", + name => "urlEncode", + input => "Test Case", + output => "Test+Case", + ret => 1, +}, + + +### Partial Invalid +{ + type => "tfn", + name => "urlEncode", + input => "% ", + output => "%25+", + ret => 1, +}, +{ + type => "tfn", + name => "urlEncode", + input => "%0g ", + output => "%250g+", + ret => 1, +}, +{ + type => "tfn", + name => "urlEncode", + input => "%0 ", + output => "%250+", + ret => 1, +}, +{ + type => "tfn", + name => "urlEncode", + input => "%g0 ", + output => "%25g0+", + ret => 1, +}, +{ + type => "tfn", + name => "urlEncode", + input => "%g ", + output => "%25g+", + ret => 1, +}, + +### Invalid +{ + type => "tfn", + name => "urlEncode", + input => "%0%1%2%3%4%5%6%7%8%9%0%a%b%c%d%e%f", + output => "%250%251%252%253%254%255%256%257%258%259%250%25a%25b%25c%25d%25e%25f", + ret => 1, +}, +{ + type => "tfn", + name => "urlEncode", + input => "%g0%g1%g2%g3%g4%g5%g6%g7%g8%g9%g0%ga%gb%gc%gd%ge%gf", + output => "%25g0%25g1%25g2%25g3%25g4%25g5%25g6%25g7%25g8%25g9%25g0%25ga%25gb%25gc%25gd%25ge%25gf", + ret => 1, +}, +{ + type => "tfn", + name => "urlEncode", + input => "%0g%1g%2g%3g%4g%5g%6g%7g%8g%9g%0g%ag%bg%cg%dg%eg%fg", + output => "%250g%251g%252g%253g%254g%255g%256g%257g%258g%259g%250g%25ag%25bg%25cg%25dg%25eg%25fg", + ret => 1, +}, +{ + type => "tfn", + name => "urlEncode", + input => "%", + output => "%25", + ret => 1, +}, +{ + type => "tfn", + name => "urlEncode", + input => "%0", + output => "%250", + ret => 1, +}, +{ + type => "tfn", + name => "urlEncode", + input => "%%", + output => "%25%25", + ret => 1, +}, +{ + type => "tfn", + name => "urlEncode", + input => "%0g", + output => "%250g", + ret => 1, +}, +{ + type => "tfn", + name => "urlEncode", + input => "%gg", + output => "%25gg", + ret => 1, +}, diff --git a/apache2/utf8tables.h b/apache2/utf8tables.h new file mode 100644 index 0000000..d18f2f3 --- /dev/null +++ b/apache2/utf8tables.h @@ -0,0 +1,818 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/) + * + * This product is released under the terms of the General Public Licence, + * version 2 (GPLv2). Please refer to the file LICENSE (included with this + * distribution) which contains the complete text of the licence. + * + * There are special exceptions to the terms and conditions of the GPL + * as it is applied to this software. View the full text of the exception in + * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software + * distribution. + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Breach Security, Inc. + * directly using the email address support@breach.com. + * + */ +#ifndef UTF8TABLES_H_ +#define UTF8TABLES_H_ + +/** + * This include file is used by acmp.c only; it's not included anywhere else. + */ + +typedef long acmp_utf8_char_t; + +static const char utf8_seq_lengths[256] = { + 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, + 3,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3, + 4,4,4,4,4,4,4,4, 5,5,5,5,6,6,6,6, +}; + +static const acmp_utf8_char_t utf8_offsets[6] = { + 0x00000000UL, 0x00003080UL, 0x000E2080UL, + 0x03C82080UL, 0xFA082080UL, 0x82082080UL +}; + +/** + * How many element pairs are there in utf8_lcase_map + */ +#define UTF8_LCASEMAP_LEN 759 + +/** + * Table mapping is from PHP's mbstring extension, maps uppercase + */ +static const acmp_utf8_char_t utf8_lcase_map[UTF8_LCASEMAP_LEN * 2] = { + 0x00000061, 0x00000041, + 0x00000062, 0x00000042, + 0x00000063, 0x00000043, + 0x00000064, 0x00000044, + 0x00000065, 0x00000045, + 0x00000066, 0x00000046, + 0x00000067, 0x00000047, + 0x00000068, 0x00000048, + 0x00000069, 0x00000049, + 0x0000006a, 0x0000004a, + 0x0000006b, 0x0000004b, + 0x0000006c, 0x0000004c, + 0x0000006d, 0x0000004d, + 0x0000006e, 0x0000004e, + 0x0000006f, 0x0000004f, + 0x00000070, 0x00000050, + 0x00000071, 0x00000051, + 0x00000072, 0x00000052, + 0x00000073, 0x00000053, + 0x00000074, 0x00000054, + 0x00000075, 0x00000055, + 0x00000076, 0x00000056, + 0x00000077, 0x00000057, + 0x00000078, 0x00000058, + 0x00000079, 0x00000059, + 0x0000007a, 0x0000005a, + 0x000000b5, 0x0000039c, + 0x000000e0, 0x000000c0, + 0x000000e1, 0x000000c1, + 0x000000e2, 0x000000c2, + 0x000000e3, 0x000000c3, + 0x000000e4, 0x000000c4, + 0x000000e5, 0x000000c5, + 0x000000e6, 0x000000c6, + 0x000000e7, 0x000000c7, + 0x000000e8, 0x000000c8, + 0x000000e9, 0x000000c9, + 0x000000ea, 0x000000ca, + 0x000000eb, 0x000000cb, + 0x000000ec, 0x000000cc, + 0x000000ed, 0x000000cd, + 0x000000ee, 0x000000ce, + 0x000000ef, 0x000000cf, + 0x000000f0, 0x000000d0, + 0x000000f1, 0x000000d1, + 0x000000f2, 0x000000d2, + 0x000000f3, 0x000000d3, + 0x000000f4, 0x000000d4, + 0x000000f5, 0x000000d5, + 0x000000f6, 0x000000d6, + 0x000000f8, 0x000000d8, + 0x000000f9, 0x000000d9, + 0x000000fa, 0x000000da, + 0x000000fb, 0x000000db, + 0x000000fc, 0x000000dc, + 0x000000fd, 0x000000dd, + 0x000000fe, 0x000000de, + 0x000000ff, 0x00000178, + 0x00000101, 0x00000100, + 0x00000103, 0x00000102, + 0x00000105, 0x00000104, + 0x00000107, 0x00000106, + 0x00000109, 0x00000108, + 0x0000010b, 0x0000010a, + 0x0000010d, 0x0000010c, + 0x0000010f, 0x0000010e, + 0x00000111, 0x00000110, + 0x00000113, 0x00000112, + 0x00000115, 0x00000114, + 0x00000117, 0x00000116, + 0x00000119, 0x00000118, + 0x0000011b, 0x0000011a, + 0x0000011d, 0x0000011c, + 0x0000011f, 0x0000011e, + 0x00000121, 0x00000120, + 0x00000123, 0x00000122, + 0x00000125, 0x00000124, + 0x00000127, 0x00000126, + 0x00000129, 0x00000128, + 0x0000012b, 0x0000012a, + 0x0000012d, 0x0000012c, + 0x0000012f, 0x0000012e, + 0x00000131, 0x00000049, + 0x00000133, 0x00000132, + 0x00000135, 0x00000134, + 0x00000137, 0x00000136, + 0x0000013a, 0x00000139, + 0x0000013c, 0x0000013b, + 0x0000013e, 0x0000013d, + 0x00000140, 0x0000013f, + 0x00000142, 0x00000141, + 0x00000144, 0x00000143, + 0x00000146, 0x00000145, + 0x00000148, 0x00000147, + 0x0000014b, 0x0000014a, + 0x0000014d, 0x0000014c, + 0x0000014f, 0x0000014e, + 0x00000151, 0x00000150, + 0x00000153, 0x00000152, + 0x00000155, 0x00000154, + 0x00000157, 0x00000156, + 0x00000159, 0x00000158, + 0x0000015b, 0x0000015a, + 0x0000015d, 0x0000015c, + 0x0000015f, 0x0000015e, + 0x00000161, 0x00000160, + 0x00000163, 0x00000162, + 0x00000165, 0x00000164, + 0x00000167, 0x00000166, + 0x00000169, 0x00000168, + 0x0000016b, 0x0000016a, + 0x0000016d, 0x0000016c, + 0x0000016f, 0x0000016e, + 0x00000171, 0x00000170, + 0x00000173, 0x00000172, + 0x00000175, 0x00000174, + 0x00000177, 0x00000176, + 0x0000017a, 0x00000179, + 0x0000017c, 0x0000017b, + 0x0000017e, 0x0000017d, + 0x0000017f, 0x00000053, + 0x00000183, 0x00000182, + 0x00000185, 0x00000184, + 0x00000188, 0x00000187, + 0x0000018c, 0x0000018b, + 0x00000192, 0x00000191, + 0x00000195, 0x000001f6, + 0x00000199, 0x00000198, + 0x0000019e, 0x00000220, + 0x000001a1, 0x000001a0, + 0x000001a3, 0x000001a2, + 0x000001a5, 0x000001a4, + 0x000001a8, 0x000001a7, + 0x000001ad, 0x000001ac, + 0x000001b0, 0x000001af, + 0x000001b4, 0x000001b3, + 0x000001b6, 0x000001b5, + 0x000001b9, 0x000001b8, + 0x000001bd, 0x000001bc, + 0x000001bf, 0x000001f7, + 0x000001c6, 0x000001c4, + 0x000001c9, 0x000001c7, + 0x000001cc, 0x000001ca, + 0x000001ce, 0x000001cd, + 0x000001d0, 0x000001cf, + 0x000001d2, 0x000001d1, + 0x000001d4, 0x000001d3, + 0x000001d6, 0x000001d5, + 0x000001d8, 0x000001d7, + 0x000001da, 0x000001d9, + 0x000001dc, 0x000001db, + 0x000001dd, 0x0000018e, + 0x000001df, 0x000001de, + 0x000001e1, 0x000001e0, + 0x000001e3, 0x000001e2, + 0x000001e5, 0x000001e4, + 0x000001e7, 0x000001e6, + 0x000001e9, 0x000001e8, + 0x000001eb, 0x000001ea, + 0x000001ed, 0x000001ec, + 0x000001ef, 0x000001ee, + 0x000001f3, 0x000001f1, + 0x000001f5, 0x000001f4, + 0x000001f9, 0x000001f8, + 0x000001fb, 0x000001fa, + 0x000001fd, 0x000001fc, + 0x000001ff, 0x000001fe, + 0x00000201, 0x00000200, + 0x00000203, 0x00000202, + 0x00000205, 0x00000204, + 0x00000207, 0x00000206, + 0x00000209, 0x00000208, + 0x0000020b, 0x0000020a, + 0x0000020d, 0x0000020c, + 0x0000020f, 0x0000020e, + 0x00000211, 0x00000210, + 0x00000213, 0x00000212, + 0x00000215, 0x00000214, + 0x00000217, 0x00000216, + 0x00000219, 0x00000218, + 0x0000021b, 0x0000021a, + 0x0000021d, 0x0000021c, + 0x0000021f, 0x0000021e, + 0x00000223, 0x00000222, + 0x00000225, 0x00000224, + 0x00000227, 0x00000226, + 0x00000229, 0x00000228, + 0x0000022b, 0x0000022a, + 0x0000022d, 0x0000022c, + 0x0000022f, 0x0000022e, + 0x00000231, 0x00000230, + 0x00000233, 0x00000232, + 0x00000253, 0x00000181, + 0x00000254, 0x00000186, + 0x00000256, 0x00000189, + 0x00000257, 0x0000018a, + 0x00000259, 0x0000018f, + 0x0000025b, 0x00000190, + 0x00000260, 0x00000193, + 0x00000263, 0x00000194, + 0x00000268, 0x00000197, + 0x00000269, 0x00000196, + 0x0000026f, 0x0000019c, + 0x00000272, 0x0000019d, + 0x00000275, 0x0000019f, + 0x00000280, 0x000001a6, + 0x00000283, 0x000001a9, + 0x00000288, 0x000001ae, + 0x0000028a, 0x000001b1, + 0x0000028b, 0x000001b2, + 0x00000292, 0x000001b7, + 0x00000345, 0x00000399, + 0x000003ac, 0x00000386, + 0x000003ad, 0x00000388, + 0x000003ae, 0x00000389, + 0x000003af, 0x0000038a, + 0x000003b1, 0x00000391, + 0x000003b2, 0x00000392, + 0x000003b3, 0x00000393, + 0x000003b4, 0x00000394, + 0x000003b5, 0x00000395, + 0x000003b6, 0x00000396, + 0x000003b7, 0x00000397, + 0x000003b8, 0x00000398, + 0x000003b9, 0x00000399, + 0x000003ba, 0x0000039a, + 0x000003bb, 0x0000039b, + 0x000003bc, 0x0000039c, + 0x000003bd, 0x0000039d, + 0x000003be, 0x0000039e, + 0x000003bf, 0x0000039f, + 0x000003c0, 0x000003a0, + 0x000003c1, 0x000003a1, + 0x000003c2, 0x000003a3, + 0x000003c3, 0x000003a3, + 0x000003c4, 0x000003a4, + 0x000003c5, 0x000003a5, + 0x000003c6, 0x000003a6, + 0x000003c7, 0x000003a7, + 0x000003c8, 0x000003a8, + 0x000003c9, 0x000003a9, + 0x000003ca, 0x000003aa, + 0x000003cb, 0x000003ab, + 0x000003cc, 0x0000038c, + 0x000003cd, 0x0000038e, + 0x000003ce, 0x0000038f, + 0x000003d0, 0x00000392, + 0x000003d1, 0x00000398, + 0x000003d5, 0x000003a6, + 0x000003d6, 0x000003a0, + 0x000003d9, 0x000003d8, + 0x000003db, 0x000003da, + 0x000003dd, 0x000003dc, + 0x000003df, 0x000003de, + 0x000003e1, 0x000003e0, + 0x000003e3, 0x000003e2, + 0x000003e5, 0x000003e4, + 0x000003e7, 0x000003e6, + 0x000003e9, 0x000003e8, + 0x000003eb, 0x000003ea, + 0x000003ed, 0x000003ec, + 0x000003ef, 0x000003ee, + 0x000003f0, 0x0000039a, + 0x000003f1, 0x000003a1, + 0x000003f2, 0x000003a3, + 0x000003f5, 0x00000395, + 0x00000430, 0x00000410, + 0x00000431, 0x00000411, + 0x00000432, 0x00000412, + 0x00000433, 0x00000413, + 0x00000434, 0x00000414, + 0x00000435, 0x00000415, + 0x00000436, 0x00000416, + 0x00000437, 0x00000417, + 0x00000438, 0x00000418, + 0x00000439, 0x00000419, + 0x0000043a, 0x0000041a, + 0x0000043b, 0x0000041b, + 0x0000043c, 0x0000041c, + 0x0000043d, 0x0000041d, + 0x0000043e, 0x0000041e, + 0x0000043f, 0x0000041f, + 0x00000440, 0x00000420, + 0x00000441, 0x00000421, + 0x00000442, 0x00000422, + 0x00000443, 0x00000423, + 0x00000444, 0x00000424, + 0x00000445, 0x00000425, + 0x00000446, 0x00000426, + 0x00000447, 0x00000427, + 0x00000448, 0x00000428, + 0x00000449, 0x00000429, + 0x0000044a, 0x0000042a, + 0x0000044b, 0x0000042b, + 0x0000044c, 0x0000042c, + 0x0000044d, 0x0000042d, + 0x0000044e, 0x0000042e, + 0x0000044f, 0x0000042f, + 0x00000450, 0x00000400, + 0x00000451, 0x00000401, + 0x00000452, 0x00000402, + 0x00000453, 0x00000403, + 0x00000454, 0x00000404, + 0x00000455, 0x00000405, + 0x00000456, 0x00000406, + 0x00000457, 0x00000407, + 0x00000458, 0x00000408, + 0x00000459, 0x00000409, + 0x0000045a, 0x0000040a, + 0x0000045b, 0x0000040b, + 0x0000045c, 0x0000040c, + 0x0000045d, 0x0000040d, + 0x0000045e, 0x0000040e, + 0x0000045f, 0x0000040f, + 0x00000461, 0x00000460, + 0x00000463, 0x00000462, + 0x00000465, 0x00000464, + 0x00000467, 0x00000466, + 0x00000469, 0x00000468, + 0x0000046b, 0x0000046a, + 0x0000046d, 0x0000046c, + 0x0000046f, 0x0000046e, + 0x00000471, 0x00000470, + 0x00000473, 0x00000472, + 0x00000475, 0x00000474, + 0x00000477, 0x00000476, + 0x00000479, 0x00000478, + 0x0000047b, 0x0000047a, + 0x0000047d, 0x0000047c, + 0x0000047f, 0x0000047e, + 0x00000481, 0x00000480, + 0x0000048b, 0x0000048a, + 0x0000048d, 0x0000048c, + 0x0000048f, 0x0000048e, + 0x00000491, 0x00000490, + 0x00000493, 0x00000492, + 0x00000495, 0x00000494, + 0x00000497, 0x00000496, + 0x00000499, 0x00000498, + 0x0000049b, 0x0000049a, + 0x0000049d, 0x0000049c, + 0x0000049f, 0x0000049e, + 0x000004a1, 0x000004a0, + 0x000004a3, 0x000004a2, + 0x000004a5, 0x000004a4, + 0x000004a7, 0x000004a6, + 0x000004a9, 0x000004a8, + 0x000004ab, 0x000004aa, + 0x000004ad, 0x000004ac, + 0x000004af, 0x000004ae, + 0x000004b1, 0x000004b0, + 0x000004b3, 0x000004b2, + 0x000004b5, 0x000004b4, + 0x000004b7, 0x000004b6, + 0x000004b9, 0x000004b8, + 0x000004bb, 0x000004ba, + 0x000004bd, 0x000004bc, + 0x000004bf, 0x000004be, + 0x000004c2, 0x000004c1, + 0x000004c4, 0x000004c3, + 0x000004c6, 0x000004c5, + 0x000004c8, 0x000004c7, + 0x000004ca, 0x000004c9, + 0x000004cc, 0x000004cb, + 0x000004ce, 0x000004cd, + 0x000004d1, 0x000004d0, + 0x000004d3, 0x000004d2, + 0x000004d5, 0x000004d4, + 0x000004d7, 0x000004d6, + 0x000004d9, 0x000004d8, + 0x000004db, 0x000004da, + 0x000004dd, 0x000004dc, + 0x000004df, 0x000004de, + 0x000004e1, 0x000004e0, + 0x000004e3, 0x000004e2, + 0x000004e5, 0x000004e4, + 0x000004e7, 0x000004e6, + 0x000004e9, 0x000004e8, + 0x000004eb, 0x000004ea, + 0x000004ed, 0x000004ec, + 0x000004ef, 0x000004ee, + 0x000004f1, 0x000004f0, + 0x000004f3, 0x000004f2, + 0x000004f5, 0x000004f4, + 0x000004f9, 0x000004f8, + 0x00000501, 0x00000500, + 0x00000503, 0x00000502, + 0x00000505, 0x00000504, + 0x00000507, 0x00000506, + 0x00000509, 0x00000508, + 0x0000050b, 0x0000050a, + 0x0000050d, 0x0000050c, + 0x0000050f, 0x0000050e, + 0x00000561, 0x00000531, + 0x00000562, 0x00000532, + 0x00000563, 0x00000533, + 0x00000564, 0x00000534, + 0x00000565, 0x00000535, + 0x00000566, 0x00000536, + 0x00000567, 0x00000537, + 0x00000568, 0x00000538, + 0x00000569, 0x00000539, + 0x0000056a, 0x0000053a, + 0x0000056b, 0x0000053b, + 0x0000056c, 0x0000053c, + 0x0000056d, 0x0000053d, + 0x0000056e, 0x0000053e, + 0x0000056f, 0x0000053f, + 0x00000570, 0x00000540, + 0x00000571, 0x00000541, + 0x00000572, 0x00000542, + 0x00000573, 0x00000543, + 0x00000574, 0x00000544, + 0x00000575, 0x00000545, + 0x00000576, 0x00000546, + 0x00000577, 0x00000547, + 0x00000578, 0x00000548, + 0x00000579, 0x00000549, + 0x0000057a, 0x0000054a, + 0x0000057b, 0x0000054b, + 0x0000057c, 0x0000054c, + 0x0000057d, 0x0000054d, + 0x0000057e, 0x0000054e, + 0x0000057f, 0x0000054f, + 0x00000580, 0x00000550, + 0x00000581, 0x00000551, + 0x00000582, 0x00000552, + 0x00000583, 0x00000553, + 0x00000584, 0x00000554, + 0x00000585, 0x00000555, + 0x00000586, 0x00000556, + 0x00001e01, 0x00001e00, + 0x00001e03, 0x00001e02, + 0x00001e05, 0x00001e04, + 0x00001e07, 0x00001e06, + 0x00001e09, 0x00001e08, + 0x00001e0b, 0x00001e0a, + 0x00001e0d, 0x00001e0c, + 0x00001e0f, 0x00001e0e, + 0x00001e11, 0x00001e10, + 0x00001e13, 0x00001e12, + 0x00001e15, 0x00001e14, + 0x00001e17, 0x00001e16, + 0x00001e19, 0x00001e18, + 0x00001e1b, 0x00001e1a, + 0x00001e1d, 0x00001e1c, + 0x00001e1f, 0x00001e1e, + 0x00001e21, 0x00001e20, + 0x00001e23, 0x00001e22, + 0x00001e25, 0x00001e24, + 0x00001e27, 0x00001e26, + 0x00001e29, 0x00001e28, + 0x00001e2b, 0x00001e2a, + 0x00001e2d, 0x00001e2c, + 0x00001e2f, 0x00001e2e, + 0x00001e31, 0x00001e30, + 0x00001e33, 0x00001e32, + 0x00001e35, 0x00001e34, + 0x00001e37, 0x00001e36, + 0x00001e39, 0x00001e38, + 0x00001e3b, 0x00001e3a, + 0x00001e3d, 0x00001e3c, + 0x00001e3f, 0x00001e3e, + 0x00001e41, 0x00001e40, + 0x00001e43, 0x00001e42, + 0x00001e45, 0x00001e44, + 0x00001e47, 0x00001e46, + 0x00001e49, 0x00001e48, + 0x00001e4b, 0x00001e4a, + 0x00001e4d, 0x00001e4c, + 0x00001e4f, 0x00001e4e, + 0x00001e51, 0x00001e50, + 0x00001e53, 0x00001e52, + 0x00001e55, 0x00001e54, + 0x00001e57, 0x00001e56, + 0x00001e59, 0x00001e58, + 0x00001e5b, 0x00001e5a, + 0x00001e5d, 0x00001e5c, + 0x00001e5f, 0x00001e5e, + 0x00001e61, 0x00001e60, + 0x00001e63, 0x00001e62, + 0x00001e65, 0x00001e64, + 0x00001e67, 0x00001e66, + 0x00001e69, 0x00001e68, + 0x00001e6b, 0x00001e6a, + 0x00001e6d, 0x00001e6c, + 0x00001e6f, 0x00001e6e, + 0x00001e71, 0x00001e70, + 0x00001e73, 0x00001e72, + 0x00001e75, 0x00001e74, + 0x00001e77, 0x00001e76, + 0x00001e79, 0x00001e78, + 0x00001e7b, 0x00001e7a, + 0x00001e7d, 0x00001e7c, + 0x00001e7f, 0x00001e7e, + 0x00001e81, 0x00001e80, + 0x00001e83, 0x00001e82, + 0x00001e85, 0x00001e84, + 0x00001e87, 0x00001e86, + 0x00001e89, 0x00001e88, + 0x00001e8b, 0x00001e8a, + 0x00001e8d, 0x00001e8c, + 0x00001e8f, 0x00001e8e, + 0x00001e91, 0x00001e90, + 0x00001e93, 0x00001e92, + 0x00001e95, 0x00001e94, + 0x00001e9b, 0x00001e60, + 0x00001ea1, 0x00001ea0, + 0x00001ea3, 0x00001ea2, + 0x00001ea5, 0x00001ea4, + 0x00001ea7, 0x00001ea6, + 0x00001ea9, 0x00001ea8, + 0x00001eab, 0x00001eaa, + 0x00001ead, 0x00001eac, + 0x00001eaf, 0x00001eae, + 0x00001eb1, 0x00001eb0, + 0x00001eb3, 0x00001eb2, + 0x00001eb5, 0x00001eb4, + 0x00001eb7, 0x00001eb6, + 0x00001eb9, 0x00001eb8, + 0x00001ebb, 0x00001eba, + 0x00001ebd, 0x00001ebc, + 0x00001ebf, 0x00001ebe, + 0x00001ec1, 0x00001ec0, + 0x00001ec3, 0x00001ec2, + 0x00001ec5, 0x00001ec4, + 0x00001ec7, 0x00001ec6, + 0x00001ec9, 0x00001ec8, + 0x00001ecb, 0x00001eca, + 0x00001ecd, 0x00001ecc, + 0x00001ecf, 0x00001ece, + 0x00001ed1, 0x00001ed0, + 0x00001ed3, 0x00001ed2, + 0x00001ed5, 0x00001ed4, + 0x00001ed7, 0x00001ed6, + 0x00001ed9, 0x00001ed8, + 0x00001edb, 0x00001eda, + 0x00001edd, 0x00001edc, + 0x00001edf, 0x00001ede, + 0x00001ee1, 0x00001ee0, + 0x00001ee3, 0x00001ee2, + 0x00001ee5, 0x00001ee4, + 0x00001ee7, 0x00001ee6, + 0x00001ee9, 0x00001ee8, + 0x00001eeb, 0x00001eea, + 0x00001eed, 0x00001eec, + 0x00001eef, 0x00001eee, + 0x00001ef1, 0x00001ef0, + 0x00001ef3, 0x00001ef2, + 0x00001ef5, 0x00001ef4, + 0x00001ef7, 0x00001ef6, + 0x00001ef9, 0x00001ef8, + 0x00001f00, 0x00001f08, + 0x00001f01, 0x00001f09, + 0x00001f02, 0x00001f0a, + 0x00001f03, 0x00001f0b, + 0x00001f04, 0x00001f0c, + 0x00001f05, 0x00001f0d, + 0x00001f06, 0x00001f0e, + 0x00001f07, 0x00001f0f, + 0x00001f10, 0x00001f18, + 0x00001f11, 0x00001f19, + 0x00001f12, 0x00001f1a, + 0x00001f13, 0x00001f1b, + 0x00001f14, 0x00001f1c, + 0x00001f15, 0x00001f1d, + 0x00001f20, 0x00001f28, + 0x00001f21, 0x00001f29, + 0x00001f22, 0x00001f2a, + 0x00001f23, 0x00001f2b, + 0x00001f24, 0x00001f2c, + 0x00001f25, 0x00001f2d, + 0x00001f26, 0x00001f2e, + 0x00001f27, 0x00001f2f, + 0x00001f30, 0x00001f38, + 0x00001f31, 0x00001f39, + 0x00001f32, 0x00001f3a, + 0x00001f33, 0x00001f3b, + 0x00001f34, 0x00001f3c, + 0x00001f35, 0x00001f3d, + 0x00001f36, 0x00001f3e, + 0x00001f37, 0x00001f3f, + 0x00001f40, 0x00001f48, + 0x00001f41, 0x00001f49, + 0x00001f42, 0x00001f4a, + 0x00001f43, 0x00001f4b, + 0x00001f44, 0x00001f4c, + 0x00001f45, 0x00001f4d, + 0x00001f51, 0x00001f59, + 0x00001f53, 0x00001f5b, + 0x00001f55, 0x00001f5d, + 0x00001f57, 0x00001f5f, + 0x00001f60, 0x00001f68, + 0x00001f61, 0x00001f69, + 0x00001f62, 0x00001f6a, + 0x00001f63, 0x00001f6b, + 0x00001f64, 0x00001f6c, + 0x00001f65, 0x00001f6d, + 0x00001f66, 0x00001f6e, + 0x00001f67, 0x00001f6f, + 0x00001f70, 0x00001fba, + 0x00001f71, 0x00001fbb, + 0x00001f72, 0x00001fc8, + 0x00001f73, 0x00001fc9, + 0x00001f74, 0x00001fca, + 0x00001f75, 0x00001fcb, + 0x00001f76, 0x00001fda, + 0x00001f77, 0x00001fdb, + 0x00001f78, 0x00001ff8, + 0x00001f79, 0x00001ff9, + 0x00001f7a, 0x00001fea, + 0x00001f7b, 0x00001feb, + 0x00001f7c, 0x00001ffa, + 0x00001f7d, 0x00001ffb, + 0x00001f80, 0x00001f88, + 0x00001f81, 0x00001f89, + 0x00001f82, 0x00001f8a, + 0x00001f83, 0x00001f8b, + 0x00001f84, 0x00001f8c, + 0x00001f85, 0x00001f8d, + 0x00001f86, 0x00001f8e, + 0x00001f87, 0x00001f8f, + 0x00001f90, 0x00001f98, + 0x00001f91, 0x00001f99, + 0x00001f92, 0x00001f9a, + 0x00001f93, 0x00001f9b, + 0x00001f94, 0x00001f9c, + 0x00001f95, 0x00001f9d, + 0x00001f96, 0x00001f9e, + 0x00001f97, 0x00001f9f, + 0x00001fa0, 0x00001fa8, + 0x00001fa1, 0x00001fa9, + 0x00001fa2, 0x00001faa, + 0x00001fa3, 0x00001fab, + 0x00001fa4, 0x00001fac, + 0x00001fa5, 0x00001fad, + 0x00001fa6, 0x00001fae, + 0x00001fa7, 0x00001faf, + 0x00001fb0, 0x00001fb8, + 0x00001fb1, 0x00001fb9, + 0x00001fb3, 0x00001fbc, + 0x00001fbe, 0x00000399, + 0x00001fc3, 0x00001fcc, + 0x00001fd0, 0x00001fd8, + 0x00001fd1, 0x00001fd9, + 0x00001fe0, 0x00001fe8, + 0x00001fe1, 0x00001fe9, + 0x00001fe5, 0x00001fec, + 0x00001ff3, 0x00001ffc, + 0x00002170, 0x00002160, + 0x00002171, 0x00002161, + 0x00002172, 0x00002162, + 0x00002173, 0x00002163, + 0x00002174, 0x00002164, + 0x00002175, 0x00002165, + 0x00002176, 0x00002166, + 0x00002177, 0x00002167, + 0x00002178, 0x00002168, + 0x00002179, 0x00002169, + 0x0000217a, 0x0000216a, + 0x0000217b, 0x0000216b, + 0x0000217c, 0x0000216c, + 0x0000217d, 0x0000216d, + 0x0000217e, 0x0000216e, + 0x0000217f, 0x0000216f, + 0x000024d0, 0x000024b6, + 0x000024d1, 0x000024b7, + 0x000024d2, 0x000024b8, + 0x000024d3, 0x000024b9, + 0x000024d4, 0x000024ba, + 0x000024d5, 0x000024bb, + 0x000024d6, 0x000024bc, + 0x000024d7, 0x000024bd, + 0x000024d8, 0x000024be, + 0x000024d9, 0x000024bf, + 0x000024da, 0x000024c0, + 0x000024db, 0x000024c1, + 0x000024dc, 0x000024c2, + 0x000024dd, 0x000024c3, + 0x000024de, 0x000024c4, + 0x000024df, 0x000024c5, + 0x000024e0, 0x000024c6, + 0x000024e1, 0x000024c7, + 0x000024e2, 0x000024c8, + 0x000024e3, 0x000024c9, + 0x000024e4, 0x000024ca, + 0x000024e5, 0x000024cb, + 0x000024e6, 0x000024cc, + 0x000024e7, 0x000024cd, + 0x000024e8, 0x000024ce, + 0x000024e9, 0x000024cf, + 0x0000ff41, 0x0000ff21, + 0x0000ff42, 0x0000ff22, + 0x0000ff43, 0x0000ff23, + 0x0000ff44, 0x0000ff24, + 0x0000ff45, 0x0000ff25, + 0x0000ff46, 0x0000ff26, + 0x0000ff47, 0x0000ff27, + 0x0000ff48, 0x0000ff28, + 0x0000ff49, 0x0000ff29, + 0x0000ff4a, 0x0000ff2a, + 0x0000ff4b, 0x0000ff2b, + 0x0000ff4c, 0x0000ff2c, + 0x0000ff4d, 0x0000ff2d, + 0x0000ff4e, 0x0000ff2e, + 0x0000ff4f, 0x0000ff2f, + 0x0000ff50, 0x0000ff30, + 0x0000ff51, 0x0000ff31, + 0x0000ff52, 0x0000ff32, + 0x0000ff53, 0x0000ff33, + 0x0000ff54, 0x0000ff34, + 0x0000ff55, 0x0000ff35, + 0x0000ff56, 0x0000ff36, + 0x0000ff57, 0x0000ff37, + 0x0000ff58, 0x0000ff38, + 0x0000ff59, 0x0000ff39, + 0x0000ff5a, 0x0000ff3a, + 0x00010428, 0x00010400, + 0x00010429, 0x00010401, + 0x0001042a, 0x00010402, + 0x0001042b, 0x00010403, + 0x0001042c, 0x00010404, + 0x0001042d, 0x00010405, + 0x0001042e, 0x00010406, + 0x0001042f, 0x00010407, + 0x00010430, 0x00010408, + 0x00010431, 0x00010409, + 0x00010432, 0x0001040a, + 0x00010433, 0x0001040b, + 0x00010434, 0x0001040c, + 0x00010435, 0x0001040d, + 0x00010436, 0x0001040e, + 0x00010437, 0x0001040f, + 0x00010438, 0x00010410, + 0x00010439, 0x00010411, + 0x0001043a, 0x00010412, + 0x0001043b, 0x00010413, + 0x0001043c, 0x00010414, + 0x0001043d, 0x00010415, + 0x0001043e, 0x00010416, + 0x0001043f, 0x00010417, + 0x00010440, 0x00010418, + 0x00010441, 0x00010419, + 0x00010442, 0x0001041a, + 0x00010443, 0x0001041b, + 0x00010444, 0x0001041c, + 0x00010445, 0x0001041d, + 0x00010446, 0x0001041e, + 0x00010447, 0x0001041f, + 0x00010448, 0x00010420, + 0x00010449, 0x00010421, + 0x0001044a, 0x00010422, + 0x0001044b, 0x00010423, + 0x0001044c, 0x00010424, + 0x0001044d, 0x00010425, +}; + +#endif /*UTF8TABLES_H_*/ diff --git a/doc/apache_request_cycle-modsecurity.jpg b/doc/apache_request_cycle-modsecurity.jpg new file mode 100644 index 0000000000000000000000000000000000000000..390c649350e15d4a359ca2be8ca15b4a963cc96b GIT binary patch literal 92271 zcmeFZ2UrwK);Hcb1j&NrG$0@-Ac7#70TED90ZEdxBmqg183X~zf&z*HgOU^h$r&Vr zh~yjxkQ`=+0}M0&_TIhsdiTHK?tc63x8M6LJpFX{bamCK>Z()c{LZfmKZ2hDPTf$s zt^yDc5CC4_KY$+xlz@}O#3aN-CrL<1NJ&qUQP5FRkdsp|)1IcLV`qVKu(PnSaq?W? z<2)nC&Bn$raZd1}h?tldlut@dQdIWBB{9+OnGleYl2VXUFi}!6iE^=ViT=ZX_)h@M zNeGJQEQH_;aDs*aLPLOW2A}{yKmnd|K0-^`Yu9gRY3u0f-PJd+w6eZuV{2#c=I-&()63f@_;E;R*pu*x z_-D@(5|duMOn&n=BQq;I=iU3F;*!#`@`}o;#-`?$*0%PJ&wc#^gG0k3qhrX~x%qDk zi%ZKZ=&kLY-MxLx!QuCM5de^%tMzNm{;Xa!V7*Qd5<&<`zSoQ3geQ1FXb6e8M2Kk> zHA&1}PM;Bdbdv5$TzX*xDfgv2D0&OmUNQzAF(fbgd)0ob*&nM|&_7kPUn}-oy~Y3v z2m$!ho6hE2hW&3Tz~enCKGegz_}O zPPR4rOxHH%{Woc->0_q?JYY(RT|$um&afP&LDl1wE8(lv@Jq(E0G+1te~+zs+(91-Hjin- z!AoFR$SXV$)BC%-VMXQtX7GQZ4F;w-20X||#T|^*)>`M(YZ#8!;}Y1IES|H8@Ia^L z3hc-7;Z4(9Y-pR~5KBDJCtv_9{n9Vb#p8i@@cmozFNF`2@PK;{3CRyb@GY|baMBc4 z$9mAKz#z|v2inVpk3F3i9Ln>#k#KCJD;^krh`U$q^Kb3rzsUaQ=kw81nKnSYloJgT zq(L%wa3+nzz3WPI)BDkhFYma`2Ppwvl+JnyoUv5O#F{4lK{MLqz}er?{aTRK)0pbp z4#<<6`E#$k*qb8-Jj}escc~lX81{yn@W7a7lIV?L?!d)Nz^9Z>Q-SE;c(CDtsQP&l zM?7F|EP)5q%=3dP@xYJ6_70}LS*bCAzJ8cxWFk^o_hQ&+wIE|YmGq$o@g#ktm*K2+ z!4oWfu2+N_agnsm%SA)k@mD7wwMjC4b?GmKQr7VlG>Z+qbWiMWiF;z6y)Cgx0k0C- zhZ_JJOIhLEqD)Qi9*FA6#x{nQO?BM}|Aq zbWK^TQ#`1c0}fLYI)z)hPj$VK2p7VVy6}Z5u^F)r(mp3)Epz-TD%V!;1MI#(9~%2% zbTyebzu?~DTDb_RcEy;sC*_i2JM2bPOcB48*=L_quKWZ8TCyX}K`;@&Cal!rR_6BU zFI)ThSQ{trw!T1i<%_qNr^8RrA5C982&hZY(jMUGyir|M5@<4^1i8gtbd9d_(I=8J zpL>DAnnodQv3VuqFlxBN-7cFP2R9y(F=y)e_)oO!pFWYuOg$NW-fpy+spntRpAG`hyu4SCB(weLd--=Nd3`o*i^u3Vh?lJhiQ{Z(%O>p2Bd zeF5i;uFoEsQh7x-?kCd^&cN<@-=ocly40$`@uIz3a<|J7W7*n^iM)&ENZqsOu`N%t z7Ad?4?^@Wh{5+*faJR>LV8H*oY3Pwb~TB z0FyTrv0?QzTxjfAr=dQpuOV|BS6rIV`LZ<;rh|aZo2jMaJp@L0Agq2~YPS1`tPKxj z=$7{A!H}B=R9?ln#zH)>OrHn1|7rpKFPO=7d^^V-PEzdO`Jfr|VNxK~`N`C270y-N zQH~vgfnK8mtY9oDyvJ#J`z?+^^>O`@g!4fUiH^~9jM%l^Zt^LGcIIZQELESdU!V3# zG&`S^PH?mz32tCUP(Q=MkmHfv%ng~cRtc|YDIRwDr)1a_+DRKRXi)Ij6AN_g*!fXs zdCeXf<3`KRN$`gu#3wlamjZ7c-U`-pFFq?MN%F8CoH zNP(h?WO?y`Vm170p!ClL#eFYm{C`V9iBOsvo;HX<8Fm#>SYJAjmpI#Joyf4%+0#Rm z%>O2k?C%^>zgOvZ@cJUW=bfW6FwjqhmYvp0;lg02UWw~4}MB-C+rNK zs~E}zGF+w7etMESu6>>iILN-6ysDtqO=)oDA*T3tKTmm^4VO~fE?3x`;n>Z66S`iU zU<&h?)CZeTCiZ|Wew$lOJs}<4_w|a5yiPZj8^lDz#Y0z9IK*N)u*0nM@=LPVkyh_6 z{r(!hw|1UBEnTIE=@0TpNNz@b^)9T?Q<5(e?hApk>c*(-Ff0rOzlDxT@)hLZ8g+h< z95hiZ+gHijpD)?@5J%-Zls8y`9&VMBxQ;fuaNnYrc17UyIc@Kk+LfO;7kR@9+GWVr z*XpRf&NpcrE|p|ivL3`W2yURcZKO`#hRH?@qSXVja&wI3NqWWiD#~ZiA)mH!nr>{c zs}?Rli@FymTi!@xdq~|3ebUp;Th+UMzwt(}`-d|SiWJu?Q3WQE8eI+}qlrnm=oc zcIDa#|E)!Y>}z=GPM$Nxr~?NbnmU5@cE4HQhoo!1kNZ@zl5WvA@}EB<5QO;491HY& z#1eV=8uhI2I80vVw!Tj?+9#VH27#Ef#hgoJMyZ4#&sIEBD|2ykiU|`;dTQ043=W9 zOA)*t$htoNT_6QAi- z^=!~@uy>lDL@LMvCvxVdhic{9ko%z}L9&ei&-)_$qaBNH5c99s#m86DsQkopy`0(5+j>O(oiO7qP+H_7WqyF3pU0>y9? zBe!uJ1G4HqCu`6|Yf1M-qEwhdm<|(RR|FVm`|R&vuc6M^omQkmn79xok=+pRd;O6; zcW6xz(eJ+Mz-lc(RH8;__WJ4ji!eoPabb#OgR;^r`~9+Y-i;SuhVpr=PZ~0}laL@* z71-p{Q2Wh?Y0>V}G+y1t#WlFjP6I>zMja)N`KKaZsa+pPuXJgb<`WA=ImX=xjTPX1^ixzG(ZG06CFs<>i2$a=R z8`?Q42&@tct?-a}>yjg$!7$|ZWNbc+S93Cqv>h6RW5jZqO>tm`DUTLi46#jNx6QL#L{d4=`lH)@iYld`pEG)KtX`H^2G>g+ zSfxVWo+yfZd4b3C*#pj`j)NHLfRr3a<6@6>uh`L~nm%fWgR>tu&{zJXBt`F%@E0mq z(%sgR>^?i<{g|>9b$UM~)YlhPj;*B`@=@ha?Y1Y6Uw{3=y7-WfC=kGrOjR#~dPCHq zr1V4$mSA^_SvB?&fh1ysdQLTmT+#oFt4otvF$GOTnkwq{BgB%Yk4l>Lw{a5z@d(MNqzMr zY9ZP=V>yoL!+HZvx@)s_B!@a*ye;I5JXww@t)GGpz(4o^Sl{k6slQtV4H1J=8L#L` z8y72G$dpKPy%{w=%`?_zXS$)t&04I)}h@n8~U+0^jF)#Hj zHC!ehm=q&uz=BSMVJ_&mHNmC%e?VR|h+;$Vz?M)a9xxt1NM2ukf-%JdXC~@*C+lD4 zPyO8)?AH?i&P?~uq?0U&Fx}!cPE&?`t|>smnR`{@%0tINzFeAIwhhj0BscbvP4*hpS?z9C;oh|$ztCMB#Q&VM}n^+OK z>7zjcI<{n&no`s9ps2U9Qp<f@nTSzl6QW%#b|4EDly zR1e8(&{B&+EoQH(V)?tNd;&_BJ4-*E{}kL4(d^8yd_9*^Xqu5{1~L^W+5IOWzT(be z<@##QxmfZhDn4XhoT_`)O6fJ+X1bf~dDH~jmN{NZIOSV1xJt6|59%l3?eDVT!(4{$ zfTl9tPlw)DQwI0;Qh229PG50W>2{?e;6&N)L$^^`}iLxtjZm9UAIl zn|~^{4>Tp`K2z@#$p^}|;pl9_7hY|8BwUH-F)`w<|6R93WWmXYJz8kDwO$ z|21sRAN>)5wu#nilAcP-PUxtXq#wG9vpUDO9}12GJn*wLZ~r9R&I&)|3;bXB+lI_* zO$8_ndjn(m*2}GF)!X*uvxm~dSy*0HKXQ8#OMN&CNG8xw-_O-UN?@N1O@r>Q?Oz1% z-Wjd37^emdzSD1rsk^^Yf$ai}-+W|k#WCpe*Kze*yEI&L(p4epC%fLohdt{f1AoU7 z-IhJNQ~gpAt1AlQcuvrx3A$NWUP17)Z6c3dosT?d;7hFruyXNA*r3;q1K8@q#wdJ; zlmi^d0%=D!kyb~^XX8%pCTTxSJNjnUwyK&mM+*P8s#FHjAndZ+a93~k5d6+Wv^QnM zJn>R*EI*txWR0_Z-+Jmu!a8WTq0RJ0Bbqm+mLttZ2v_PTEAW1KJUyuGGv%vx-z1BR z58zZge&%=}ULAzOhxtKeVxd7SR!`@rP8?D7rJl+eR&2lpOXEPq9u-MAjWJ5LiBH?I z>?S?I%Gu@VUm{m~fo<6)CYyPxcz8+`X+k}FX)cc%ITbFx`6LxiZZf7w*&n9Xm+~??~K=FW3_|euV?h zQS=g9i*i~sn^#y-Ynccmec3G=>$uTU{Usw}uV^xAmNPG8BstPI=KN$++4R@&Wb?45-S7(flaH|o^ycJ$>TYn3~2RzA8>PzRT0?bPuJ;DUI6Rf7* z53ot9_1qm#g`d~wiQ%2(eorwc=wd2t$0EK_KO=>`Ql$XCnE2Ey!rz+fV#fl-g(36U z+wj^Q`XNl`)gh1WQ?|*$hRgD2ljY99N|p-za?tJCmp(^)5T#N%+1<}1MzB^jRBDY_ zN;0Tjjk9xRj*Fmdjy0c1z6H?_Zf2oO%yY^-QypThZ9&d&{+i8mp+;H+u>vQlG0keq zw7)FDBHQX&SX&`VZWp64;x%I)dUAg;&&RVdn)P;H0Q)lSh~bmuy)l7TK};!I&w+Bj zm=q$wFtXKwulZdK`yMTejBuHMZr4oIqjD$EAdANXtwC+GDoIG{kBky~d2V|JGOU-w zB}dECDu=lX%H=%^>{t@Zj}#}zmVM^O#6R`XcYP5dCDqUq2vRkQ{rtAL*W(uTUJz=s zEU%zD@8+RjpWyaYZvJX()(50>oN29rat)c$M%>b2P7&&7Uw_TXObNXK!?gt&x>^Nx*x>w$a>`V zqRwh?Oy%-ejZIULy*%T9JomU=S)|!sm07X?t3$E0q5M>OeGMYsAM@c@y)gh9wg-=G z?%;|1FmYZi31;hRV|jt)GIIk{$8zgL4@ob}y^Q40aO-zPPZ(CFr1pw!?(LE=&&j#y z?q?^}yRNl*+C=#bcUSdP4Po_XYKi^N?fT2ZsFfZh+f^Tl-r~AK&LH=I&Sib~-OR@U z_cRd95j(I59lv>%+QA|@$XGm`XCrEzr$BL-UA}~1Qw@Z&bOvK2%-GPYS8lOYZq2K< z8GoP>XfCNgF`|gFIl4Wr5z%BYC{{7&a8zB);%E`Y-65%2dIha7&r%-Tn0gU4>kx42 zl}cr*a_G2b-{yXk`&~e`rGr9hkpvUV&JS6#|8cTk#LD3Tu5JeSh%W5-OzBTJB{jU= zttD-bJ{AvL%d>?b-bC;N-;ZDHk;7kNa?mFDZdLuUpTzc?*ibyM>H$B*I4>##cYkMv zRQ%pXS^6ojU-JC-obBRNeE<)7##gB?u(veohVGYaCU1SS)ZA2H5fZZ>*B_8b7n}7j zHih}=qcc_oJ$;A~H_fnLN?VrTG+5tv#+julUy=kLTz=FS2sYR3tGNbGg_soNRpWPJfA2g53MXPX!03Ug4^efsGnPS3#^4T*@)i+=3cuqK|s< zBu^N7-900Jq0?6nf!UKtYN!fSxK6`1TLI3}PxJO0Usa0)Z5UrW>>;sF73s6?XVlP7 z`uuQAYEyYQN~}}-QRV{%%Rslj8i?L@p8NEgfJG+{Eu)it*M}qyPSoU@(-*6v*a!D_ zS^(es^{3pKoH<4}H10DCr3whNLPuCO_jJ0x^`GoqV2J)mS|HdjMlP@!Ql6aIeyYM^cro)5shjF*Fxt{CAVm5YsvnAc_alAA|aRVrA^T z9gFYO&Bt#%PE@Y5&YFgmhVftMVIL~JIZm^8C{xC-Vmb%TLYJP@k}-&gi3h!x}- zsN**8!&f)C2=(RV0aDx@fT@Mlj_kGkkU! zdyamx;Y;(DgR{=inwYX`eF~SJBvG{YVwiYtJ-MG;(W{$%X&Tp%4RT6rj`%`gJqea-m0*UaQ zN7-_i>S%=G>)@dpL&aXfU0-1ulc~`72icUVp_S7qV&k{ucwC&h%|m^*71&jqg-_k} z3Tv(7h;M0n|FHw>FzHBgNMX7Wfr2sEGO%1IM_O9FV%|%X`s&a#-6lPl^_Kmy30v}A z0MgCe0=WBxMY{W6P(Q!2BKAyjOkJGg-5fi&YH6r%`0#!cf8~6{mekIwqwnl}@*M6p z%Zj$tPy|}(9VU!2z0kLvla>21XhN?0n1;L8nlx+*ZD@UtvOZYWe~P`@!~1ehfH3O8tA~J)VH1vJAm6+^{_B*tcT{R%A11PC%nwRca(r9d+(RJu67gym;G5YUQ8I3< zLeA*2@U{9`>YEhDS%3LWEona|S!726`=IO8Wz^TZi))e7V~Jy)CFqv5C(RPiCy#R= z1I{?kC4+zrL8}TC|8X_QCvo^4v~EJ?7;kgZ$%fV|!Cjzdf;`e2+?mv1KciNO>$x$p zxUp>*kI}kY-fua$fr$ThW|i1S2=IW?$aB@!hYA&lx$2B*Fs0qtsNs5lxfogP&~~&I z>^W2u)|TWW{|>d#>MsxFecWIIQ!=TXso*Y0WhS>)5c8f5lroKmZ}IaT4ZcIAC&-dI zeQnToy)Jp82qzAPEfHy(nyCIJ1BPs*fMKnYO8>@&3XnKE%3~gT<EeKqZn_)xxg_Q1z3nYUuiP$N+b^N0+mkNs2HVoaS$Rcg4COi2H?=QzSI^{Fs2 zSRq!C?{Jf@J#Ba0k`}(?yZUp!7!@Z|oV=`hJ~)Xuaz)|+<>nH2BReSAYKjHiPTUt1 zERGYJ`BM-d9I~)b*5ilaHZCCL<=mnT?x@SS47Ctu6I--2=FYVI&EU=47JardaOVA+ z5M?ri8E}zEh)#n*`R9WK_B(ImZvfI?(Mj0A_4+k|EHHReN4Ig9gFo`PaVau@t1~NjrJU{>;KY?w4GN>f$w{YOiOgj){Rh&?n}Sy_Crp zk=C5+)THAJFBY4!G;4e6QZBhB)xz5rDwbP7H|7;@%Ur5wllMu*@H03ace z3p47q{EjpGc!qAev-(n&>5U%gT3hlo@7sLc9IEo+hwxw=t~pa=hw&8ayJtRfY^izt zairqYSGTxF;BnVLxN(|n$snaJ-PumIe+&<_m5=3f=#=9Dm%B6Yn|e0CCvDMpV|;N+ zsh|h`@dNx&*}<5|4ab28o-Rhh)&!uqID;M%#Xt3Rf~?+*cLqwrelSp>lz3oh z1&q_6roTo2g+DUITz-lBu{Li1cI6cHqtG!-lMvz{I9d}oJ`md z`I6yg>`zC~>~}{U^CmxhEwoUc2;Tm9dUs%GvqkuT)(J!~VV^(N5kWxxb^1HT$MGn4 z+`m|Ebe%yRJ>WWA{A7WDpi25ADpHSg~`#y;;BU$mHerTrHuHQ|HfPDXJYUuBO&xf#AQlglkY7CwhqLt%qMJFx&zM921#FmAT=8u@;02f7 zbIeN(t+AQQk-zsEJ_h|7C@0f+5{5k8-wONoG_OF&UjW(&-8yeKz1yxk30&$ly&+q= zlijOu%1FP#gEYdcsnzFQ&RR*eklc+iL)BAq4y1!T4E?_dL#Zy zOD#cxqmDUC7WHS5+Xv{WKv_JX(OViz?WN=1MJ6oUUg5HwS{jr_?E%H8+`ZT`UsL3x zmmfWc5c50e79;5P;#Nz$iW<=M_8)&+0SikRbQ=ge{spRyy4-1~ehW z2%0hV4Pngz&=QStXTctCxaM7XHq>T>b3S*Z;qw*;Mpk%@z~IHvuT-`&-9|km;r1p( z=(B0>R_ro@hCFNh&$nbZ3CtmFLd_%R7cOm@e36JXP*0NrqfeY(j4eK)c^REKT()cN z^TSn!3o=$JE4dNRgg0-EO@#)^_IN32f^OI2NOhn@#VY+C$LsdM5x!(VP+ z6YuisZ`8yz-BOd9Owb8-QD8e;J~OGL(_bP7zkaY`QKoSkm77YA62jD_-5F-Q-%&<>*a%YGu00mi?r|*RtNNxa4WP*`=Y=~zhyksVGveh#finL@G~AfT z98)#5uy{q&&XM;^p{f3aw@6%NqRfko`%auT_Nlv2EYGm%j=*Z#elryN@F&m|EI4@; z7vk@R!vudPD&hfB@!?~#!^LAX2_9faPz6OSg0|_|D$utxHNpdRoFG6B8cer9$MQ;D zB_8lo1P8%)!~(p=T+gpx(i?_tK7nD@LCek<-cyhdpFRagkAY0Od^nEQq2Q2yxBF<8 z8YiRrUt#{0Edw_H??I$L|FX!(RSqdWdkd|z9nKy^$xQi|H~EDSu{;8& z)?nk?y(`}0pF3tLEln#fE)A{Uk8F|+4$Wn84yM?O%yYU|_3C}p@z|PKX$(^W4ZV(! z8K|}`QMjh{D|-j?$!o7a@(Cob=B**h6h1b_JvwfPD59f!UIIK)$owG)GB3|F*6ocX zf8jW5XJyTKez$-Y6W>Nie)|3=Ka9 zF4S)Zt73%;z+hX?iB%j%d{bTL`7?|J1^o|BKRR&n`x)8WYdMKi$$(kFLT#J0Q*c(hq+iEWWv= z$V_soH2@@<4c2fu%SL--Wjq|N^;`#Ix;C@ZkA`_S4S84i?h(+u!~h5--3Ry}DZh1p0Hn`p0Ya~PNlHTA?I1{GtG(Egn}%hT zY~EaDSy1Sgm{6V{x?Mfn?DUPtY-OM8TRpIOOQRVsO66uplxI(i>sv85hHl^#w)b@Zm>s9;Ej5J)*wp9+|a{e z(gLsBce8PWJtHmNQ2A@fyE@apt%zt@sZqW(FMk8j>yztn)Gy#8;c(Em!; z7d71##w};}^WuR!cwi$Ln8C4vr0+p6-h`}Aq4WEZ8grtp5f2)5V`yUl*W zpjqo=dblzDW!U+DPJY6fd%>UHmot*m2@A&1(lOtY3jqZ8$>K_48n`tREypT^ESo)( zzxDKs(aUQ}#=G$Tl~pMx8yd8ph{@PJ8+Z-_ zZ(gYV9(2IgxK1a8$ZozuTGiM zZXAs)r2XO6p{X(3k{%YBr6yN=FENHV?%HzwPy;bG7Vo*ZkD!M2)Tn!8Ps6QN@qpmV zW;c$6DOG+>w*;6+tpjzlJX`tD`i*Pp_e?a~NW{CAlGhi*Ht;}^N6i7`$p$Nej$mm( zPsm{|k7Kp@+*`v5!T68uW)AOuph5pahyEWv|7m4S|1uaa|Gv})cmV$qG?M?Z3ldoV zZduLj@7CP>4~c%BG?R?#Hl2t3bD;Cp3uO4WgrMeNL5FVVQngKH`zuZA6v_6Nd7d5Z zUMS7&p1q}ETcvx`7Vgh^l%Z$&c9~&JC)seEQ-kD7Qze4L&OoQ^rETI+;bR4m&>#WAL)gI1GT?9sjg$D*>A4OUoA z2^W|I-QS4CnD~Sp6I_68P6EEq_|3b#3tDnYz1>M-Z+|=;<;KYt0cr=N_X>1}5RA6g zyT_ti4+e6VJc-mbzk%_p)4ip)R29&I5=DaVM6W>@2t5mmb|`h_^i;|!RVFJ5EI@7v zj0RKG*_`9IN!10}vx+1UcWZ>7E~Tchb2LlVnRr6|S)UT{7f|-PY$Es?t5fq*5*#8LqT2std~z%;t@ezXB?M=<4A1bK&TipWX zzDA(Bf2$xARkKTdc)|!iT?On*3pBxgsMo)vz{c)2!(GC%$OpiNW&R>^Gqx?-JfWsG z8sttOs5X9Gx$rL-s{hHu@m&76ZXhf7+&6ZI5VT6E+td4IFw9^|hwS1xnuoDI z9{<#WWqP7c`K}zQxv7jqMLO$l`)gL)8uB8^0N0&3e#>pocRzAJ{?;{0IQ&K)TKyVT zdML7iO|NeF5%xMrF?*K*ui=M`t*?EE{-C<13))g#sRSV0uOExP{r$P|^YWsDA9Hl?ye zpJ}Na6ZcO8k)05?p|sNr6&M$nStaMNCv(<-k9lDc^w%=vTP*Q_{AE0_zXlKSGEQo9 z)Z}LDU)tD{YLa9l+iAzTIpkn2-wJ4UI+^jDJsR*h+u9EA{9Yaud3{en_+SeRGSpjQ z1;R0IbCt4o6q`KqritSYHLl#c_at?g`Njgdj_6~t2Zmq>u@Fb+AJK;M%fkbkBOtr- zon^tY!Rt+;gfX@AY@)$^B_I9yPf!=$#RJ_5Kb4?5@&Ug1c^Y>di+YE?9sz`{>B6?Z zeQ%yNjOLyI^q11l-v>ebA0OU{B!G+aB!}7!1Sbi9qMdX#7Ag9t+N|PeThpHcjj{g8IR~ z(w+HFB`(R5eI0O)|J-Nzk_m`RAgRoauYfRr+HeRQ&WAQ9ulcZ1G&033#Q8w&0d>le z&Vp6i)!|AJNGX?7@Ko&yp3U)(?}skCjE%Pu+R|&7&DEML|6wEUSM&O(Rk7N7Wb4e@ zE4Bn*BZal%mTv?6pP1;`XkN?`#HjoH1J)*}HF%&A$tu)nvi+Ck&(Fwb)sW0moP|b6 zt1R$FQuL727=Xh*1Ey#~|9!c7em@?VqTeX1M=w+N=!N2XdZjLlhRD!|s%HYun10+f zHt22xEbl?G86Jp)_~Ouc(+uEpol49l;#c&a#XG|F%;Z`f7}cX^Fhmcn?xeqp+DA|b zNwg%(!pJjwQXng|C`8Ocbv?1|ezHWvx`GLp*2Q}Y{*>O=QD``+;_S(1PwqN#j|^9i zdxb(zVL9zIazvC$1HqL!aVTn>oG^Sfy+9kS^Q|Q;EPtUa@(WxjR8F$sJmy40p6~;= zqb8HK_kr$_>z`=m%T3b})Gu)K4pj+BQ3V`KH^)aKgU6p4x8|X%wTsc@b{cl}Yqxt8 z7R9^$7--6)JfhyGy(~OPHl@rs?f2m2*{g9^!@k)A6GH)__EmDFHPkk^SKR(z+#(FA zW2Ez1>xo}oPAoilK^WKNW_sE$T4s(tp=H4Qe$zQ_Hj8&&ksAHG)RC99ma{~N2cdj7 zdq`YnVbNouk@=n3s@Vb|H$x%GeHeeV#bOJ24(qB%%goWDDNU*d#3t3|Zl}p7 zpE69+xV+N^Xrnnw-x*>}3}4KhwVfxj+$~T<$3}6L54tDT^}I=3m}Bjv(yes#0`WES zm988468XvwSgUi;n4MB4%}0+ESULDHZf|TeDV6yQTvZ4 zh4UI34~L&)ZeMe+kH|fn8xnJK%}!cpoitz&ZKzvO!nNKc@g;>Hl0Hx;w~|<%R2H6f zVTmcnOrS@e$!i79Zs#^(bmdGu!x!GMU%hwK!F4KOH}(`asE$?j9+Vmh?Np<5#DLWz8AHH zkhic@^ozAhc6M)FkU6b`<$BYRx!kgGGTu7|b^J;EMRkqRY|8Yi*hoF6Lq*WV_W<-f ziU_z7S?Y582i*J5cN+NX_c70b4l5d!yL(v;+&5lz1ACcYT+zdHs1s2Hj}*xNSff7< z6tyL=&)B@wPAl?gqAxrn(eZtS=JZgW21J8if!Y9N8V=ji5sTdq@%`q-*j%QK$;`O) zl<~oQ4@spVyzMneMC(NJg^F#`EqB}Gs8-N4?BpgMhCD5aJU$Dnf<4hr8@p_}y$wCy z;fHkO)e$U*=QyX@_-eRvcX=L$1?^N%lfxV33)f3pFA6vusdVB3KntlZ1p3=sFUm2V znTD7<>ePf?#k*Nccz|kWo$+eg^}zDcg|9RItM72VMc_t^FF-RVU3D)y35#vR1O8+{ zBPu&+O_rPOoz+R&%eUOMTKUQo8IFq1X<-ITf6e}fcNN&`L+jX=Q<(;woE-^hZ(nzA zjT8>^v5pN-Gme6m6n2OYz->q2-CyAQJ#T*#6>zH)#K7NT>Mf_*js|gDLmxi`P%N=L zOlP0xip=Ir-UMUt_v;rIU`I=u$8W9i089il&aMPXG1oCKU$Wn_7tHR8dzk!80ppyp z#K>6m>Ew|?0z5rG_qQT`XpJw=Wz1x~~qet*>ubwmp@=%(WNCZ4k zb86LS?EuaP0sYK`0raqNS)y#OS32bb7aF$BTc;bVVC$^H2M4jZL%LrZ2tg�wdc= zqiLY({ic4Zu?l5B{J4(IE|tC{;goZ-W~f_7e!*X?VPq^)Hfn zz(0tA{>AtH^Y$m;W}_H}&eghqC~GWz78X21#sS?WK5+kwl_W32B*z26lpf+aCK z--ww~P4N8qNsgbONBNryNx(wpA5wWQdEU`}iv|QLqRAx`HI*dN;u+`HZ?iga69xy5 zW$0)d@qa=9KrQh(Td=@w7!-R!{^9_#E@nABUjDIOmZky+hdjB1f|*z79CVY#6m#cr z`j|ojy5C#i37oa?@D4K8TQpD6qZ22+Pt7do=KiQMin_1odC|S9{P?uOsuCF zsa%$g>k=II9HoaS%-WbJcM+6?Oa>mm@nZilw@*=$Sxk%P%91wQy+9f(eWsjwvZnws zkuu>Ky7AX(27k;?V)^=B!GhTSoKT`Z1SYwB)9{Xs=(X`M^JU!}a5L*if56x{adATA zuKbxk%YmI``sXF+sFs-4@)apY=tZ^&;F~PhJF&!U^-8~~#sKqa`k}W@2HTT9eU2o} zr&fk;+%>vD<@Fzk-XSXdBMgh82j%YB@4JjG z?~C4eKw(9l&kuQA9CqY9%QX0OK~kkpMlVxE^!k2*9LCZ?@S()kS5cEY8fiCnt}Pk_itc^w?IHpo!fulP8$kAqG_VCuc=BQy$7YlYcsG|%Vhi8BhIg_w2ZxUb|JUp2&M1RGf~ z=m2gvnQpIof|2_klH6Vs%^!d1{qg4i`ePl&wtDgo>8lo%Di6s->q=KHZwqymxMfeo zDS;7T(!cJu{P9f+|I;>%Q;{SbrbJ&@&Xc{EAC~wW60yN^RJvFvY3}V!oIEX>NLdyr z?Myk=MjUd_l4+Zp!okb^J&TcvPDqKF*%^X}`hOhe5^voVNG*}#B8BkL6BT{_V)ZP@ zSA+0lap4vH=}m4%cbS|9L3`QH^!YZ zKyPw{Q{0E`cGSn^{&0<;PQlUJN;?(I*4{NW{7{in7`JKib?O9aY7X~^@pwz%a{vXr zeKZ$7?1o*P;+3IQ#VvIKZfU4TUd}kbGvMG-hW>D^*Nb&#D41n-4+(Qn#cC&-NQLgV z#$)a)g>y4cD=@&3Cs5N^j50VNB49sUFQ05^;r)HC{3zoBA^c@&e$~R>P&-CVON<6K#xQ$FF{g3#vgeT zd>aWp-a7YVc}q(ODmUCIVG!-@eryV|X@0oQkBI;le@y)2_1}CkieiX&I8rQE&PnKu zexZl(q>%;@9HUSp0Y(XE;L~Sff4Hu?B63}UZ4t|90)j7TC+j!kZpacLYhri4UmDY& zKSqLaz|;T{FZj(q@mpde;~%bmsr=ODv%k)YQz(Ohh~(1(I?OT%+}x7DRSWr=MB@QY zHR$0?TDu0(%HImA{LyFs5&M5gr7?O9tE2pAI{j`#vjk#5MZS*Uc=|;($KVTQE0V{+ zwStg=J)m?5qt#GFh@&rzH@`vkP9 zeupX;he3F;Hf5l*K(4W$1_?W;kHZP7Xc$CFPQt?AOY9`aXjLpH4wMJs z4&847T&7XACC~#TSP(b`{zK{SD55)?wkO)CMrkt4-acsYc>4**-VQFIxesRS4Q*wI z-0aKWDJv?CIdhMBtYTAv0x0vbkZeGOV>0EK2Kl+hDO4+^8SEjzy~=S;ox{b zT{d-qfX(e7p5C-dW?+y_tk~y+ixDoYb{S#BYy$uOXz;Jyd? zg~r|61)d;5I2PnWPKtvoWQoApnp8J8wa%q`(FE;=2RQnF+G6;VJDhGgl@Sx^E&qmR z%$2yM>(qB| zlf5?N;IJ3GeLecv&V5}-Y?{qrY=u^^kc7$Rn=NF(-88)FUamLqhnF#TliY$t9vQ)7 zaJ*yoJ}T+i<5#<>8VLhklADL(Cj&TF>n*j(_q1Y#mv5owbs@-m8T;gnV*$?f`#F$2 z6f8mz%ZDoZ?3?u^zHqC@gJ)>#y-FU9>ll2 zp^d%{`hLpqWX4U%w; z)R44!eNSw|q03KzDs>8q=6n5gV=<9!nDcs)e$QLiTL>pS;F$;b>PDgs)dxLf{H3qj zZrCsbQ97ZRw9FLyxob~kCa*jIw`n5EYqLnB7ZWc0pm2Y&^H8TgOn0vjtA-|5J8^Bw zoY}lDP`XxW*8S8(X6bVw!OG@9irL(*eA|5!vHrfRI{sqa7z_^cW|j5xcBDM zj(diexFZ%V2F-_X=j=Rt`AtPnJdklwV6V$Wd#aaLR+X2j#H-niVb}#MsGqPnV03mz zq4(_?ICkf8(4fh0XeC+xu0;tRUE>k+8Rk#zVe8!TDd2Y%47j-5SH(Nv%$!ij%$-wk ztt`PN=-lu|JA@3C#@vvVAB*h2|MVc_G_R`o`j`av(S6t|$P79Upy4rTTXg;K)uQ3j zrRgm~P{-wyVne*L+td%p?CN(%9maN?4^Duw;bB7D6>vM#Kg5CgdDo!7mR5`RPgFSn zpSf`eD(c_1{8jyJPliCj-_hTURDVZ~+xc~OqQ6$o-}s$i7F>@}xA6*x!g(y=s6mpQ z5~xY@Eo$cG$|w8bQ_!!qP*AsT@q>eW_lpMcpquF_@#X+QgC5HQSZ#tO6Vk!OVZTcb{;qC3;m?eTylq0U z#?DA*V8lt2w@G!YZPhT91rukN7iQSr^5K1E5a`a1_nLrS2jdLmv&SVuHsot|)%QxB z>Ufv;hDbdFb#P0&2&%D&?Mc?zczc%Key4T$uPqYku;%mYNzK=s4N!ti45L!JEx^MP zJ^E~{N@)#hU~C|6E#@4VMG*p1?|Aktov6X{(uAN7ZCSREzTr(Wv}p_sy`2dkHpi}x zS(x*X-mJxf{-vrE_J(-Z_mzrR9gDxMmCxn3Xg?LTudR4FQWFOGh#<7(N%kwY z5E;uO2n5#E{vJ?t?JiYTAj8vBZo!&23(l-7mCG%gMSi|{`q@Mep~=ne3&uG08y-uo zDXy^PXK-%a^R@ff;0^dHc&)%egR;b_bQ$8R(?FHZKNSz|7bVbuBag-8iaV(uZiDvh z3+vb~Flk_R2L`zuJL_HQ#&6Dt>KF1m!G+G7suqku8*!<`jto1;?j>!%g{})PDsbq# zpi+_Ij)(r+O4(ws#!iiNId~-@Ygk%RiuA9US3C}~;(KPi0ULv+FyR3^xHPaWM1r&$ zb1J=@?(2S*HmjAnn_g85Bje)X;wt3qmwWwDv-h$|dF)=;qRRKTfCmDozELc*^P8`q zCJfnoZ^*C&H{k)wjSsSW1Dnan33K`Tv$c%hh50$Xt2`~r(#uAps>)6&yqapTy5O}f zqs{R%1IeGtkC>gj;5bD}_S`(^k^)o~qtvJuz*jrSSz5hic2C~6+r**YS)OU63z_4- z>c>04{VlP|pS3BGg|4XM-uq}_p)QBH<4kbN*w60HkINr&a25|bIr|NjGc`zcxtp+} zqF7kp8O` zq`@#H_v-&+?>)n!ShsEAYJwpW+F-@QNjp{u*9dR9^O)_lhtV@yBW5iZm)a=q_N z5i~DL+nC2o?%sSdgtc8}u#sF?fROF$LSZ(&9)GET8=X4;iEjf$G{N&(3eDHwOo+7g ze#XE)p^!n4ba;)`ljD&(-aVt|OXfB%)jFfo67+JF823+XdtAIdy2SA|roIBUQ6Ck9 z=czdJlOYb=5JU07Zcm?s&wZ2ey_a^iy{r`(^7oLFhT=GSWM z_#QHS?v7kID5as6vq;C{vRnC#{c_sBX3Dd!vo?)wGu<&zB)tY&?d z5XkN&Mu<))ayN!VdTqG(*R#-NiwZ_ z&OszOu9-%T@a7#DwGki?Nx55K79&CJlP?2OF!1=KIP*x&US2UNdT?>U%bg^xo+vF+?K2)Y>v5vo|%%4LY5M6NK35E`>}v3RT}`h2Kq z+|7JjxRST%PJs4)&(-8Afy>?W^wX7x>5u2F#`XQgVA)X`XB}zPkgkpU0-eH@NO2qS z!TjAv{Di(-qtuYg_4|qOB2#KhAV}b;0&Cou>|6FYd3#urei6xItL;|RAsVY~M@VK1?Kw7GmK8tJ=Xa`*uh?RwJ5Uk@j1zeEuN_~=CVI)O=PDl4jq z032%?VDl${9{AM0jx1JxjT8oRTO9GzW$}2MU;Gq)7dKX7%dNFczpL?z(yicnNO!0L z!N7C?qx>XS2-%-01W53@7l{YCeKaf@bwALOn{8+SRFe03b|eUAnxj&33@vk&{wi^J z<(8LpnSZoP?8Vz`YuQix8}7y zPUcrbgeQapCuKwJG=#3~Hb*;(fl>pkw*)tNdTdk07dHg=68Fpfz$y>UnegHca?fNi z`t#1Sw*9wIq2p<0^!B!@Rt|77e*?LW8bpAYpU8i6_2=N!np6Tzam0m=H)RL$nbB9b z<LIiEUgJ*aQg-@ZpNWF_3R!^+EmQ80X50Ei5h%6cdWs} zY0wJ&jriXjTVOuY20x$u zvMJ;q(P^w6%FFA>-<+jgS4!C6;l=8{Oj_a;Di!lkGyhv3Chx`>LZ3 z+Dd865xM6ZV5fxRjK>sU?q;LCbe9R`L$C(k?*I7e-MBCL(#~ZYe!If#W;J=T)o-?6 zKPGT$BinORck6;AL+=3LEq@G0QZeU|YrNlkdlGE}gfMz>IJRx}=;al$;4=68$&@;J zNSd+T+1le0M9W@=o7FYqORw&62G&JYF{I0%qm^oW-L|w+^IRF1$b%v(+jDgEE~u_1 z@rt=aZW}L6rp1)lhL90Mu&2vYR=I98Y5iWY=662Bjr8t2lT)a#>h@T?0EGbDbiGxL45}CRE(MWdq+%JdyV%Wxcz$AD%f(a4p9|A z)Me7Rb#C*H*UH#++dF8ehhX0V(EhAYTBP4xdLi12#qll9Eo1@OR0<99KxHtRU;Jb} z{dl-MNkot-3i;5><2(tvQsR6|IAyL;1tHnW4Dt=M#m~M3h|Uj0qr90wmef9o>ZOH! zBQU|CKdce`!}|cyrT@XT+f-|-#!GT)8n~*}ac?o`yoC}q<1vN$%A7sVn}mT7N?pc) z_f0rw&y}wLmpn+iYRoS1WkZA%vy`qJ5ZSHk1%m#4SOIjQV;$bE51!MoStf5Ze*in_ zWa$-@wkV0IFVmuM~R-WVb<};LMT+G&qRx zy~to}1NzzYTa-Jqc~C2PIX(;+VyYgYK;obw$G z`k3(x7jjSJbkq>T5HJof+IxDYF;v+x23BiWd>uWzLgXUg7;zC4^JG>j1SmA*G>LH)_H_dMdH}zx5xRv~EM6oFCZq~tA|rdym3lB;zG||&1Y&`Pi6`K2 z{49M>%nAesXF-hSc*X&7@Z`J)rNu4-)^ezye+BB>-sS!kD)z_U|ND_muHs&3dI@$A9RaEHH+ttI?=i zp>f~vc`kQRXrc)7_kd%rT$%eh5vQtXirja&djnsaV?+dRDe>*a?ENJ4l*zcEb4VVX=A-L=u%e`SJa8UCxVKUDYExB|#nw3ya?b z`UdDq|GPuSuXdY*UpgEtfunbNj11reRouZKjvnj9L81B_*E>$tR%#4if#u`~LJ(U`jy`v{IWn@C{j{Dqxz(?5jhPs- zhl+PuOuuTA+;bR}$t`D3_KG^F)}PvQOl_<>)!6pzqou3%rIxB--A1rE{etbbt%{wH z7tu0zP_d3LI?Q(4L}v1;qBXrU`HNdy5)^5`Fj9IkQl?qaui$;{^LHlpp0w@-Za$xU z7MZ%qd0Y7RbnPCTD35I@Bixp#RHR-Y^pAQ~PBy?)Z#Vm&cu0cF!jdhC0^TexFQ7e;XVhaoV z5eH@EFq!yeal%7E#+sPRRS#Y|jgMD+oQsZhRywj4DV>K>s$Q^+;uN_v$6YgWa4zfS zLMDaolsvzShbmn#fplfJ%*NUX*r6)YWNi|k+HtD%Uek-6mL{X;z#zASU3sb1L{z*TKGlEwIZ_Wl?tNzy2q;KSJ_DMtmBuN* zPS9XT7~!c?*HoYRs6S0)2fH(5h-=Y6gD^9ceVHQa>RM3SI@8bgb~rBJHb0-P z+}FddE&SREqm#Vun^F_O53I(>BQCAdEcWreg?9cD`afd>+$ycXu*vBHNru!hY3^6= zH-pyWBJ(?D$;)lOe*}{i)n1PWu*tD@&61Nw7$W-USg(`OMof`|(f<<3kLL_Bs_zNC zThUmMIXtul7tuxmLwq5&j*tVV;RkG}nKIT}(C zVge*c?Ae{(qj@UEH0rCcPeT=EmgTIH!1Tp;V?FbroyqVzHX~|f=2^HYu3(&fH}{CKPj}Y^&1=Qo7sTOvoF|w+?@3{|A-T#lja;%kbR>7^15?hIsdkrwnTe- zrc1SDDf_RV> zbGFOz7G;V39cdhn1S@cn4rGBv+?zd5@gF`1%Eu@4QFYda_V%C+xJ$*3^%(Q z-k}Jn*ht)~0L?j)Ls@S{w|r>w9>z!{pev)NOgre;UAvc*?(R)+w@L=|_AQT(g> z_@CcHU{Dg&b;AuQKOzHJoSW}jn7YKnj)h7mq8=yMtz>j5e9+GC6UX5%&c;)|0g}Je zG{w+7t)_LA3JjTsuD@FbO9FqZvBUQ)=x;T6Xt-u{Ys>p9@N{}heS+S=;2?->dnYH1 zP^=$)$>zD(e&tY$F$kZ^PN9O5*HCztU_+RKe^}1mv4gJPEQ2mgLQyQyh#!}}``i9% ztN*tbmVdYN5;?`|@Yz67aZ5=+3(ikQeeIGt0VWGbIr%S?@k0+Nn0+KgCSDr%9 zdRl4zEH6N$Np82T+vM`J=$90mQhTxp(D-kAC_H_Cxh)=)XrqBo*2h>GUjcpF(N<7H z55RZ6e@ioyP9nbc7Rqu=lX#XD4ZZ?IgwI?S^N}Z)Xp1rHBi2Zd*u$Xy4T5*Vz7$Ui)HA(MBCn6mjV6Wzi%A9-S%@NKGFT> zBXZzNf*QSG)>mnQ&Ah7qwZ@f0vTT*~MeRgus+zL2r(x~w<^CtoM&@rX^scr#F&5}h zEJ_n<@2d&sEjN(GvyN?_h!+EJKNCY>>EGiQ|Hpb-U&J|&WoW<`;OX(t5dLv8eh7i; zd-&Pk57&65!b}*Gk@P=t4z!G$@c_>G_X86Cv(D>J0Dj8+aUXwj^5J;&gOZf`qR!m9$Qfnn~_#K$nZQcahSK4>( zEdH*ZCS-nh2bB4kfn2{4QxJl<_bng!&FLdCUeuA*j4-c*-c3-r%9X%dpw)g~Xc!0x zfkY_@{i8?Qw;Mn2O^+(b`xFj~P}t*G{e1KOoLT=NXa{wh{zZe=wRM((Uuj>#(k;1J zIN-)BAF(2hCTC+?m>?csnRf7jeUdP(#5)-gC&O zSaTOZNBiBK{`QCdIWFX%=sZ%sU>k_Y_rmey-X@NnQ35P{aX>a5IKiLNFpeLeN=ANL zL`O|0Zy}9JIf7yR#m%s8OKY&XRa3>8TE!Zr&bwNF{@u4VO%p`c4Al$^>9Df2wZ7zO zU;b!yQZ^2Sl>+p2(I?XlJ0zZseVtrjD`v8nFx#FT5onnVOqBYwVMT&9;IgIZ&-u2{ zXgyhLV&-ZjTu1BxGL1Cf#p{5FBxL8kH`9|}rt#iJQ5dTDEZ_dNkA@~l3(Pbeo#3^{zNu6*+@p)uz!`XbfARU!ZM+y=$s zTu2U0mo6w)udU12Qpnj%jPyLF4`mXz0z(Zgo||P4$(~h+Ea0|XEw$~NtMx5;qx;5HJ7{1p140X9}1E-XkLsU1> zu56eHS?do)inuMNqzrIx%2#iByjAt=;ps;4?TTeD7PzJo!McYz7-Ud%U@O8&^&;H^ zbiQ}_(XLZdDYAxsIrtZB-!(&)90+ZU1>@u=Zrs=A*OuNg`TtK-e<%Z6BZ$|RbL|lAKGjm(^FfLX!NA< zgFW1RrCiJLXGN&*+MA}XqpwTlP^y3CTS&Wz2rR0JM@1G4j+z)`p2N0!oIId}B9`ng zhH$@B^jv=*JWK(c)<;lMtf1(iZ<4@?gkhvQLaWTk^GOGn@m!@>RZwpk@(y^tai5_Y zD1a3d*aM}I>D-lXb7Dmtt!-H|4%J9;X!AR_&Tp^s-`-x~z~3q0{L7Y)wi%#AudlIm zHEco2Ok-??&}haWiOxB*!ddvTWEoC-I^m&DG$tZzt2>cPv0#G>C&z(ZmDgFOkt+nf zkje=u)kG5x-BUzLe+7&qkv*Os&pvZ*mx~BL%nx2cR7sC*-*|)K<%$x=RB2BJ4rqeK z_;)$OcHHWl6};nc7wP8GEcj7^ zJzhsKIkQ7$NWD>4-#)>bC>%HA{EG|Br-9MEujhNjDB>0#`4fbHn(1aM2F60Fyt0gOZ@42oQUFxGxUUW5iIwdp&W*lAl#(2`w zRik*HYMPxeE#jrjEw5F@c41BB-v!H}aUJQGMX-ty8Er>?wGj!ATVtEPnJ_FwHo5YmR{(bbmLxyqUkx#k*d>ibnq?`LTBiw* znNE0cJ(Ik;8?lfc$37_EOF*BeV(4A4D}F>1Y-lwqTT`|CveGXSxfY&0*e~8 zG_Gyb*Hez6ziIb?u{LE?g?&XgHA{BzmN`z{?jUQ(aQ3rqlz7uP?-0rC=IINed(W>G zxQ^Ea3#( za#v2RY9FuqRMIMGiP`9mE-qvZi=6sH2L7QKi>HA>Z9~n7Tlv9~8DF=(ojDzCc%KVe z{StY{R$r;}bbe1#v-koO{~jNin~|J)d~<)7%}9AHgB!g$)E_&FO$a`hZns%_ zJq+g~QpultOTX|i%ACqSfS|KJRsMtqB7*5dOE)*8O>}p`(&i-2C8`>-ovae=D_pvH zbZQj8RP(8)d>W=e>pD+Uzy=H%3&H(ZzN9ZkGHFfKP+c8#PdHYdIm#uh(0#iuV1{wH zK;1XmytXKMUV;ZR37h8e%bR|;AR`hJgqtuZFDiF0f%4ezgBhoFIsG?r-NpiN z%Wgb$`KiMccAGxE7wuWBuA%aS3+NAIy(MT%+S>K2fPT4TE3^{5H zG9}meFr^4GogSko;79ez@1b@rZ4v&P23yg*z24@If~RX#1?cIOh^%ClsAeOxMI#OS zbTeM358Vl8uPmJ&Ju>PeqfCqcB(vmzuLN^IC?sk<1|PVN?Gcnq)`s?<(zqg~@Zc!s z`6YsGIjf163fMui%J`q7Gux5HA@DDCVo%`os*TT-s#^yecLk;w_Ok=;a_(R+y`seT zvqJyaEV|3oIma|1UgbIF<|bIKFqgh^ZgfOQ|QHM z4HL-dWBTaF)v`SMC3mkTxfED?2MuAC`498IZq_9~c^(l3*&Zaw^}>oM(^QNB{u;DASG-H9#DnL|qP2HFFykp;Z5LL(A4)HBRLbsP2ye}Y$JZEe;)~^j|MXi4uLJ#uBFmgV z7&?-fFHP~i>2rY%T}FbE;x+1d<>C^Zy`f9+vcM1!d8Ne+p;+V2-wA5cxcueht ztw&i5vy-c@>W!5I?M7iAn0N~bd9`$)uMYxrK&qzJ-yH{W{8Noc=D?XOg6GoV0 zDzOp~?!^zKaWCTmk`9iR7~AdJcM_hlWqypN0!dYrz)dR<%8g)d&;2VusO;S9w78(k zH>>E`1drDPva|8AOSqQrXazvNRm_&^fa7z&&nV)4&xaa~+WnfJ!~57E85blS>n=4w z`dTDe3>6rKm}(5LiSGkqV6T~RL&mWICmLc{m@kRD6z;ajl#8JXIJN#q_|N(+5KP%nj0THE7_2wE}06p%qa}G z?6#tj6Z4(CdzsFXZ^_F29MC+y^1PH@_@tNj>ue*1^9-zq9#G;Od63bA?2l~QtEYLv z*;ch94b9h+YC zr1@m1N#rRmo4{=9Nt`3@XqF3jGDRO)mvS7~_J=&zZ^aQJXk>Meu7;=172_VcC^@-5 z>#%pUoj%0FQl8)i=Zl}(%P*3VQ?Ux%fpdhw_O>6|3kayo0KO-{D_bFynNzHfjw0O4 z+~g7>n)#jMhd1RG)R#vl70fSlZ1{s!QyV++E^muOjA4DLtAecv^isg{E70CSx0yV- z{1D4S&5%;);b7rXsr@8#x{L5-CleLxH0rTxkC@L{7f1a*V~0<5PAes39mCtRU?*na z(+CE|X|}drNIImtq8Tm|t8h^xD(`iQn!`n;vY-9xoV1-|?(@Jc<6}SYEOkvs6*ay% zDn1Gkd_%SQB@?D}O>?hx!X|PBm$P4j8Uo)$Y|fKej1w`*ug-QkmR{^`gEuqSMMlp1 zkZezi5sp;%cX(La7c!G!;A#eU3F(eUWiLlpr+JtLh|u?_DKhnhNM57bidd|wo*6>u zd<8Dsm$}_Gd6!0CQ`zH3z!}QhaERF!d)b~e+ca~k`C1ktfzL?llWw^b7B6IfDtLQk zobTL0Ka}*0_vwmm_&b>t)a7jnFO~O^y{wyfJe{Y?F?m#Cqo1^|l8Lye5@4H8daXP!mV# zRXs-$cKhylh=U>hP?z%MqH(lp3J8Of9@hZ2K7O;Du(vau)fTSK^G<0nlQaYwz#DHr2Bv~hyL6Z z#|s#_7ZyZ$CiAia=+dTfaxOXHy3h&-y$K8uYaT<^AM-pitnZ?9I|Yj*7fP%uPi(@k zc~h|Cl(f%6jC*ZD#fOg_){la2(?*&`V!?|dASc-1;n~VYy?Y=2zPXV8_Nhkk&_VhYn<*JqPAG_yT_q!Gk(geU7AsfcDF7xroPCcrG4%!@#aM3E{KMO z3@n&1yyFXHZ8QA}WZ%Wvk0@Y$bDV*{shgd~7_K`h|KUMQuO#*2)6DRT3C!8@OKKr^ zQ~~PFhMP6TA&63kY&>VaIy;d;*S6QG@147#DN(OnhinSI0%S-$N;K`si_{My3hJJ} zURYwlT(FEtYbii)xT8DH!mLFFkdaWe2_-4D z*KI@Qbw3-ONCq;uH<^TLj@f7dw8`UxUjbp?w0I%9-at)9@MisF4C80~CMEZY^b+e^w)_Ov zj$*Q4YkN7kPp=rw2$J;3NLoGW5_0sexc*KX%*<076@1IzZLke22;j?q{+!RS7Vdy# z9>N2SFbdFfz^gkFMsSMTaq^9-bFGu+fIN7=%mGDg3HAkU9EWyBz~_(k1B6r%x^tI7 zYSMd}R2q0?^L3El^HN+0BsjukJsr+U<^J|Pswu#wyVQz#95X-$%mmHTRzjM6is1bp z0-lQV6o+ZY6x#~D;wjvF@JQBWvPlL(4r_J>g{oAXNH&Ly&|wRL!RUX6?gE8piwK-g zW`93E$SAb47yjh@!hPiWKTpM!0LYWz>4JW;5&!w{B&eAFmv^_7wmTGsb3ncoRs-I~tbnNhA9ht*&}SIf^W6D3OBEds`KBBM?V4f$es8qXU}- z!G!OQ<>cexi*}0v#rk%JTnqtNtpsg09~#EDeF=8g)F*tEcc{{`?}u4>-)GAV%AjAt zh;HnPR@*Y}rz&mcQQ&poWq9p(tO-fk^qHbsgkD0V9UD`$J!#gt5yo6JsiWpKj3yqb z3D3`W&`1MCxd&&8(S)83i;Y&bvE7zUL7v+Y28O*19;|hh(*#sL8X~qJEtO!a?NYNq z?naFKR4unb$<~o`)`udJ`vzqF)B#ss5qayBT8ZQ5jk+p%-*h|6n{;cyouY_uJYkD| zs~$iNFr+oFQEKz1;~*7Fa?4T{O-R{~BJCXOsMYl`6Pz2)c3v$9IeTqMU=AT)^`xH% z451z$_9N&nw!x%47gcVG^d-Z2?8t@9)Vcj$I~|t$d`Po6FK#3I6y>xbU(s9erZPi& zGgB51@Lh6btb-GDegz1P?;KNzB|5Ic*&ft#CiBM%!yo&jPd460O6DL^jzZz9nb}Wb zXFgw%JBqs$p)7URxha4FH}I7khI_gEE;O_T&qJj)T6W5w*EYo(r|`+k6%4;A2?_e! z=bo#T&7uob`ZQN(5b52gpS=?@t?ef#D`#ddnuRHQEtTVbYC2QB@D+$?TgCz<6c3ER z+gkBKSrACRBZt1hpFwptI-nA|j4*#GDg7;#Yb~E_#^K82O&f(=T@8l)>8FNo$t=it zfl9fRUQ&j0>w|BS!EdZqr&p?I6MAOJI@8Kmrehh?^b|yB*I7ORe59tBgTGj|-+V1k zuRbuE>67sqLyOH%=I$E?wR%#9H6ZpwpC+-teB{5UU@{brD*f35@=}Oh@Q?U*MC(YD!~h(rKvwXuYCm_*{JtorK`-;SMu8G7 zaxK{5ZEg}^2ftr;;rNSX7ynx={M6)4jac!esmdq3pTuk%h+p?M(CS1ZQWo7~%6c2k z?N%6`5ZQ||qu0TyGAI~45M73QwpD5&B!h^%K9_ift=KrSlT0Z;i?U{aPfh;bzkjd# z1|Qlrzel-ic^(2vmPT3iK|ts?)0iK!pC2=!KYzc5d$R|S1<3>RJhIzv3MaB63tYRXVCPfY1T}%NCG3AJTduu6<8~>tGbC^sojki z!u$H^c--5AJW1AjIj`*su|s=d${P~6x+9lZgvQptGdP&g`82jumOm1GIn2N@58(FJ zv=(vZ(z-97lR(e=z{Bn^i`5f$Ry8_cye(eezPQpIzFLAidP5e?N)5HWXu2kvu`Psd7gt^dsF`vG*{# zy*oxhO!zk6)pxm<=)S5L(gmKvc`K70{=C`zgotvhDc{PcmL zx$1?GpSlSB#rXAS>-^14J}Ezr@|}sAXf=*;R!;=0)*A#R@{bDBUo?9fQ5+!mC2(Ud zXV3Qm*g;~N1_c=aIs3L5SpkAy0j6G>{qsz)-c31=bdUbkQX}XopZ@EOtbV=tfBime z1ebP;+P57%G8CA}HGTA6a2*W2bUM)idE3sQ$Z0WBUV&oHYS>6RP_$%HJ&cYiPvS)o zK0X-{fvL?`Aa04^1U38>fa5!$g!L)XV(_!flFWTt7(1#@E&V4~W3j|E-!cP97s;8iln=*$ z;IjQUQz?uE^I;5^yL9)Cw-xO7M0|3{cr$YPW8RS50FyN(wreaU0;=fxt~xlc(k11G z>BUybPsdDab!XprnQ07z)APp*76DhY(j1r_FEQobxsj|_5o{CHu%j)HRgiHJW=-xw zi$0ozO`7ow#b!e*c^4yv_^Q|h!<*5bklTy_)Km)X_f=|i8f;Tx574Owgytq_$uVNR zS4&heoLDcyk!c4jk(XCA337$LkHr7@TadiSV3*tLck^tYdSx|$N?snFAy9K_+ku%j zAhn}dy}OEWa!|AYa@E|u^VKgNAa%tNWP1aPVi&EFwY~zu z7705lLDm?3Y#VXLiJ%I)?Frbhfxs5*%-7=xg+Q0()4^6uTgI6ZvQUWKV<6ww03bwkLf?)KjSQ@D&sz z;@wi`98J_$K*`N-EtE2R8ctmYwuHHETLhBSN)tlp5E;HayFaMXP8hxMAq=q?L6YMZZg#e50D9s+eTfn-Vnc6i3pb zem^GtTzTFXkbn6v(fsq@qMb_&S(>MGRbuJt)E?E>mBbBo+NZmJRJIT6Lx$Cwd?8pd zjP4scxl$^=Rga3F@&yO@82iQ%S@Kg945o_eii&yWEN9gW@JQ6#69v=;!*je%mb}zL(C=@~ zuOua?Qcf1rn4d~(e6K_l&)`>6hX1;{{fgrt&w!i|Z&;18s4b~}lczme?*~4P#KO0N zghH`$yQ&we)!1&V#(i^F^j4S+Xom9xp6EW_>D&i>}_@qY_RV$!iW&5UzEgC&HF z>ZaANPCD9e^j+Vv;~)QWi(2Dgk~0Qe4L5xk<(SX=wk#_k@H)NNIE0UcQiH9(!CUi+ zl5_df#aU4+v`@ru`ney5;%V{3G3q!&Ldu0vJU)y~O-ZC`l zerDH-*L)+alLA;np@G%i7;(@{WU_@uy*2vYm}T>e$ja-Fyr*9If|cJGIw+{SEp;`y za;LAOPE6M0kzfy~;(}H)K&|WXa=F6U7NQWPUjc++1+??VdCU2$8JB2IzUAa=>*?@- zc{Z5XeBAiHI=(+4{{`8l2vw{?h264?&7#)DRD89wVgpGVhKar6q_Z}Sn8A|737fk7 z3*J*CE>1YUqNAod7bI`J3m(${?9VDgf#e;Yx0n)kR?!CrcBxzVtKdcN=B&uEA!ofi zI=&>kP!!=Obfpoczz0nZN$QAR=4=F4Ub7X+Q*ycn;Ta!KBok~ShQ!?Zg27~f=vGe~ z5gU>x(_r4q_)#4;wye-Rud&~`o{?Qn;n0>DKxMxwa$V&Dg{q;ldgF-i$ z)tu;va%vqp*#|51rd@)*+XqViYw}9$xv`AXl+<~zeVrCdiL9!dT70B=`kjI@qMHn( zQtU|PduyW(F@inc@QtE|ReLaxLStxUFdW6IArm%jS9Ch{ZvCw~U>+YVbSQgYFy(RaZh#jk zZBNMDU1eqWU+mx=V^HN%UutDhjDDuLsB*zZhkugbnshv97WoPxa}X~yy_tzOX<+}Q zCL4Ze8YelW37GbSy#MH6v6~I)dQD^Yv|d@MdP!k}BO69okDFy+cXlUE4K~mwS3jlj zoGwh51iHh?YYIhbI5I2zSO;~69Efb&ESLuNuYt2w0`-YjVFiccyS0sG3g7H|frY7u zg}(QyD&ZpjH$n+SuR*f0GRv>QcaA&}TE)*|)9vRz%z97_Gi z@Y%!QZNMB8z;IOlaLhqRZR~!NGRD(uBzt!zYYSmYVheeCG@!jMx3(@A(_Mp+t#VSS^NV&pGX#<@Kj$JFfs7~vn0^} z-))x^6}SV+s)w;!)r_$~=J8aw$thObHy3^;6GG_sEmJq+Y@GtX0&G7St2n1uZO+mh zuANK~Fh#b~^W)Y z0RqsE=JD1d=Q;X3>Li2Ue&d)$YunsAZLTf-gh?j@T1~ZdeRvx}xs?ud8WRQ0x{}3V zLWpNzI`-4X=rcRp51S+@o|Cr7*=5gk1j#P#7~lLMaHYh)HbT0P6-pv*w6F?P?TMmJ-_Fu#kFa?_Z*slH~sSERy|WWxo=;Nr7*!>E8^Om-r@&X>#T z#I6H&T8aiAEW!*}a*hgDiHOffx>PZeit0%H)jkv{roE^gx%aqwAl9aLSlN*o60_sk z=GDPFUK2@H%k8HGqAx#*F|@49CaL)o#Dem0jcMEO$IJ!LD0vVTnvE9a=omlXzRmhU zD^Fsprco7x%UF&#g_v^0=_ttQDwhTe3qia@K3J_^-=L;k9(_q~G5hAyaUpXC1^@}* z`fDX2U(TJg_gIqwR5E-TIdTz`6!8+#>XCn7tBmNY4oAPUTb0b@XF+Uc_AMhH1ep_)L z#3j;-LBHm3>ozo^d95geX9>2tIdg?+tj)W10d^uLIn&mkdzrT@>l~<9EB3(}N?O-` z&M%u06eDlfO!(3}WK>7cKgPXP(jOgsBtRh(5*S}Qed{6LhQF)H{sdG=WW8;z2(%&U z^-PBirZ1`xbmYHrSG4E47F9Ed5MEdoVysAxJnwqHOYm8YG8oJ&SMn`5 z2x;e;e6u}@fk@!xK$C+_)6&qB$vJ_Bsst}`v4JtFt=IcmKOM)&8aP82)dAJF0w4|Z zsjq^qrGsc!k$wd8g=lOfb99%-*6r2=-GIIqec=buLYya?ZK>2hM+oet8Z6ky7i{sE z+;|^z>17qmWZe`0t9l3@<)*4|i-+lgj4kMc&rsgwYjQtF7jS#$f+yNc$11#irFHDp z+FVt&N(hC2{31?^(yO;eu?pJjJjNmah$#E#O(m##ijg>qkq=g@np~@sj+^iA8l`2! zmsA?z`ku~=H!pXviP~2G<}@cNz)d?23fO#CXRe^(d5gu}Z!}K9OQtNbA*QHV0|z9`GtG`cM^&k4VACQu7>yu#aAU%gru)c zlh>u4#0(Fg*y^t-^%J64|r6XFMRsn1Y_O+H%heI`WBP!c-xVDG1Rz_YL8twxOQ z0mf1$R!rh|fl3)}1q|!PtWa34%O1?n3ay6(v;Td#$ctI4I_~H9vM&TMWfjfpH}|o! zf|g>TJj4$auZrab5SE$BcHO>^-b_3zNJ3Z>mhOX_{E```8efzdt-cA5v4^}c*IoV@ z%NMa17h{yA0;~@p+Lu=2TRp?EV?CE+oUU#2@qxiNtM`g~F`nv`CRkt=*?xekK)oi!3?A2WddFEZ-xd#- zt$X`I$ycDWZuj^cYkt4n9n_36p-9@I+t$Ut0w5)%6bXudB#)6>p9(SvE`fXmhozlU zg0?j|BrB8#It+d(bZonAkI+1J11iXu&L-cl-bb9RI|2!uHO+3dD$R#H&3)a z0LR(E^IRM~V%4qbi=Ty6_;1^mca_r!Ap6quOTDo|*eQ;V{Ok>1yh;uC(RmaQvKk=5 z`QM5Kq`qL!_st*BKnGim3175d*k5|W6&N=1$S1)dN*4w&FrxP*#yWH@Ri)vZY!T- z4CkNL7f_og3CTC8%>-M_*M?Ml-VXNjjK!W!izZK9Q@wH6 zMImy}ZXcA0hq00NwqCz& z1BVWe=XfSWwAS$M0B_`Pm&;9h4)3&W#py&KF|X$~JB{Qp=v3L7>|wNlQ#r6vFDu;j zy@*=j$?d__LE8xq*O?7-i|1=;@vGvPZOgV3Vx`7wY?a-)Irp(z0CTGmC3NmL_`=$K z2`P1U;L{;z_7PLxJvZu#^OP60^VVqktJiil?l2Jg^ zNwz#EV7aBOCyh%OBXL>UJx*)_Yd2qo>!~BRjf{**V}?crfttkS_C2AMUKT;r#HuOV zqhd`EpvNMFosJXSFJ}Zzg!^g?vH~cGF=oa!v@eb?Gk+T#uLBW;5~@O=Jm9|oApOZe z`V#;JvM(3|xI~PKYNKJrGoantWR7|MWUGHAqTi#ir6r+^ziaiun=h=BV(iAv)T9Zw zPrP&>avH{R@U4aOxdvX3|HIyQhc&gO{RR=RP?X+LigXa93j{@)h!iQ(RgfwmAP{Om zq<0XIA|Sm5r1v7dNN-9{=pc|#1B7@tXO3siIdjg;eD|AsXYO;qKX|gU**jTlXYaM% z^}fGyTq-2;sqAAYnGDlCh?n*420j`deBQwG+Ir2!LJ{bSjubwr>3Dd1 zqEs~8<8~?<(7ORF<3T6J_z~LUG*CEBt&@c zTZ#yBwB+4lLr~;Cp5L=00B-3ubP&PZ+t=^%#2ow{WoqKtLtg(LsrBJOANZ zLSQNd4TpS6 zHv;|eEX@x_0f~gW-YlvF7H*uiqk9{8`mHqG4EmFe?&HD(B=2R_4V7ix-OH-^dqL;=!KNe676ZHFbcT1}Jymm=5BmLW`or3O+E!sdkiMv_yI-v7qF0mWmc? z3Py|NFh#RgmD4CA6Xbo1Wt4Od>x)a#ZH`88dncPKryG|*pNFX5&GN~bz%1IWxujR( zokV&Nv#xYqGE(cCAVI}At;q%E1d2knLreLW4%y9p>`8wpkw{(GlzkA77wm^d`|x?yN1&VZ9xM?!$ad8Ak+5q zmhcy73&Br^K+p1Tzii?F);sQ}Tpr+;*(eD#X+mx;iP4&x}Z99kao$70v(%$&OiB9nd((%b+iDlD5OlK z;7hLxRiLfGQLs8@{3m3Je;}#;!RxaDQ%-)f{ zv~qdUstLovL=5Db_E%N_X^diBU`3OJB_|1ht{m^~0`kjeivohyrrlFlU?|_;7`I3x z0b&V1T)+ScTMs<_$9vEgALKT$W#k1tb=yzm!0pOHUxY6PO&iaI<*TxP2NfHH2hD@= ztrE*8H4`gZ3|XF>o3UQC{*a{9G!5=)yonOV92X1%4Byl^0paJy|1 zV12*8Hit~}xDAZj6RD}dw^TGzp%JR&YZn>X2xH`LK0Yj#{YOnAVfL1c$C6V85MY{S zp>xKkZkFiF@Z=}!RF9=Xp!*wx`_%kYykyU%@SX*kTaJpq@a;;wP|uC*RYZm;@g?wN zO*=duJL%)vlInk4JHG#R*7T`Ir2+B&)1|P76HfpaZo>D(yn$_b1hd5t;)$+*k)JI6 zAd$=DC*e&){gj&MFu#m$PSm@OYl$3iiRoFOTQ4^|?4xV>wyndFc43K+Od#BfgEb+X z)j%teDykovh2;~49$i!m?HleoEp_5tE313t&O z^7wADO|G_+OCO79L~+_VwWKt?G|O?c>=rC9**tL!{@739!uXaNxQ-Vvd5Y(s?4@1E zs8Q0l=(kdE3Vj}qCv-RXD=vQA*}O5s0aDUXt#y28t_37vM@Q}TGZnZKm0%gkPj}I3 z=Rd?Yt`V#$n#zgs5R8souTsP(1BVG(i{;o1B%jcNlCQ|$>B?|hq4N_F8|P@@zoRCc zy(YRPgku#Np=UeHGD#w=%e$;AOVtIWB3@}a1YNpH)2exsZMbUN;HnH|Zmzj*0`yfg ztxc@~pT`Oja1gncyYEewp0(Ljl7zCu_ZH{$xH8LnBK+>k>B_SSDhPqrxl*Sh-aYEJ zZLsQX{Bmf+J_(=?HG`48HwHN4r^kX!cSf9V0TFnb|Kfv_yHTof&jX(WIqSEY_C2Mc zFcL|NFV46dGNkH?MMZUQUrSl~BiL-Rxh^)*@wu9VTW| z2V0}_SP_>!%K=O}qYppG*YrK91uaRR2P!_Wqluj9`;`aVx01QeskjC-ryfx>No?1v zVU7KZro@gE`#@%B)s8qL?wUsbDgSaCSPH;RjQGY^ul7pp(=A+IBUNNAs+@#$u6$s} zz_xim--xC<5gh)Ib;&F;_JAB`Q`Aeeyd3pbn*NE$ksB?aq@#)5f?~Z;=i$yPse;!N zGE9sw9*SQ!mS8?<@xCRf0@rYswqY!sJYxP!Nxx6|68v;3FsZl5tV|rzJk43D% zZ0Wp?B}*rjphWs{Ng)%_h6K^RU!jC&Utvt(TZ&MkW<7GS&qgj)N@Fm5_)AXsfiG3>)F1xn38#{MxZO_dfg0V>nG}9? zadm92msu9~;kWZvbwLMd=VVK%>_-VFQX#iGY2yPWZSpM+)zhaYSDrGch^U5W>(Fjk z97w#HklYkZ>j6wZN!nRjn65bWc9zDi(KyUL20VRN9mj*0UZpZwCRX`pjW_Q^-&6{# z9Vd=K`FB1VdsY^sk~k}#^uiH5V+Goa6twP_R9R?HRX{B#r0aM1PcC^oxCJ*LQiCPz z{OwH2f@ijKpzwfbZXXmcaumw~aZ!uD^@8Qbh@E=YRz;v89{m>3(d%y{Ob#^O`ggrS$sofdw|d z{yZCVz62p|`$M*;pJ1xw9uGz^qAqy(`cjL-p?)DTG7J^0O{h)qNx+c~J3KW|gpob< z8?t%mf%J~3x}j++LhX%4$Y|nO2ca87p3^b86EfyL<8?9Hl{@Zz)AGwu( zcfRIFJAS;r2x$~i-9E?NRk7_mPIeh~2gSOWKr-Cmm6jsa)8n-fmhCMD^&hs}S<|?z zcwW`kS(LiZrN;rMn6HWi9>M4tE&Me{b@!HYpPQ*5H(_2+%AK@}xj+JyD`O2=-lCQ! z3@pDv0&2b1okNlx3jI{bxCjpy0)Fu2k?EiaYNR_~V#%(Cwe^18Y{ z<@(iMKfKVftp|z=4z~!+D;F@fSD$J|M$`0?xBdG7ZC z*v7+Rs=|FNn*6Sk)FK2khaR6)aztM1G0iG%9MdmA?sL=t`RdPl>08f--k(kBg=zXgKgUAsj`^h z&**9>BJz>X;mI&WwS~4ZAh(luJcs9CweH>v2yB}g;_9KA>G`JSPMtUqw$)a~95ngI zi4Jn;+Dt395w|4GciK@xN>#M_PawRQdL}jQ>aiD_7*6D|J55)la3Eu5AUBg)MEg?CwoVZ`#|^@w z_T?em>ZQVP^$afD^w>GA%*d*AfZV3$YQ(t)W{62mxwS67iPNM)1;|zPlNir{|5i4a z|6ZLfZ|DRV?x&4X2x;Z2+M3Gkb8-eE&YTesMJJ-$n$dJ-FUq+f!Wmf@Nfq#;vEuV> zNqdtDSs>SYX7`ZqhuaiGW9pdnriU@yA_eJdWYfm10v|rh(32Trqmawv1M+nvIi4HR zUM7>JLQQWDDc!Q_OV@WQUrBMs$0PTB`&qtm5ljGLm?QTF z!yC*mj%JpQW<*@l@wPZea-P)^#jde~1iLwgzqg*`1COd=;b(QSOPiBSR5K9*IRK7R zD5t?4z^<$Vy?l8Fdqt`S%=buBh{euKX zl>bsYFFDR(Pbi1SYI3y)H|y!Ka*VfqgEzUTRKH|0RG6g>}KHh2=LMBW}%K5u;k zdDD_TDAPFVqs2KZuFJ0y@Y!CDe%<=aUw-eilpIJmJtNpyK-7duPhH4#UaSw0SNsQk z|Fi$s@CP;Rs8$#sFB#f6&WZvmEST%LkDG7tl)x=;1JI;7*sBi~LQ|~AM5?kp7Sb%5 zNb7G|9vJdg%B{*-pB4kIuZK*rAos@cy$owNoj0C8?_sh&^Lv%*1l%FED;hW^XJg^N z>{6J-@&T((d%$a}Zqx3*NCV`TJ?aNdfPL(=mnP2EiNR1s19yw`1j+^L9?|p8u8|Kn zLed;i0vjkodrh@zTUxtD(N@BPE3C8IpFiP&Ke$I_j=EjP zT8NJUB5Vfehv1f79xsq%T|Y4tl(L#32X(VOj(4QL^g>7Ap(20=c4w|`1t~O$h?xXN z2U1DD#bKk+b2p2v;_>tJQ@&K1Jucqq28s^OJ+vXuGL$yfD=nhIC4LK9=ln3b_w;Ba z_kZ(e>>J-#6nf9)o;S^$PfxZH465G_$G=#l+J@yZZgAV_5Rl(Z{WQx|c_mCwNp1#!FNj4ZZyu!KAqV_YXrL9s&)Az{md{7j zZ5rlZ!;J)UT@~ow_?Z{^X9Ly0djEgm{Pc4dFDyRTk(i)Cz|LtuEwJ>pSv0=2P+c^e z9xb^;0GFYk@b^%)gXzCv@2QPgf=uNJk7W2W?zfur(M%qc(=BwL=rgsxw|L7S?xkK^eR9DpjyksXiYLgsU~E8_4mEy(FtYm=Y2(10>o zjE}M|Bm4W!dQndybK(+GB9O&t(KNIdD9&tuP?+2V3{dN#fE8?_2Y&{-wc}9K&b-j` zJ+sMJ!$ua6w|ulPcT7EjJx(LBKQU~=9G+FiJd5VA?ww~PFXT2_OIqqX=tCHEJ0A?! zL?2@Pg#q+uF7C9~gdH%KEdX!)n5?S+;LuMsr25-f3e^bcs)_N*dc?2J1syU~Oab%T zPp!IBU&&w&d=UkF4w>)a{v9Ms3#8gLnfw?fSyHbSpYF>rjvtN}%1{YJbkr9hW|o#= zmmpA;mk)B-J|Ri~7SAKdHrAi*tQ|lPlonn)IIZ?VA%Io_dkY|O-d4yu!5^i$`^M_f zj>y8wBhi)>>|Yc!A6^X2vz$=!6o^7N)UXTT zY`p#55B>Mbq3Ywpk6#&z7n=oJYATT{({o*}>t^ooHudSfNuLP71KuQVVEsHDv1s2j z^4#x4cG8HUSW@faV~YKO69mbbyA$h#@gDa^>R}rb#`z}-a^>UoSAISKBGs68h{s}+Y^z$nYdDKcIcjyG>#^%e(qR8dhBk}9dh{?KO6Zwl> z^MeF*@Cb^qJ7NB5jq)Fu@aRHMCZ0q)+x6GHhqlBW7kFlq9k`DzD%MjLTJw_`uZnV- z6yIy1ylwK1xJeJRcb_Y(VOW{AUV|sF^;%w^9wD`<+PNVh@$$Py{L}9>u8^n$nHk|I zL+6i(58-MOg7e3s^WAIiU%iSz%EYPXK&zBdv;&#QF>c`tbg7`C4bwgm7st4dre5#TYp=U~WKkslm-FWdap$e}hMFnIEZLxuG zZ~A10?2Be@UX9S36=wi2(Z~pYTENx~vS8R)51Cx2A&J(l>37%3glJFbl#f+hbkZ+( zcQ#q_n0uv0U>vg{uL=|W9ALXGE!9}(&nemE07{fh@qM}M&GeW5dEA@7|K`{>J7IGa zUi6e;usZFcpr=Lmes*~j^Omc+&Pn@6PEy4znqbXHw+u6HL5!vHMJEQBTk z41sC^4^iPYBQBsQZFY#Q5q2$ZwnOg&KEQxDy2alKF@GO#;r?E#R0sUq!BJIb?At3| zK2Oz0)szP>LC@dj*`!4hfXGIJL3MJ^)}(m`_h(2w%~eK8J*B6s<2*w@h=lb;%1E9g zxo_@|d7cKTHh6zoP5+ZkRX;PkN?ln*J-*l4nhag}+2F3NRTcEgy$_&KE4<#<`wmi7 zJ5(osx^xcbdv?4FH45072#7mYHiZWel(_c7QHOnpZ?9yeonKb9~jSGd#4h#0b!cqsRF${r$zG#zAk7V;KRU8kpc&ls`yI>@~<2r-7v%Nf|Q~KT4 zIqBa6}^rmu@XZkFaVDC1#w?lV$ zjR5??4XoC3Do)eFggSsD>hP9g!IGt3ifBL(i4!>N=KJik`>2L=G?FI-wyPw|O=I0* zz#0;0Aa)GJjKtCeMHK1u&ri()f zHUb+463ph(`&HKzFl?m7#{)zgL2D<0bKt|?)NyZ;Uu%&)21G%ji!mDj`lAPYO8piR z(77>GB4n5AT|ZQ_<+}LA0xx*ry1Q`k+O?^TJj0blYeh37xi(H-2WGHRQnX9XZ`_ftOa$acG zp?-nsJxXcVbK+u(sUXuXD4udc0)?!3ek!*BpD z((i5Ho8}#=F7PC?yK!q)q~>y9u3IZ<7&l@uiZX<1KvldnYblD!uflJrLfQSP1$>^g zos}hR(mkRxZ7p<=fCf%SR}c{h0L)))I;sJ-p6xcv^;%b77y8_L*N-!Kr^9XBLwlAN zY3|E5B&>SLvXK>;NZ?#k`WD|}=W(M>in#bxC(PxTsRjPD01~{dHI}NW;yilCf$>V{ z6($-f*t`5ZW-DdHIM0XL={q(0#RwaY@Q zeyWrvtCrwPEdZ#T_Y-g3)@^x%ua;xaN~++M?5>9lXyaZLhPkLVj7_!CI>jX)`!#$A zeU`b+;-z03(Naz91K&^~dlc8IhCJeb4nYNpQi|JbOjEAxBFZsfxSwwCCIC3wQ6r%(0HKts{vXulYCwxT=n^v47 z;SkrLLF!8~H9PfL%OPxDVw_b;RGg_EN<2x}RO7sJV>+5T*JNO1P4hZh1;K42RWEM0 zplgC`N@RVESG_xEJM&RYk}z}y?Dqm40AK!Kk7&5v=0!I?q0&@YL1}joD2YT7hVHo9 zy6-nHd*6h47#B-|DQGIF*yYV>psz-{UrIH z=2$D)Xl6-${1DWv&Q5a#qtT_>RerskPP#=o+_UXq(-+na-!e zCvAs>yiW}3n;gBlN9u2-%fg!o*Cr)#oF`>Uq8n&x%e;7$FxKpCUWA^2AS~TP+|g4* zhDEbC?bW??48-yhZnU7?DNlZVRD8S2WrK)MyJ&~r2W(q>>}nBU4g8z8*5g8}+phoG0Hz*XTcwU3zKCB{|k3eOUH_Svw=-O}EgsCj|74-79mI9OnXB=P0a=*h*1+;m3(ahF`)eY4a*?25F7G zzQrdHsgScW=Y-*>IDGw$7Xx*o{2-Egy*6cD(IhBA`O0IWH18a077A%!ILz_kP{reY zCNhJ$^;&O-D#GgEvB2vdnFAoQl&{Te!EGq^)){D93hqbb(m-%fqBvoEyq&F5&0_3% zd}>^laIe)gLe+~n3(yeN1qQy(Z*G)HR^u-RmR_7#zi*EEb_@MfVdRVT0OtC96D7pq zxSe0}Nqntbp_#ywxQka@B>l61 z%zt1dLNYTsNG&7JvDvPOOP3;iHo50?N3_PVdeIU*1R zkaMM~H!QTE^@CN$3&_7ECV;u)L3BEbk7$LO@(1z6SkW2wHuS5*6!wv>ISYvR!c>^M zS!n0UrMAPJ_#>^kTTHGkrxv)MN>IwCh|KHk$_Uh{1peG?Dc^HY)WhH~CA~KD{T0XNNM~mE%vCu3Z@a z<-@1`^3@CdkA^kDVH}PrAJCBMhKqt8r8uEj;MIR8-Zy=_c?wIYVO+4P5|&cxw%F!eR=&Dv-1qs51b!{lq;HzSYQT2`bm_7K+(p;-@LBvGp)PJdiuEw>F(&Ga}}|tsdP! z1uLo?9&*#V(@)?b<`|`xeO-woOedVbWeQcV>C>9Gc3rc-k>SdA;L3Tu3ub)9QpB0@ z$|z~i*mXu-F?AV6CnR~9XT!UvL97uS4avKa)+@$-Sjiy|HmPH)j>liWY+m==7;1t$ zqeZdqKswq(jUX-as=QM8&8*sar)JbF^hiT_^^k*grmeOPKD-@q>c{RDRrD5H3Y4h6f3o z3s@M#&jR7QhTMQB2OFaeX90k9$}V({oGA=TEM*ReOs0{@L{n$UM9UXuq_s=pXvt9oOC7H&>N; zeo<5%q=|*~?zvIAX4Q zJ@TzKT{P9+s>`>65=nB-ZxiUR4^0{v+UdhoyLaDQpmThoA-;qZTWu(7Ca6$1x-$>> zvQVL{-IkMF3#tNNok)onZ*DhsAGp}~^3zb`HW5tid=Ah@ozAsdZ!?jQ$M`9@!sEmYAmkcpHa-+$7WwdmtrJU{Vo!u0%lg@03aZC!= z=w_qPI_-lh+exX)U|a0xt6pd>B?6lMTL5^SIrwNunjIayEtlFBg)S8-g?9$f9hllhg(2*af}HtUO4_d`bg9 zhV8&D=j*$;>Wa!QJ9i1L_GA(jIuOfj&cU4LE`BR6#4=i{xaL)?tJ;x&Ba?=&lW4y-sF( z+PcG6A!jwcO^YHW0-l|74)&4ww@Dt#NVTM&2;nap99=zvJ0I2Ie{(Z0;_iNBsNa!# zb!#7{dJjcvQTsf$SO4ps1EHAy=QN-FYCubF=6Q&+B5B?Y7ck+glLDvLBv%aAp!3LOnlCegnmqB~wn1mguQb@;NbxUrZ zTTAE^dy6s(QPc#2aYc-E{;GKo3h!-<(#R{>;B}!UiZ!=nX1Q8LY9JpkPE2IeXHM87 z+e+tqy42@T8_~MSxMT7%kJW|Y&LbZg27_BiX@XZa*16lHg(^MNvq|LjHX{5z44-m{ z(58nx$DVU7=0k_L=Jg`#E>uwW?>o^o0N`#{}W``Hq!S;w8C z?;!c_ph${{QwO~rfIn%x!zb?^kVbq7dN&P5{R>(>zQ->(w94%uX`3X12*W0FyR4Qc2CYVrgw|N;^y03gqSPT; z;9nh4dO!j`B+KT5~Gr;OKtZvW`XDFECi&siushRFx!E^?xEkIAM-*{6w48 zw^S7()Xp!FUnZXs={ATz*D7_n{g|?hd1Iu!vY2s+btMsjQ7?w1s-ykvGcBp`6vfmN zHydd%YS_8J)#F-M9c0l=XM?Lt&_3NMJ0kN?&y-iVSzOC#4`&J@iomZ+M^{7a+B$h& zQshbBz{rg*O+0GVqiKu2a+$=f3wij)Lk zp`oH;3{&Rixbt^%!)i7St3HK^J57PFuE8rq{J^5)-h!{bdf1`x54JUji)L7S%0ANW zLn*A>vV)M7oJ$V1ue0e-CSulfj)BQ%j#OIF}c)-Eyt(EXHW+<+AQ&zL!6zfb?Ikv8ZP#G)T6J$67IdP|=HkXM5A%@4lrp zx12^`>~VLb@JQd)mf-XjO+N2JL70lOWgMBp^;J{7^+J!^Icw{bmz}ObJW9x|1{DjCb$?$UA-PmBZbd1M}u8G)rg z9_}F3K?m>Z*|%K18xgDUbT|tjv2rlv-%f&T!DcVYt9M+;vq&SBF!qK8P? zoB#lZ%UZsJcIQ(MyNZT`K?ndLpbas`dXQm{$e}HT$R-S${d9-BJl$KY39Xev1*m`n zU~@q15m_L~4_LYbN*x}-n*byL5YRC910W=yz}ry@7_I@JnmO%ghp92>t9Qf(N zp+`v7lSLps{pVjv(UgvMR~@`A@VJdd_KP;`zf{x3`K{EvODINimKz!V;X_terFFR$ z8Tl*~Azik-o7;%T^WSLHljC%+&*GI$NHctbD<6p-QI^Otv=m)ZqQ%n%9fzm93I3D{ zkIQj{&*0NY-ovj;Q&b60ul$N9)*=z@I7qmXwl?0t6%1OGlmc>QG{5A`(t(_rg-J!2 zfbW|DjoT=I4xIu?f@2%t#sPYpp2N+!E%^G^5e(?$e zxe75}s6iRGHk~tGt4&-x&W^DmJQ$X|dyh5$Wh?falsl@=X0?fge^b(qKWP8Glatcc zt6g(Rvr+lXXz5h~92t-ajb!q!AreQE%Ns-ua?VO4;VDC#AZ!?iRY>GenUzM2mY;J& z?65Hxc&pR9NFMA!ECV+)~pwhgC@XK(EVMoy!?^W(cAUE4kWj`lNMd*U59^Elm| z(jjsnS0A(`f=JbPP+^<6i-l|sQ z`@*?;27K#LA-f~c7og0=mNRQPE)o2qu_F8x11^x7?@eJr?!{s0MkH0v2_CsSfR-DK zJUu;BkRCH!m5U)J_WkxoF*hQzmCbk-OM_qmiovLR67mUl7B<&QgLoqzHv@2#J|<#m zW<9iK5?z?s=iy%OrCXti2mGWSY88WpLt8eN6}U`^8XF4o8A*}zFBcRl35oA~osHK- z_D2-Te4P0z-_zv6k_GZOnSW=7GH=t}x2BVS{e?c6@KPBa1$tbk*Q9(tx?X3H)+i`@ z_2ZEV)K@7wsBf+G)49K9r`q~64`Q4e=XbU zqNhE!%D1A`PA!mm+Efwl1fHd72YE~^G%*dJc)tm~2lU?vMd_V{>rgCm(oATbtS^%0 z{d6u*bjmDKhz5lcJf>`G9wL``r4(%91GW)wt3we1I&pA{0ad9hru?%3&ou1x$mIs zuv@1~#YTWGM@Ssgew!LTaWS&9Rj)M8{k)Q@!nq2-q3KJ#)Ds)#m)%q0u{Clag~ecX z(qPXs3fFCoc>t{WH%Y!93CaJ)>)+y8#1~vmd|OLYgo5bR*WDcJ>Yi%JEwVApb~hNB6{qI%h#tPcIEXE*?@;Q#h1YLcFC03z6RpX6k{#tyCS#el`k9S#9zipBxZ zCehP93*1n29fE;hXS{s7#ITcZ++b6@*x||*Sc3$mF|8xA`y*|qH>MeE8!qna1@_5pJl`{NKqr(57#Q*tg!R(ygT4jWjtAy+& z6TX$2d7O16U;!e8^Q?qVIANR5v}7o6JS!5FhMU`i`8FjAf~wor)?u8@%`B&If~?gjaJl!-X&9OMw_T&c!8U+{uxQ zCt{7)84gu(ktPh6!WYwGh?T(|VND$Vokl4q&1+7RK?h6A3xpR~t_>0p0rG>5R28L- zA5%57s&{(6Z71#&`$-E7zT!1jPf~AqtZ~szE-A|Yt!U7N^MD}A zIuW@VKCVT)gfdON6py_^a^rgeusQVbLN|cIslBw{v$zafn_OzZY+CX-=&oO=OX;5n z%|l)7TZ>QbEAD?nRB)waWa(NB^5{ece3@E!dB0xebn)qH*wzIh90vf?HB?|BX~a`o zlnh>4X6^edds?o3@(DXkH1{n<<;B<8DJ#l6Cv$sxq@rM{{3jm_Af)~4x$8e|`~R&d zfU{_g-i9?aH~6BNi8p9VYw%hIQKL^;B#xc> zc-;8ncpqgL1pH~>BJ>5MCIx;$U$!o4T4y9)B0Ry#hLyyH@hf@W za)}2xbCr>)I!<3d@J%#8I4T5jc}w5~>&ZQLBFwzvc2)V0Jt|F%ELb*Gp;-nD(x?5V z&kctjLe~mC@B#h2D|4GB!C%w81#Fxa7)G6G`>H=SL~aJg&ES0ka=i{uOuvIln?;Q- zELY~!73jNf=<*iLheKHDjKs+WKOW+jcy;El8jB~FZ{WTj4{5wKd#h|(jJpilyH9aiiH*Bt-oZ9}sXbnkFkvA(u z-%$F~8P)BlE5kJ9B&EI3KOuRmP^wns*$Djc0~P}R$ON3Ix_R%6!AROFFr4j-A*T;u zlYe5!{i`l$Qiiqq2B%Bq`0}{E5+>+FjTSMigq7)4R9GqJ#%y`PKk#4ORSn!xjOOcL zS+(}2B3n2$@p78;P|!HM5OSF0V-Sd3&emjN`zY_GhDTDa3LtRkcGCypZ?M+-@I6V;buY>^l044D6AbKOqaOT<@k82$#8*bm9cu@h7)$hqF=~>Bw3;@*@ zpf(Ukbfg*g(aMbhL)ebcmXa{@mKqQ4HoVtr@?xM@j3STDPG+_owEnxv@TNIRMn(Rh zXF`6AU$0*-*phcx%ICB74Qcc9n4+8OfOd==5Q$#s_YJhZ-MR3w~_cbJWoL|c}>%hTuSmV}Ps|2#r9 zKT|#box@9iQ;1|hz@{5xf=J!{8nti@#ru{!Jf%(|{^K8+Ik7CM(PR0$&aRFeX<;N``r^ z>vxbzP4N63PX9-AwwLD5X+}-sQF!M=&7z2C>DJtCg>rSUfUQ9b%IU)O3<%HMF(N*TdtzJ z*Pvin<-a3{+gUO7R4PbK2K=ZUc%>=w7H2yA1o zqocP#USru7GPBxv15;TpqHA_N%{O?#lqk#ZCZtU8<(kBriM(D4&RuMKJSDZ z?b^?4)uD=tiv}RHa~i`B6AxM>Db9yhe%l2A?+cq=1gG)vneQNf9bH*RSGRaxmje^; zT+qcTmy=HMZ5b*LSp@ism6zCX{Z)8_ycAE;RVP=E!Hb4E^j!W6BiQ4OP65kV(FqU! zB0xlBmbE@aGe&ttU!%PK%8?2emv2cdWZmtAvEBsQh6UA*?!O1O(NcbV)!^JQ_if|W zUDj}mBlz1>RmuIe;RN_V0Pl1A!gV9&F(#d{ia?@@(Vi3y9@Z!69Ba+=C&W@Rl2dx| z9f<()1}F`YuS>J|TkDSz9$S=Y-3z@>Ze!o|L`HHYLT_r!L!iL;E1IfJnxT4RWn5_U z2A-kFemogxD1ENfku7BPf~3|QT2tZ(IWypw)L{n@_6~1M&V36upx?ro66c~zCT^VJ zHr7Kwb#$Q$C@v4P-`jM*SEj7E7025xnD5uh2O(JAhX-C8#Aot%TDA4!)N4l!5I{}P z`HvZFwx1@{*Noy1^bnKK)v(nPzoY2yMTzQ-%U2alp=+hC!^~cd?D^!-yy@{}ao-f< z9Vs@xW8?!!6_3TYA7D9A#)09m+{uoiDLL|U9O>sx#2ApOPbV5Q0T>BTo@ZXrs6bYQ zfJ^sm?wchlJK8iVJKHusGBpXmZ33v$(o_L7E#bKA4!H@Urwm_faHKHNl*u3qg>i3UbTF zh=_Fi;rJG>((P4Bg;^0*kip%PuZ~%+bL|g)R4Nt;^$tC=4BRh&DWDA&PRS0Cq z@lp@6j@qoN<; zY|I63=r>0*F+iYgCTfO>Dn4a5T@89;pU)(t4r>9;Vqz=zF!zUO7~Gh|V1wI> zx}!YwR(H_Hc@q};m&C;4>(+^A>kLS=G5X=d1ccJFTK_G?wI;KOQ|5*DrKFBkQ6o{^ z#Tug?w1;z~FJky-HD3q$#~5U;z=SDj-z_ zr346_P=g@72|R$(LI;r|NRg^Yuc3!t5?ZJUH9+8*^M2pVvqs-ZjaVnba2KXoW}RYkSj%QU7F#-Gy2|9el8jh90`zOsf1DEJlIv9o--*; zxa=yk0sGOwwOoS?frzh~@((J!C>X2#G%%x;7Yd9aQ|_L3WQq9-mI{=V50HyN~53D<~4E9_5A~9 z66P~mkpLs{G?n30v$RubBRa(`HT#`B;q1;*DN)s5fJj#{XSDOpfGW^=sf@MCV>08r?1Asn zH^UZqP*O`tNX1d4U~{N-E^Nc1KD3CkJA0#D1iEtagWOPuKpewq0WxCqbEybMwE8e&$xCzQ=Eft;t zEU!ruO&!w7>}~My_ZT-E>pSkZ`}_FuTJ29tb#i)d&Ql9_&zT->=Pnq}7tp-f+{Fzyu$fGlkY)PrS2RCn zwapAO6K=9~2)Hr2tfC4|gF&02XT60Bt@R1x)_QK9ft{6IjTc@%A1mZ1-y2w`K(WaPp7P`P2Nnn>XMWn(J%Avr`RjJQkQeA2+wAc9`zL8L zE^dWzo~0wr39Bx9R;mgHo9Rbp%L$}$aivQhp@6CT`hm`(Ao)*F)q;+>9#E&0_Z0tx zM5oq+)c^To z7+&^GkwTu^hyHY;gz+uStxO|on?1YtJD-n~qt~{FG#u`E58_ z_+#Rg+QiZ_7>AJ0R7BW-7|$J6U&&R&#d@q31NjlEF^y-Kzd!wRIg7M=+MOQ$gmES9 zN%KWBpj7)19WWbOMe_8PNa{vf`KZCOYmUSl&(+?sn>t*oE{<-VJ~bpl)=s-dXstSq zDSYo8?oSAP`Bih`j~#wWO!~5l6=hNdDY%$qjA&CO(tKW#3ktNYl1jWI=I`p0;a)(H zb-}Or+%~R?FegTCHp17B&6=%!?D9jdCUmWZ_%m731R6hI+VB^jnUKVL@-&@?!MG5s z<8NzH^t^kNSFZrKiy z1qDhI(E_^NJk360zl%IaN^H7hU1ivS%4=gA6y@@DnMmzC%QK_cD$|%v$O{pEO^UB- zKB4ou)Dml0o71gZ8a2nrHFHfy;ri0zQN7a{7j8Zh%o&+)EjJxlEEQjjuk5lFWC&Ip zqIr=BS;7PihAGGswjT$#e8Qrb5PmC%DGucfs+_>?t4pmwSAClJW(WunmNEa|qTMSR0cHCBF#>^9xAn-f*`7(-%lZ3zreN^QJx=8kbLG6+8kuL|$B zii2GYE1FrbZf5&PWgn=A0X9(o>_h@FL}lpQ=D0$O4zdy=fYa9YzJ2 zJ)`AExNOu(l_qSTI4(v}%x+i76jz#2DWDj6iO~~(2)I$9*BbN%=2IuWYz{K2&$h*3 z-$KNXoZd!#A3IL$oKK0Xb@MrV>8Fr4=bMa00x5G>8v1t+_~Wmn+O0E>(OH@acfX19 zcz$lZRkmmX6(ZO0Z4P?caM?YV7H;(Q!er+g*36dXLVYkBR9gAFEMH(z%0#k$6iiZ5=IB451I5=B*sC^}ge6n7AL?ox600-F|d{uZ`E@e2O2~ z_xR{gB!JM8IV4%6)vQl2owgYX>NQvwetSXS-iy!jrQhdIDvUHp&e(d$beD=5M-TTK z%WH^%arzqz?=E_OxvVG)`KI|Ev}$ilRtBJo+dAb#*ytv_{g1_t#HEBg95BkNN_}9f zHfu(o@5)2y8$j6m>?};Qy1x!@WIGMypO%`ZnMBn&$gmb;Hy;e=5(9%i(v=hN4tF{r zDVO*xc|T8lX}u+nq;>SnYobN2d)7AuU@@ir6(86(gpveF0`}a@9oWJ;?UrOBn;m`kT`?X8tp9S#0yn=(4e=QfG zM|OLpo05!^(u$mf3$Zu2bqhxYW*ySgvh{DESWkFr3+OL2pXa3QdkDrpeEt*~h1yc9 z&^p9}Pa+Ms{{%53KIsgRF(e;Deq;T*Mfe-1Lc%TrBKk8+%H@q2u5g&!4yN>8z(9 zghMl!2!@rv7YPorFF(5Lnrj+<_w3gLU))uy2LcXYLC6rr8l%1+=`oh-lh;RlxI3<& z_Ne=lSMJKV4Uk^8VD8GvNw}qdsITV!5z%BwYAZ%qJ|v#Q*SOYaKem_Z5K{dkdV_NE zi@O3%AGkQ-aE%`|sBpT8q_BlLZX_GeR> z%iL{XE|2^QMI$Wz+qx@xr17I>2OBZ<1vU4aiX=WhwTLs0y(&tFKwz$78Y^#Q$o_lWZ z@(bA`N3wHOuGN3RHd|`W(A3zXfZ$kl*>xSjGHID+Pw0rpCt1bT>W;Ws5sP@;BlTgI zVZV!>g_;3uXi5P$T*b4Ilgl=SiBXbMa!}^Hpu(Mmt;@>K?b#P~Qof|-oqy-)#vhgI zr`S*(iNvx5dW+^qLJfyw2bNo}TzGE*|09;7^CMTJ9_bY}8O?$ap}ngUqUysLd3r%R z-_7`ipW-cQs4<2T$F>^|j~*$rGJL|Gy16HIYTDzTjlT2zJh27jsUJ-CnS(Q#)aQm5 z-gR{duWPA@sXX)pe9MYs>qOP7>$Rc`HTJ`I5IY=WcHBU~rgjNa*Eyd+bJAd8!JA|aXgb~ zACJ`#Y@MO!!?^B@T-cQq;;l3=m7d|A+af$6Mv(zyZXMI70KB8#ly;Tanurx@a!PUm z>kLMOeX8N^h^JI26U9glk|j_^bp+v{4D9);>V|qMoJd&mg$Ar22xm`^Q(~$6rONzk zg%)U)o%*W|8krZ$WBwqc{_MwVl+i@Xz)i{OSfgi8&!t3+XcN$(KLStsjVYq*P1c8W zA0_Kljv)7drEhx(NFxVu{U5in$U|ztO;wf54-o{)%VB_2^63cjRS(ce)LK&AGoJao zOSQXZd)&6Lg0&5*2E7g%Zf0Z7Nc7`_{^LYx@-C27_;`q)!D#He!EF(W78ho~I{y;> znX0OrtED$C2X-%q|D2aL)YT<1C2j z8~*n5yG2(8t(NXU1B4WYdqh}WEknM($31n`pi^YDck?~xPAgcU51fzi`pdMA0GQTo z0H$?Pib~JV@;qFIHIdH*=;9rWzf4hR!oIbEh_ucOqKn2p8Nf#w{g)S?CW*DtaV{t^*ncm zY!k2>ha=sZ#C8?$Iw*)vu~*CZ$sR;}Xr5$-jeLk{sZ46#Q>z)-;DFyiyumMKfo`{P zdTu#>2bc7layS=x-yQVj#7`^2FWi+AaOi-%-wU~beaYhJ*kS%oQyc>**FTb~Oo{H1 zg>~X{KKHB{kd{|7+z}(ILVhcS1sPwLyYNHXz~fcHw7_l|uAr7@!!1TAE=6*!@5SXR zuBT;j@=3iKrJl@+i0ni{D!RG=)fWR<@C&h@_z1}#$o#T{I{s0vLM^V?3q%Dj0(l)X z;d~*)-U@TCxq~?E+WwvMt7obc4tqN+;gUgaTx1XxeTm|V5j@0w-15h|vxynQC?X8@ zj9Fd{S0&b-JbL4x|DBkM^JaSokP7fkdur;gxuxP%*MWmFhdTdkYC#s@gV?7Zygb7o znat(hltX?7$Q4c-rgYFAe;D*el_j>GlhJv1wr%dfb3Yt8{|JLz<8k~GlsWEqb+E!m zv{~+=jo#xcBgt}=Tv?ap{GT@Hv8~YCgg1Hag=2*UOqN+Lpv^hnD@RF1KJ`28N6np8 z0g$Q3FzlJCCOgQ?143&2VnXRd{_5BRo%e8`Hfvc{S)M=(((RV220GGN$-ShHdlQi_ zieAJj$A^?%pH%fe1KjXFT=x-eK-=OYAg@sy;AsIj*SKXC#fgFTF3UClr0MUCCRuZ{m(*(5WB}dsm zH7yl2w019nolN&pyk;WeN!X&7Y0cNt+>trzp+V0!ZpfCtCG}9SY$}?&NH$aPdIko$@O>wwTc$6)SxwsE31)9;{W2FI zi3z#s+F|}7Zr!c){fVg<7d5N>F<1xl5wx2B&uhXzIHD~7r=S^shkN{2`p*0+A^Lxu zR{z${{W-XT4%XJd1ZPLw*}SV>YBgAHdsTds5*CDy!9T4tniYaFlWr)UTDkwM2&W8p z|8iB9(cJBJUlcXka}`KkmmPv|u3+4f&X6H|3?$V3kS6Y|J@2AsAE}y4_?R?Ll&Pcy zih4CP&!(%0RCc&>q+@)uGW$n@x8s6{CcUN?ZZ)kl478Q}EzonLevgCaA}NXXu0~nB z#WUu1;h_vqp$BUG{!UIXb{|oFK!{>Re~Ih-GdUA7ySGT0#2thAGkj-Ev~=2K*OW@& zxgmWIET}WkXZ+>?;^Mp2%=w}svUG{{;V?NVaIx;h?zpogahp!xYCTBcXhe&ABh^c{ zysTeA8N2N>*Ttd|HZHFn`|#8L(-}n&uHLgAU_7Dz;ocfmM5pP37CO|PxE0^Np!}D? zwD*NQ(sSh_awXxL`o?L@M9SbO^{3(;Hg|8I;!rrA!>9Sc`mO=oWa6A#ZPBE4DFOvJ zbdAWld=!9ly)*i-w?ltjU}rUAX|=~}$d_l;ElqH!qJ)|hDv?!yTd&+U^2j%!-wj98 zc0hGK)=fk2gIbIcxK$OHk)X{uwP3wJy4>Ny`F{wdEcERu#6^$PUkw9oe}pjL?FjP-4N-fh z=08EUM{W>j$3YJ^e3W=v>UPin?Y1at>GesPF_6m5Ch;uR5{^ab_pW7Ml;IZ{H7?yL z(FQUv&toIx^rKF$SQ&DMyGkU5c--98y3R_SsegK-_jYv3K9}OB>5L$G1iwGySw@=+ zj4s+#pxibXoMu3s^MXK`(?&i8{Ntu>ANU`+#{NsmG@>(0;LWZ?tW1=Y+j4rGnIa;u z6>^!VAF(t*mgT?c)~P;ws7*;$En2CmYGt)u+vFCq8hyn`fGtx;we!<8@hZtehPS~@ z9=XZbGwX{5s>#-DH?^E@jFjMbSP(TQTR3&Mpx(ZictuAgo=3acH`8ZhP(_HU0N?8! zVE+xl;bdusQ;cczddva&h>4b16GY@It2JJMK=kQzphFJ+A>DcIpgKw*4zEJk5NG5y z_OQ*4gPPzKhJ0J+RSXT5G&*X%qVEur1lq4}8q%p&>Q#YMYz59Vi?VUCPL)R_tTlss zg!iMpEowy4w%a=>KabCD4N>g+s@zVyPATMa`Ir__TutO#?D|n-5}6XPzHh@cg`O&g z-yx<|&uK9>T6%c`ro|pj79xO8!&4@LDY{JeR*-HX#pA})uIcm_`yiY! z->U?=H!mEqd1f?dIBj<&-lavVa9L=Ku`8#0J^e^mZ+|2e9~xs*R?+QHobJC|g9W zg(LrPb2gk*v8ecZuGXD(dkck5CtKlB)a#F%OfL`a!idi9#Wfv{l6B{49LiEV7Sizn z2S@rj0DXa)4kjVb&xU($C|fjO5@#u&>&1FpySz700} z-v;!}6z#oJo%%AHBgOqnoSOk;v1t~91}Zph*;um9i8tkH-^7PxnU0hF5}SF6&471} zgmJU8rZ%l=w3`zz>cY5k1;0}QHX9k6)AcHV-GB@Ic|;klCzpCNM8s>kC`-J>62=n8 z_yLW+3|>^&X?xM*EauHSQY4{a*5uZ3Jxci0q3Q?oBi7sYm!IFZ-0;tmS&bSiF$R{Q zReci7!z&wMqt0dfj1~H!dZ= zwpqJLx*Ow1kBJ&RInDYEkb>k_p-rD&_KtF1Xq>-5(%1Muj}=n|NHf`m8Pxe?i@LGc4SovYhF#bY7{uLzP6KX-+e?8ri+5>7 z4Tkvw$sOvPZ$^hr=v$d&?eC6cm@>8&^u=^LsFm~z1%o7A}(dkX`D=&4%wdi#|$u7TZTtD;T2ga?^N z;iKB%o;3c-vxLDr6=AnTt~h=RlN?RDM>u(R>B=)Fq2+2af9B*}8r`u^0#FA}U1&hL zbZyu|;ZPULB>W-hpti;E;TWPzvvRnrDX;R@v6xVvhI}I}bB1eHqpM;|(knryhl}-} zObNcB*eCagZ;qItTz2>pH3>nXIo7e(dq9r%7LANT9H|f7dqVr}TcCn^{$%T;4f+H} zBhyoAKm_IZ)Hb=Sn}f2t#I}my7Hns+=lJYKqu{ieVT||ntlSh^=KlMoE2;UET}aDh zwU+~~=RfHD(S6Xd+2i#}XHX(sn0uzZ^v%oYzNagH$@YG!I05QAT2Z3`7xV>0F~_lP z=YZZ2&LM76z*c|Ftw}~OSDF0D?B}KBH*Wtw$%sJzC*`4JpFRiR*0r2C{wk*;tu${^ z^RPIz@|wNQSgFTZ8PGi8Y;ouRhHeoovptaO?)4Q`3wBpV3bQq4;qhNkjTy=7s5H7^vhg#vJn3wCG(+Kldl-FUUOW_w|2c@P8T~YUbWy z)>}q*3T01UKK$X-{!_4n zZYDwciQp5&IC4gUV!Gd$WgG%5vS<#iqs8d*zh(5LNul<8K6Mx`OI{*Lx literal 0 HcmV?d00001 diff --git a/doc/breach-logo-small.gif b/doc/breach-logo-small.gif new file mode 100644 index 0000000000000000000000000000000000000000..d732ac5018a0110c7a1bc11349528f3e1bb966c3 GIT binary patch literal 2389 zcmV-b399x-Nk%w1VPpU#0Qdg@ML|McT3h=4{`dU;_51$D>Gx8+=R7z$h0yK^pxxE) z`E_%1e|&wEl9R^8#i-u%N4VyvrKPT{tSl)i%gV}?*6;+oF*4iR+tSg|>gwuDy5^?c^DVC8a>?wW+wu~m-oCxPP)$x* zR#t4s>uJU6`27CW)z#ke`WU9)U|wG6=;+Su_~hi|go1+I-Q9c4?XTeUGO**y>-cze zcH{K>jEahg(eL2%``PgNZEI_u+VZ;O_O|2o&d$y~wdISknQA*$huh=@S85%O zJw7U};+oj;fPH=pqTVPZC4+&1Nx9}FtKk5h+&DBf{r&y>`}$VAR*S));~Nw{QUem zHaG9@@9p^glaZ0Qw^LA2W@BWBg@)AA(+8m4@A>`N*x0J6sjI1~_4M>? zX=*}0Kr${bV#DcM!048gm4D9d6{X)-zUYtC@RQZ>*w@#jqNCUF`mnFBdUtrh=k|z( zhjVaopq`#PI5+{F+<43EZ^-LTOH6urdC14dt*fla$H;+yfNN-JURzw9o18tG(x>HY3FR$a`;^M%+zbhvwJGA6EH8%D2^_bW3cFOGL_55JM>71IIT31-l z?f4=dAOHXVA^8LW00930EC2ui0Av6p000R80RIUbNU)&6g9sBUT*$DY!-o(fN}Ncs zqC*h*pgarpEENb47DI|W__5?i0R#wKxUlNU5CkW%%#g_i0+k>6R$fYJvgF9021^P6 zu}Z-dDkg%UV1@<)mo!Z*sF_N&s+vJ*xbP@pz(uYiCNlL9HDG{GpcFq6xFl*v5Erq& zq)}nDuHCzJEntC%M&GkB1s3fYigsa1Pog@7GH_x>0=wQKCrD5R%b-Cs1`V^DAajCY z2`og$>rDlhFW^kr_%ZZj;eQ~?+DP%u3tg)!u!#8rAzCvRE)Z0xFy>aLPT4v=qsK*s zieB)nq)L8o+C3=1H$^i*Z%LXNx2;Km;5IY2tpX4#R+AU zw$(R9^w5tCt9;_&YleaF$tt3}(nAWlaFB#8k9ord8u#>bphGBu@q#TXG*JQqDfBbI zCom8OV@M|vAb=2=K!L)02|yFeJwFhj5CJmeB83?0ykOLI~#uF|YYN=raECR*@kY4KPr=W%^ zDq89N)P^d;#Gq;nBD5n%P=BQVs;V&5#B&EpbI7`C48o{l&q0(FL(QuQu|WbHntY%^ z4DGlHLJlL`;2{Y1s4_wviWJjMLG3Iv!31W^W5xk|;84ShYye}%1mc>pOgL|hKuJNf zw6Jct^WUB8%z`w zPr@CXQi}&6Bn&_d1hHXC!g-wHK_dyzL&}Sar#k64S-NgzXW~k&o+$o!H6Y5B<#bl0;%jzBO-_`$2A@J z%YI zjJVkc9a3Ko+XrU&;|!nwc#TcP#T?*|8_KJFK<@(GfsNp@52OeH{){rbLiR-Ak22fH z&HX@egyGK{w>>2%{i&!$SwYHGxR5paurvM#9{Y1Nm*^5Cn3&SbUdM#4Ox3WF%Zi)P>%CpZBBCJc=rlwg5BSn!WF zkij1Z7(o_O$i;%R5D&`OBPWzmkA&IKj0xMu4gTL_(Y2L%;Ez9y zSO^#an+PNf2o4ip?SQcmHdFy&u)~AyXdo?tpm2)|X`v~U2LfLZ@si3k8$nPhHE61> z8&HhiB>VyYfIlFSe4|*%9FVt+7VyChEvRG%#_^vx?2`!|LPQQI_>cQpu3{e$XENuR zum#*;7KexjAdbcav_;b&YshCGfaVXU)y<0m_`@t_ItxV{;y)m;=KR`mgP!^#VdfBJ zANYVcd0-I{zBmOFG$6|sP7R~YgC{}$kg#RYpam_E-`YmtAvREM8QX#l1&$Vua}5L$ z)-wYQ_`p^^n1Tj``$rs@;ExGtfFL#4CjfFF5K3GlVP;^04~RfSf28ASYh(dC|LPA+ zK#v6B@BkgcLD_Kp!Us7(*BkN>fI18W6+j4sDJb9}5+uU|m94A?Ofe3D{Gk;9h=K=a zp#%Ujct9QlIm9jkkqAN*VjhWj2RTgo4@P7G01N0t#We5>07L+Kql&I{r%T=HTKBpU H2?zi?XVITh literal 0 HcmV?d00001 diff --git a/doc/html-multipage/actions.html b/doc/html-multipage/actions.html new file mode 100644 index 0000000..17fcc6a --- /dev/null +++ b/doc/html-multipage/actions.html @@ -0,0 +1,345 @@ +Actions
ModSecurity

Actions

Each action belongs to one of five groups:

Disruptive actions

Cause ModSecurity to do something. In many cases something + means block transaction, but not in all. For example, the allow + action is classified as a disruptive action, but it does the + opposite of blocking. There can only be one disruptive action per + rule (if there are multiple disruptive actions present, or + inherited, only the last one will take effect), or rule chain (in a + chain, a disruptive action can only appear in the first + rule).

Non-disruptive actions

Do something, but that something does not and cannot affect + the rule processing flow. Setting a variable, or changing its value + is an example of a non-disruptive action. Non-disruptive action can + appear in any rule, including each rule belonging to a chain.

Flow actions

These actions affect the rule flow (for example + skip or skipAfter).

Meta-data actions

Meta-data actions are used to provide more information about + rules. Examples include id, + rev, severity and + msg.

Data actions

Not really actions, these are mere containers that hold data + used by other actions. For example, the status + action holds the status that will be used for blocking (if it takes + place).

allow

Description: Stops rule processing on a + successful match and allows the transaction to proceed.

Action Group: Disruptive

Example:

SecRule REMOTE_ADDR "^192\.168\.1\.100$" nolog,phase:1,allow

Prior to ModSecurity 2.5 the allow action would + only affect the current phase. An allow in phase 1 + would skip processing the remaining rules in phase 1 but the rules from + phase 2 would execute. Starting with v2.5.0 allow was + enhanced to allow for fine-grained control of what is done. The + following rules now apply:

  1. If used one its own, like in the example above, + allow will affect the entire transaction, + stopping processing of the current phase but also skipping over all + other phases apart from the logging phase. (The logging phase is + special; it is designed to always execute.)

  2. If used with parameter "phase", allow will + cause the engine to stop processing the current phase. Other phases + will continue as normal.

  3. If used with parameter "request", allow + will cause the engine to stop processing the current phase. The next + phase to be processed will be phase + RESPONSE_HEADERS.

Examples:

# Do not process request but process response.
+SecAction phase:1,allow:request
+
+# Do not process transaction (request and response).
+SecAction phase:1,allow
+

If you want to allow a response through, put a rule in phase + RESPONSE_HEADERS and simply use + allow on its own:

# Allow response through.
+SecAction phase:3,allow

append

Description: Appends text given as parameter + to the end of response body. For this action to work content injection + must be enabled by setting SecContentInjection to + On. Also make sure you check the content type of the + response before you make changes to it (e.g. you don't want to inject + stuff into images).

Action Group: Non-disruptive

Processing Phases: 3 and 4.

Example:

SecRule RESPONSE_CONTENT_TYPE "^text/html" "nolog,pass,append:'<hr>Footer'"

Note

While macro expansion is allowed in the additional content, you + are strongly cautioned against inserting user defined data + fields.

auditlog

Description: Marks the transaction for + logging in the audit log.

Action Group: Non-disruptive

Example:

SecRule REMOTE_ADDR "^192\.168\.1\.100$" auditlog,phase:1,allow

Note

The auditlog action is now explicit if log is already + specified.

block

Description: Performs the default disruptive + action.

Action Group: Disruptive

It is intended to be used by ruleset writers to signify that the + rule was intended to block and leaves the "how" up to the administrator. + This action is currently a placeholder which will just be replaced by + the action from the last SecDefaultAction in the same + context. Using the block action with the + SecRuleUpdateActionById directive allows a rule to be + reverted back to the previous SecDefaultAction + disruptive action.

In future versions of ModSecurity, more control and functionality + will be added to define "how" to block.

Examples:

In the following example, the second rule will "deny" because of + the SecDefaultAction disruptive action. The intent being that the + administrator could easily change this to another disruptive action + without editing the actual rules.

### Administrator defines "how" to block (deny,status:403)...
+SecDefaultAction phase:2,deny,status:403,log,auditlog
+
+### Included from a rulest...
+# Intent is to warn for this User Agent
+SecRule REQUEST_HEADERS:User-Agent "perl" "phase:2,pass,msg:'Perl based user agent identified'"
+# Intent is to block for this User Agent, "how" described in SecDefaultAction
+SecRule REQUEST_HEADERS:User-Agent "nikto" "phase:2,block,msg:'Nikto Scanners Identified'"

In the following example, The rule is reverted back to the + pass action defined in the SecDefaultAction directive + by using the SecRuleUpdateActionById directive in + conjuction with the block action. This allows an + administrator to override an action in a 3rd party rule without + modifying the rule itself.

### Administrator defines "how" to block (deny,status:403)...
+SecDefaultAction phase:2,pass,log,auditlog
+
+### Included from a rulest...
+SecRule REQUEST_HEADERS:User-Agent "nikto" "id:1,phase:2,deny,msg:'Nikto Scanners Identified'"
+
+### Added by the administrator
+SecRuleUpdateActionById 1 "block"

capture

Description: When used together with the + regular expression operator, capture action will create copies of + regular expression captures and place them into the transaction variable + collection. Up to ten captures will be copied on a successful pattern + match, each with a name consisting of a digit from 0 to 9.

Action Group: Non-disruptive

Example:

SecRule REQUEST_BODY "^username=(\w{25,})" phase:2,capture,t:none,chain
+SecRule TX:1 "(?:(?:a(dmin|nonymous)))"

Note

The 0 data captures the entire REGEX match and 1 captures the data + in the first parens, etc...

chain

Description: Chains the rule where the action + is placed with the rule that immediately follows it. The result is + called a rule chain. Chained rules allow for more + complex rule matches where you want to use a number of different + VARIABLES to create a better rule and to help prevent false + positives.

Action Group: Flow

Example:

# Refuse to accept POST requests that do
+# not specify request body length. Do note that
+# this rule should be preceeded by a rule that verifies
+# only valid request methods (e.g. GET, HEAD and POST) are used.
+SecRule REQUEST_METHOD ^POST$ chain,t:none
+SecRule REQUEST_HEADERS:Content-Length ^$ t:none

Note

In programming language concepts, think of chained rules + somewhat similar to AND conditional statements. The actions specified + in the first portion of the chained rule will only be triggered if all + of the variable checks return positive hits. If one aspect of the + chained rule is negative, then the entire rule chain is negative. Also + note that disruptive actions, execution phases, metadata actions (id, + rev, msg), skip and skipAfter actions can only be specified on by the + chain starter rule.

ctl

Description: The ctl action allows + configuration options to be updated for the transaction.

Action Group: Non-disruptive

Example:

# Parse requests with Content-Type "text/xml" as XML 
+SecRule REQUEST_CONTENT_TYPE ^text/xml nolog,pass,ctl:requestBodyProcessor=XML

Note

The following configuration options are supported:

  1. auditEngine

  2. auditLogParts

  3. debugLogLevel

  4. ruleRemoveById (single rule + ID, or a single rule ID range accepted as parameter)

  5. requestBodyAccess

  6. forceRequestBodyVariable

  7. requestBodyLimit

  8. requestBodyProcessor

  9. responseBodyAccess

  10. responseBodyLimit

  11. ruleEngine

With the exception of + requestBodyProcessor and + forceRequestBodyVariable, each configuration option + corresponds to one configuration directive and the usage is + identical.

The requestBodyProcessor option allows you to + configure the request body processor. By default ModSecurity will use + the URLENCODED and MULTIPART processors to process an application/x-www-form-urlencoded and a + multipart/form-data bodies, + respectively. A third processor, XML, is also + supported, but it is never used implicitly. Instead you must tell + ModSecurity to use it by placing a few rules in the REQUEST_HEADERS processing phase. After the + request body was processed as XML you will be able to use the + XML-related features to inspect it.

Request body processors will not interrupt a transaction if an + error occurs during parsing. Instead they will set variables REQBODY_PROCESSOR_ERROR and REQBODY_PROCESSOR_ERROR_MSG. These variables + should be inspected in the REQUEST_BODY phase and an appropriate action + taken.

The forceRequestBodyVariable option allows you + to configure the REQUEST_BODY variable to be set when + there is no request body processor configured. This allows for + inspection of request bodies of unknown types.

deny

Description: Stops rule processing and + intercepts transaction.

Action Group: Disruptive

Example:

SecRule REQUEST_HEADERS:User-Agent "nikto" "log,deny,msg:'Nikto Scanners Identified'"

deprecatevar

Description: Decrement counter based on its + age.

Action Group: Non-Disruptive

Example: The following example will decrement the counter by 60 + every 300 seconds.

SecAction deprecatevar:session.score=60/300

Note

Counter values are always positive, meaning the value will never + go below zero.

drop

Description: Immediately initiate a + "connection close" action to tear down the TCP connection by sending a + FIN packet.

Action Group: Disruptive

Example: The following example initiates an IP collection for + tracking Basic Authentication attempts. If the client goes over the + threshold of more than 25 attempts in 2 minutes, it will DROP subsequent + connections.

SecAction phase:1,initcol:ip=%{REMOTE_ADDR},nolog
+SecRule ARGS:login "!^$" \
+    nolog,phase:1,setvar:ip.auth_attempt=+1,deprecatevar:ip.auth_attempt=20/120
+SecRule IP:AUTH_ATTEMPT "@gt 25" \
+    "log,drop,phase:1,msg:'Possible Brute Force Attack'"

Note

This action is currently not available on Windows based builds. + This action is extremely useful when responding to both Brute Force and + Denial of Service attacks in that, in both cases, you want to minimize + both the network bandwidth and the data returned to the client. This + action causes error message to appear in the log "(9)Bad file + descriptor: core_output_filter: writing data to the network"

exec

Description: Executes an external + script/binary supplied as parameter. As of v2.5.0, if the parameter + supplied to exec is a Lua script (detected by the + .lua extension) the script will be processed + internally. This means you will get direct access + to the internal request context from the script. Please read the + SecRuleScript documentation for more details on how + to write Lua scripts.

Action Group: Non-disruptive

Example:

# The following is going to execute /usr/local/apache/bin/test.sh
+# as a shell script on rule match.
+SecRule REQUEST_URI "^/cgi-bin/script\.pl" \
+    "phase:2,t:none,t:lowercase,t:normalisePath,log,exec:/usr/local/apache/bin/test.sh"
+
+# The following is going to process /usr/local/apache/conf/exec.lua
+# internally as a Lua script on rule match.
+SecRule ARGS:p attack log,exec:/usr/local/apache/conf/exec.lua

Note

The exec action is executed independently from any disruptive + actions. External scripts will always be called with no parameters. + Some transaction information will be placed in environment variables. + All the usual CGI environment variables will be there. You should be + aware that forking a threaded process results in all threads being + replicated in the new process. Forking can therefore incur larger + overhead in multi-threaded operation. The script you execute must + write something (anything) to stdout. If it doesn't ModSecurity will + assume execution didn't work.

expirevar

Description: Configures a collection variable + to expire after the given time in seconds.

Action Group: Non-disruptive

Example:

SecRule REQUEST_COOKIES:JSESSIONID "!^$" nolog,phase:1,pass,chain
+SecAction setsid:%{REQUEST_COOKIES:JSESSIONID}
+SecRule REQUEST_URI "^/cgi-bin/script\.pl" \
+    "phase:2,t:none,t:lowercase,t:normalisePath,log,allow,\
+setvar:session.suspicious=1,expirevar:session.suspicious=3600,phase:1"

Note

You should use expirevar actions at the same time that you use + setvar actions in order to keep the indented expiration time. If they + are used on their own (perhaps in a SecAction directive) the expire time + could get re-set. When variables are removed from collections, and there + are no other changes, collections are not written to disk at the end of + request. This is because the variables can always be expired again when + the collection is read again on a subsequent request.

id

Description: Assigns a unique ID to the rule + or chain.

Action Group: Meta-data

Example:

SecRule &REQUEST_HEADERS:Host "@eq 0" \
+    "log,id:60008,severity:2,msg:'Request Missing a Host Header'"

Note

These are the reserved ranges:

  • 1-99,999; reserved for local (internal) use. Use as you see + fit but do not use this range for rules that are distributed to + others.

  • 100,000-199,999; reserved for internal use of the engine, to + assign to rules that do not have explicit IDs.

  • 200,000-299,999; reserved for rules published at + modsecurity.org.

  • 300,000-399,999; reserved for rules published at + gotroot.com.

  • 400,000-419,999; unused (available for reservation).

  • 420,000-429,999; reserved for ScallyWhack.

  • 430,000-899,999; unused (available for reservation).

  • 900,000-999,999; reserved for the Core Rules + project.

  • 1,000,000 and above; unused (available for + reservation).

initcol

Description: Initialises a named persistent + collection, either by loading data from storage or by creating a new + collection in memory.

Action Group: Non-disruptive

Example: The following example initiates IP address + tracking.

SecAction phase:1,initcol:ip=%{REMOTE_ADDR},nolog

Note

Normally you will want to use phase:1 along + with initcol so that the collection is available in + all phases.

Collections are loaded into memory when the initcol action is + encountered. The collection in storage will be persisted (and the + appropriate counters increased) only if it was + changed during transaction processing.

See the "Persistant Storage" section for further details.

log

Description: Indicates that a successful + match of the rule needs to be logged.

Action Group: Non-disruptive

Example:

SecAction phase:1,initcol:ip=%{REMOTE_ADDR},log

Note

This action will log matches to the Apache error log file and the + ModSecurity audit log.

logdata

Description: Allows a data fragment to be + logged as part of the alert message.

Action Group: Non-disruptive

Example:

SecRule &ARGS:p "@eq 0" "log,logdata:'%{TX.0}'"

Note

The logdata information appears in the error and/or audit log + files and is not sent back to the client in response headers. Macro + expansion is preformed so you may use variable names such as %{TX.0}, + etc. The information is properly escaped for use with logging binary + data.

msg

Description: Assigns a custom message to the + rule or chain.

Action Group: Meta-data

Example:

SecRule &REQUEST_HEADERS:Host "@eq 0" \
+    "log,id:60008,severity:2,msg:'Request Missing a Host Header'"

Note

The msg information appears in the error and/or audit log files + and is not sent back to the client in response headers.

multiMatch

Description: If enabled ModSecurity will + perform multiple operator invocations for every target, before and after + every anti-evasion transformation is performed.

Action Group: Non-disruptive

Example:

SecDefaultAction log,deny,phase:1,t:removeNulls,t:lowercase
+SecRule ARGS "attack" multiMatch

Note

Normally, variables are evaluated once, only after all + transformation functions have completed. With multiMatch, variables are + checked against the operator before and after every transformation + function that changes the input.

noauditlog

Description: Indicates that a successful + match of the rule should not be used as criteria whether the transaction + should be logged to the audit log.

Action Group: Non-disruptive

Example:

SecRule REQUEST_HEADERS:User-Agent "Test" allow,noauditlog

Note

If the SecAuditEngine is set to On, all of the transactions will + be logged. If it is set to RelevantOnly, then you can control it with + the noauditlog action. Even if the noauditlog action is applied to a + specific rule and a rule either before or after triggered an audit + event, then the transaction will be logged to the audit log. The correct + way to disable audit logging for the entire transaction is to use + "ctl:auditEngine=Off"

nolog

Description: Prevents rule matches from + appearing in both the error and audit logs.

Action Group: Non-disruptive

Example:

SecRule REQUEST_HEADERS:User-Agent "Test" allow,nolog

Note

The nolog action also implies noauditlog.

pass

Description: Continues processing with the + next rule in spite of a successful match.

Action Group: Disruptive

Example1:

SecRule REQUEST_HEADERS:User-Agent "Test" log,pass

When using pass with SecRule with multiple + targets, all targets will be processed and + all non-disruptive actions will trigger for + every match found. In the second example the + TX:test target would be incremented by 1 for each matching + argument.

Example2:

SecRule ARGS "test" log,pass,setvar:TX.test=+1

Note

The transaction will not be interrupted but a log will be + generated for each matching target (unless logging has been + suppressed).

pause

Description: Pauses transaction processing + for the specified number of milliseconds.

Action Group: Non-disruptive

Example:

SecRule REQUEST_HEADERS:User-Agent "Test" log,deny,status:403,pause:5000

Note

This feature can be of limited benefit for slowing down Brute + Force Scanners, however use with care. If you are under a Denial of + Service type of attack, the pause feature may make matters worse as this + feature will cause child processes to sit idle until the pause is + completed.

phase

Description: Places the rule (or the rule + chain) into one of five available processing phases.

Action Group: Meta-data

Example:

SecDefaultAction log,deny,phase:1,t:removeNulls,t:lowercase
+SecRule REQUEST_HEADERS:User-Agent "Test" log,deny,status:403

Note

Keep in mind that is you specify the incorrect phase, the target + variable that you specify may be empty. This could lead to a false + negative situation where your variable and operator (RegEx) may be + correct, but it misses malicious data because you specified the wrong + phase.

prepend

Description: Prepends text given as parameter + to the response body. For this action to work content injection must be + enabled by setting SecContentInjection to + On. Also make sure you check the content type of the + response before you make changes to it (e.g. you don't want to inject + stuff into images).

Action Group: Non-disruptive

Processing Phases: 3 and 4.

Example:

SecRule RESPONSE_CONTENT_TYPE ^text/html "phase:3,nolog,pass,prepend:'Header<br>'"

Note

While macro expansion is allowed in the additional content, you + are strongly cautioned against inserting user defined data + fields.

proxy

Description: Intercepts transaction by + forwarding request to another web server using the proxy backend.

Action Group: Disruptive

Example:

SecRule REQUEST_HEADERS:User-Agent "Test" log,proxy:http://www.honeypothost.com/

Note

For this action to work, mod_proxy must also be installed. This + action is useful if you would like to proxy matching requests onto a + honeypot webserver.

redirect

Description: Intercepts transaction by + issuing a redirect to the given location.

Action Group: Disruptive

Example:

SecRule REQUEST_HEADERS:User-Agent "Test" \
+    log,redirect:http://www.hostname.com/failed.html

Note

If the status action is present + and its value is acceptable (301, 302, 303, or 307) it will be used for + the redirection. Otherwise status code 302 will be used.

rev

Description: Specifies rule revision.

Action Group: Meta-data

Example:

SecRule REQUEST_METHOD "^PUT$" "id:340002,rev:1,severity:2,msg:'Restricted HTTP function'"

Note

This action is used in combination with the id action to allow the same rule ID to be used + after changes take place but to still provide some indication the rule + changed.

sanitiseArg

Description: Sanitises (replaces each byte + with an asterisk) a named request argument prior to audit + logging.

Action Group: Non-disruptive

Example:

SecAction nolog,phase:2,sanitiseArg:password

Note

The sanitize actions do not sanitize any data within the actual + raw requests but only on the copy of data within memory that is set to + log to the audit log. It will not sanitize the data in the + modsec_debug.log file (if the log level is set high enough to capture + this data).

sanitiseMatched

Description: Sanitises the variable (request + argument, request header, or response header) that caused a rule + match.

Action Group: Non-disruptive

Example: This action can be used to sanitise arbitrary transaction + elements when they match a condition. For example, the example below + will sanitise any argument that contains the word + password in the name.

SecRule ARGS_NAMES password nolog,pass,sanitiseMatched

Note

Same note as sanitiseArg.

sanitiseRequestHeader

Description: Sanitises a named request + header.

Action Group: Non-disruptive

Example: This will sanitise the data in the Authorization + header.

SecAction log,phase:1,sanitiseRequestHeader:Authorization

Note

Same note as sanitiseArg.

sanitiseResponseHeader

Description: Sanitises a named response + header.

Action Group: Non-disruptive

Example: This will sanitise the Set-Cookie data sent to the + client.

SecAction log,phase:3,sanitiseResponseHeader:Set-Cookie

Note

Same note as sanitiseArg.

severity

Description: Assigns severity to the rule it + is placed with.

Action Group: Meta-data

Example:

SecRule REQUEST_METHOD "^PUT$" "id:340002,rev:1,severity:CRITICAL,msg:'Restricted HTTP function'"

Note

Severity values in ModSecurity follow those of syslog, as + below:

  • 0 - EMERGENCY

  • 1 - ALERT

  • 2 - CRITICAL

  • 3 - ERROR

  • 4 - WARNING

  • 5 - NOTICE

  • 6 - INFO

  • 7 - DEBUG

It is possible to specify severity levels using either the + numerical values or the text values. You should always specify severity + levels using the text values. The use of the numerical values is + deprecated (as of v2.5.0) and may be removed in one of the susequent + major updates.

setuid

Description: Special-purpose action that + initialises the USER + collection.

Action Group: Non-disruptive

Example:

SecAction setuid:%{REMOTE_USER},nolog

Note

After initialisation takes place the variable USERID will be available for use in the + subsequent rules.

setsid

Description: Special-purpose action that + initialises the SESSION + collection.

Action Group: Non-disruptive

Example:

# Initialise session variables using the session cookie value 
+SecRule REQUEST_COOKIES:PHPSESSID !^$ chain,nolog,pass
+SecAction setsid:%{REQUEST_COOKIES.PHPSESSID}

Note

On first invocation of this action the collection will be empty + (not taking the predefined variables into account - see initcol for more information). On subsequent + invocations the contents of the collection (session, in this case) will + be retrieved from storage. After initialisation takes place the + variable SESSIONID will be available + for use in the subsequent rules.This action understands each application + maintains its own set of sessions. It will utilise the current web + application ID to create a session namespace.

setenv

Description: Creates, removes, or updates an + environment variable.

Action Group: Non-disruptive

Examples:

To create a new variable (if you omit the value 1 will be used):

setenv:name=value

To remove a variable:

setenv:!name

Note

This action can be used to establish communication with other + Apache modules.

setvar

Description: Creates, removes, or updates a + variable in the specified collection.

Action Group: Non-disruptive

Examples:

To create a new variable:

setvar:tx.score=10

To remove a variable prefix the name with exclamation mark:

setvar:!tx.score

To increase or decrease variable value use + and - + characters in front of a numerical value:

setvar:tx.score=+5

skip

Description: Skips one or more rules (or + chains) on successful match.

Action Group: Flow

Example:

SecRule REQUEST_URI "^/$" \
+"phase:2,chain,t:none,skip:2"
+SecRule REMOTE_ADDR "^127\.0\.0\.1$" "chain"
+SecRule REQUEST_HEADERS:User-Agent "^Apache \(internal dummy connection\)$" "t:none"  
+SecRule &REQUEST_HEADERS:Host "@eq 0" \
+    "deny,log,status:400,id:960008,severity:4,msg:'Request Missing a Host Header'"
+SecRule &REQUEST_HEADERS:Accept "@eq 0" \
+    "log,deny,log,status:400,id:960015,msg:'Request Missing an Accept Header'"

Note

Skip only applies to the current processing phase and not + necessarily the order in which the rules appear in the configuration + file. If you group rules by processing phases, then skip should work as + expected. This action can not be used to skip rules within one chain. + Accepts a single parameter denoting the number of rules (or chains) to + skip.

skipAfter

Description: Skips rules (or chains) on + successful match resuming rule execution after the specified rule ID or + marker (see SecMarker) is found.

Action Group: Flow

Example:

SecRule REQUEST_URI "^/$" "chain,t:none,skipAfter:960015"
+SecRule REMOTE_ADDR "^127\.0\.0\.1$" "chain"
+SecRule REQUEST_HEADERS:User-Agent "^Apache \(internal dummy connection\)$" "t:none"  
+SecRule &REQUEST_HEADERS:Host "@eq 0" \
+    "deny,log,status:400,id:960008,severity:4,msg:'Request Missing a Host Header'"
+SecRule &REQUEST_HEADERS:Accept "@eq 0" \
+    "log,deny,log,status:400,id:960015,msg:'Request Missing an Accept Header'"

Note

SkipAfter only applies to the current + processing phase and not necessarily the order in which the rules appear + in the configuration file. If you group rules by processing phases, then + skip should work as expected. This action can not be used to skip rules + within one chain. Accepts a single parameter denoting the last rule ID + to skip.

status

Description: Specifies the response status + code to use with actions deny + and redirect.

Action Group: Data

Example:

SecDefaultAction log,deny,status:403,phase:1

Note

Status actions defined in Apache scope locations (such as + Directory, Location, etc...) may be superseded by phase:1 action + settings. The Apache ErrorDocument directive will be triggered if + present in the configuration. Therefore if you have previously defined a + custom error page for a given status then it will be executed and its + output presented to the user.

t

Description: This action can be used which + transformation function should be used against the specified variables + before they (or the results, rather) are run against the operator + specified in the rule.

Action Group: Non-disruptive

Example:

SecDefaultAction log,deny,phase:1,t:removeNulls,t:lowercase 
+SecRule REQUEST_COOKIES:SESSIONID "47414e81cbbef3cf8366e84eeacba091" \
+    log,deny,status:403,t:md5,t:hexEncode

Note

Any transformation functions that you specify in a SecRule will be + in addition to previous ones specified in SecDefaultAction. Use of + "t:none" will remove all transformation functions for the specified + rule.

tag

Description: Assigns custom text to a rule or + chain.

Action Group: Meta-data

Example:

SecRule REQUEST_FILENAME "\b(?:n(?:map|et|c)|w(?:guest|sh)|cmd(?:32)?|telnet|rcmd|ftp)\.exe\b" \
+    "t:none,t:lowercase,deny,msg:'System Command Access',id:'950002',\
+tag:'WEB_ATTACK/FILE_INJECTION',tag:'OWASP/A2',severity:'2'"

Note

The tag information appears in the error and/or audit log files. + Its intent is to be used to automate classification of rules and the + alerts generated by rules. Multiple tags can be used per + rule/chain.

xmlns

Description: This action should be used + together with an XPath expression to register a namespace.

Action Group: Data

Example:

SecRule REQUEST_HEADERS:Content-Type "text/xml" \
+    "phase:1,pass,ctl:requestBodyProcessor=XML,ctl:requestBodyAccess=On, \
+    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+SecRule XML:/soap:Envelope/soap:Body/q1:getInput/id() "123" phase:2,deny
\ No newline at end of file diff --git a/doc/html-multipage/apache_request_cycle-modsecurity.jpg b/doc/html-multipage/apache_request_cycle-modsecurity.jpg new file mode 100644 index 0000000000000000000000000000000000000000..390c649350e15d4a359ca2be8ca15b4a963cc96b GIT binary patch literal 92271 zcmeFZ2UrwK);Hcb1j&NrG$0@-Ac7#70TED90ZEdxBmqg183X~zf&z*HgOU^h$r&Vr zh~yjxkQ`=+0}M0&_TIhsdiTHK?tc63x8M6LJpFX{bamCK>Z()c{LZfmKZ2hDPTf$s zt^yDc5CC4_KY$+xlz@}O#3aN-CrL<1NJ&qUQP5FRkdsp|)1IcLV`qVKu(PnSaq?W? z<2)nC&Bn$raZd1}h?tldlut@dQdIWBB{9+OnGleYl2VXUFi}!6iE^=ViT=ZX_)h@M zNeGJQEQH_;aDs*aLPLOW2A}{yKmnd|K0-^`Yu9gRY3u0f-PJd+w6eZuV{2#c=I-&()63f@_;E;R*pu*x z_-D@(5|duMOn&n=BQq;I=iU3F;*!#`@`}o;#-`?$*0%PJ&wc#^gG0k3qhrX~x%qDk zi%ZKZ=&kLY-MxLx!QuCM5de^%tMzNm{;Xa!V7*Qd5<&<`zSoQ3geQ1FXb6e8M2Kk> zHA&1}PM;Bdbdv5$TzX*xDfgv2D0&OmUNQzAF(fbgd)0ob*&nM|&_7kPUn}-oy~Y3v z2m$!ho6hE2hW&3Tz~enCKGegz_}O zPPR4rOxHH%{Woc->0_q?JYY(RT|$um&afP&LDl1wE8(lv@Jq(E0G+1te~+zs+(91-Hjin- z!AoFR$SXV$)BC%-VMXQtX7GQZ4F;w-20X||#T|^*)>`M(YZ#8!;}Y1IES|H8@Ia^L z3hc-7;Z4(9Y-pR~5KBDJCtv_9{n9Vb#p8i@@cmozFNF`2@PK;{3CRyb@GY|baMBc4 z$9mAKz#z|v2inVpk3F3i9Ln>#k#KCJD;^krh`U$q^Kb3rzsUaQ=kw81nKnSYloJgT zq(L%wa3+nzz3WPI)BDkhFYma`2Ppwvl+JnyoUv5O#F{4lK{MLqz}er?{aTRK)0pbp z4#<<6`E#$k*qb8-Jj}escc~lX81{yn@W7a7lIV?L?!d)Nz^9Z>Q-SE;c(CDtsQP&l zM?7F|EP)5q%=3dP@xYJ6_70}LS*bCAzJ8cxWFk^o_hQ&+wIE|YmGq$o@g#ktm*K2+ z!4oWfu2+N_agnsm%SA)k@mD7wwMjC4b?GmKQr7VlG>Z+qbWiMWiF;z6y)Cgx0k0C- zhZ_JJOIhLEqD)Qi9*FA6#x{nQO?BM}|Aq zbWK^TQ#`1c0}fLYI)z)hPj$VK2p7VVy6}Z5u^F)r(mp3)Epz-TD%V!;1MI#(9~%2% zbTyebzu?~DTDb_RcEy;sC*_i2JM2bPOcB48*=L_quKWZ8TCyX}K`;@&Cal!rR_6BU zFI)ThSQ{trw!T1i<%_qNr^8RrA5C982&hZY(jMUGyir|M5@<4^1i8gtbd9d_(I=8J zpL>DAnnodQv3VuqFlxBN-7cFP2R9y(F=y)e_)oO!pFWYuOg$NW-fpy+spntRpAG`hyu4SCB(weLd--=Nd3`o*i^u3Vh?lJhiQ{Z(%O>p2Bd zeF5i;uFoEsQh7x-?kCd^&cN<@-=ocly40$`@uIz3a<|J7W7*n^iM)&ENZqsOu`N%t z7Ad?4?^@Wh{5+*faJR>LV8H*oY3Pwb~TB z0FyTrv0?QzTxjfAr=dQpuOV|BS6rIV`LZ<;rh|aZo2jMaJp@L0Agq2~YPS1`tPKxj z=$7{A!H}B=R9?ln#zH)>OrHn1|7rpKFPO=7d^^V-PEzdO`Jfr|VNxK~`N`C270y-N zQH~vgfnK8mtY9oDyvJ#J`z?+^^>O`@g!4fUiH^~9jM%l^Zt^LGcIIZQELESdU!V3# zG&`S^PH?mz32tCUP(Q=MkmHfv%ng~cRtc|YDIRwDr)1a_+DRKRXi)Ij6AN_g*!fXs zdCeXf<3`KRN$`gu#3wlamjZ7c-U`-pFFq?MN%F8CoH zNP(h?WO?y`Vm170p!ClL#eFYm{C`V9iBOsvo;HX<8Fm#>SYJAjmpI#Joyf4%+0#Rm z%>O2k?C%^>zgOvZ@cJUW=bfW6FwjqhmYvp0;lg02UWw~4}MB-C+rNK zs~E}zGF+w7etMESu6>>iILN-6ysDtqO=)oDA*T3tKTmm^4VO~fE?3x`;n>Z66S`iU zU<&h?)CZeTCiZ|Wew$lOJs}<4_w|a5yiPZj8^lDz#Y0z9IK*N)u*0nM@=LPVkyh_6 z{r(!hw|1UBEnTIE=@0TpNNz@b^)9T?Q<5(e?hApk>c*(-Ff0rOzlDxT@)hLZ8g+h< z95hiZ+gHijpD)?@5J%-Zls8y`9&VMBxQ;fuaNnYrc17UyIc@Kk+LfO;7kR@9+GWVr z*XpRf&NpcrE|p|ivL3`W2yURcZKO`#hRH?@qSXVja&wI3NqWWiD#~ZiA)mH!nr>{c zs}?Rli@FymTi!@xdq~|3ebUp;Th+UMzwt(}`-d|SiWJu?Q3WQE8eI+}qlrnm=oc zcIDa#|E)!Y>}z=GPM$Nxr~?NbnmU5@cE4HQhoo!1kNZ@zl5WvA@}EB<5QO;491HY& z#1eV=8uhI2I80vVw!Tj?+9#VH27#Ef#hgoJMyZ4#&sIEBD|2ykiU|`;dTQ043=W9 zOA)*t$htoNT_6QAi- z^=!~@uy>lDL@LMvCvxVdhic{9ko%z}L9&ei&-)_$qaBNH5c99s#m86DsQkopy`0(5+j>O(oiO7qP+H_7WqyF3pU0>y9? zBe!uJ1G4HqCu`6|Yf1M-qEwhdm<|(RR|FVm`|R&vuc6M^omQkmn79xok=+pRd;O6; zcW6xz(eJ+Mz-lc(RH8;__WJ4ji!eoPabb#OgR;^r`~9+Y-i;SuhVpr=PZ~0}laL@* z71-p{Q2Wh?Y0>V}G+y1t#WlFjP6I>zMja)N`KKaZsa+pPuXJgb<`WA=ImX=xjTPX1^ixzG(ZG06CFs<>i2$a=R z8`?Q42&@tct?-a}>yjg$!7$|ZWNbc+S93Cqv>h6RW5jZqO>tm`DUTLi46#jNx6QL#L{d4=`lH)@iYld`pEG)KtX`H^2G>g+ zSfxVWo+yfZd4b3C*#pj`j)NHLfRr3a<6@6>uh`L~nm%fWgR>tu&{zJXBt`F%@E0mq z(%sgR>^?i<{g|>9b$UM~)YlhPj;*B`@=@ha?Y1Y6Uw{3=y7-WfC=kGrOjR#~dPCHq zr1V4$mSA^_SvB?&fh1ysdQLTmT+#oFt4otvF$GOTnkwq{BgB%Yk4l>Lw{a5z@d(MNqzMr zY9ZP=V>yoL!+HZvx@)s_B!@a*ye;I5JXww@t)GGpz(4o^Sl{k6slQtV4H1J=8L#L` z8y72G$dpKPy%{w=%`?_zXS$)t&04I)}h@n8~U+0^jF)#Hj zHC!ehm=q&uz=BSMVJ_&mHNmC%e?VR|h+;$Vz?M)a9xxt1NM2ukf-%JdXC~@*C+lD4 zPyO8)?AH?i&P?~uq?0U&Fx}!cPE&?`t|>smnR`{@%0tINzFeAIwhhj0BscbvP4*hpS?z9C;oh|$ztCMB#Q&VM}n^+OK z>7zjcI<{n&no`s9ps2U9Qp<f@nTSzl6QW%#b|4EDly zR1e8(&{B&+EoQH(V)?tNd;&_BJ4-*E{}kL4(d^8yd_9*^Xqu5{1~L^W+5IOWzT(be z<@##QxmfZhDn4XhoT_`)O6fJ+X1bf~dDH~jmN{NZIOSV1xJt6|59%l3?eDVT!(4{$ zfTl9tPlw)DQwI0;Qh229PG50W>2{?e;6&N)L$^^`}iLxtjZm9UAIl zn|~^{4>Tp`K2z@#$p^}|;pl9_7hY|8BwUH-F)`w<|6R93WWmXYJz8kDwO$ z|21sRAN>)5wu#nilAcP-PUxtXq#wG9vpUDO9}12GJn*wLZ~r9R&I&)|3;bXB+lI_* zO$8_ndjn(m*2}GF)!X*uvxm~dSy*0HKXQ8#OMN&CNG8xw-_O-UN?@N1O@r>Q?Oz1% z-Wjd37^emdzSD1rsk^^Yf$ai}-+W|k#WCpe*Kze*yEI&L(p4epC%fLohdt{f1AoU7 z-IhJNQ~gpAt1AlQcuvrx3A$NWUP17)Z6c3dosT?d;7hFruyXNA*r3;q1K8@q#wdJ; zlmi^d0%=D!kyb~^XX8%pCTTxSJNjnUwyK&mM+*P8s#FHjAndZ+a93~k5d6+Wv^QnM zJn>R*EI*txWR0_Z-+Jmu!a8WTq0RJ0Bbqm+mLttZ2v_PTEAW1KJUyuGGv%vx-z1BR z58zZge&%=}ULAzOhxtKeVxd7SR!`@rP8?D7rJl+eR&2lpOXEPq9u-MAjWJ5LiBH?I z>?S?I%Gu@VUm{m~fo<6)CYyPxcz8+`X+k}FX)cc%ITbFx`6LxiZZf7w*&n9Xm+~??~K=FW3_|euV?h zQS=g9i*i~sn^#y-Ynccmec3G=>$uTU{Usw}uV^xAmNPG8BstPI=KN$++4R@&Wb?45-S7(flaH|o^ycJ$>TYn3~2RzA8>PzRT0?bPuJ;DUI6Rf7* z53ot9_1qm#g`d~wiQ%2(eorwc=wd2t$0EK_KO=>`Ql$XCnE2Ey!rz+fV#fl-g(36U z+wj^Q`XNl`)gh1WQ?|*$hRgD2ljY99N|p-za?tJCmp(^)5T#N%+1<}1MzB^jRBDY_ zN;0Tjjk9xRj*Fmdjy0c1z6H?_Zf2oO%yY^-QypThZ9&d&{+i8mp+;H+u>vQlG0keq zw7)FDBHQX&SX&`VZWp64;x%I)dUAg;&&RVdn)P;H0Q)lSh~bmuy)l7TK};!I&w+Bj zm=q$wFtXKwulZdK`yMTejBuHMZr4oIqjD$EAdANXtwC+GDoIG{kBky~d2V|JGOU-w zB}dECDu=lX%H=%^>{t@Zj}#}zmVM^O#6R`XcYP5dCDqUq2vRkQ{rtAL*W(uTUJz=s zEU%zD@8+RjpWyaYZvJX()(50>oN29rat)c$M%>b2P7&&7Uw_TXObNXK!?gt&x>^Nx*x>w$a>`V zqRwh?Oy%-ejZIULy*%T9JomU=S)|!sm07X?t3$E0q5M>OeGMYsAM@c@y)gh9wg-=G z?%;|1FmYZi31;hRV|jt)GIIk{$8zgL4@ob}y^Q40aO-zPPZ(CFr1pw!?(LE=&&j#y z?q?^}yRNl*+C=#bcUSdP4Po_XYKi^N?fT2ZsFfZh+f^Tl-r~AK&LH=I&Sib~-OR@U z_cRd95j(I59lv>%+QA|@$XGm`XCrEzr$BL-UA}~1Qw@Z&bOvK2%-GPYS8lOYZq2K< z8GoP>XfCNgF`|gFIl4Wr5z%BYC{{7&a8zB);%E`Y-65%2dIha7&r%-Tn0gU4>kx42 zl}cr*a_G2b-{yXk`&~e`rGr9hkpvUV&JS6#|8cTk#LD3Tu5JeSh%W5-OzBTJB{jU= zttD-bJ{AvL%d>?b-bC;N-;ZDHk;7kNa?mFDZdLuUpTzc?*ibyM>H$B*I4>##cYkMv zRQ%pXS^6ojU-JC-obBRNeE<)7##gB?u(veohVGYaCU1SS)ZA2H5fZZ>*B_8b7n}7j zHih}=qcc_oJ$;A~H_fnLN?VrTG+5tv#+julUy=kLTz=FS2sYR3tGNbGg_soNRpWPJfA2g53MXPX!03Ug4^efsGnPS3#^4T*@)i+=3cuqK|s< zBu^N7-900Jq0?6nf!UKtYN!fSxK6`1TLI3}PxJO0Usa0)Z5UrW>>;sF73s6?XVlP7 z`uuQAYEyYQN~}}-QRV{%%Rslj8i?L@p8NEgfJG+{Eu)it*M}qyPSoU@(-*6v*a!D_ zS^(es^{3pKoH<4}H10DCr3whNLPuCO_jJ0x^`GoqV2J)mS|HdjMlP@!Ql6aIeyYM^cro)5shjF*Fxt{CAVm5YsvnAc_alAA|aRVrA^T z9gFYO&Bt#%PE@Y5&YFgmhVftMVIL~JIZm^8C{xC-Vmb%TLYJP@k}-&gi3h!x}- zsN**8!&f)C2=(RV0aDx@fT@Mlj_kGkkU! zdyamx;Y;(DgR{=inwYX`eF~SJBvG{YVwiYtJ-MG;(W{$%X&Tp%4RT6rj`%`gJqea-m0*UaQ zN7-_i>S%=G>)@dpL&aXfU0-1ulc~`72icUVp_S7qV&k{ucwC&h%|m^*71&jqg-_k} z3Tv(7h;M0n|FHw>FzHBgNMX7Wfr2sEGO%1IM_O9FV%|%X`s&a#-6lPl^_Kmy30v}A z0MgCe0=WBxMY{W6P(Q!2BKAyjOkJGg-5fi&YH6r%`0#!cf8~6{mekIwqwnl}@*M6p z%Zj$tPy|}(9VU!2z0kLvla>21XhN?0n1;L8nlx+*ZD@UtvOZYWe~P`@!~1ehfH3O8tA~J)VH1vJAm6+^{_B*tcT{R%A11PC%nwRca(r9d+(RJu67gym;G5YUQ8I3< zLeA*2@U{9`>YEhDS%3LWEona|S!726`=IO8Wz^TZi))e7V~Jy)CFqv5C(RPiCy#R= z1I{?kC4+zrL8}TC|8X_QCvo^4v~EJ?7;kgZ$%fV|!Cjzdf;`e2+?mv1KciNO>$x$p zxUp>*kI}kY-fua$fr$ThW|i1S2=IW?$aB@!hYA&lx$2B*Fs0qtsNs5lxfogP&~~&I z>^W2u)|TWW{|>d#>MsxFecWIIQ!=TXso*Y0WhS>)5c8f5lroKmZ}IaT4ZcIAC&-dI zeQnToy)Jp82qzAPEfHy(nyCIJ1BPs*fMKnYO8>@&3XnKE%3~gT<EeKqZn_)xxg_Q1z3nYUuiP$N+b^N0+mkNs2HVoaS$Rcg4COi2H?=QzSI^{Fs2 zSRq!C?{Jf@J#Ba0k`}(?yZUp!7!@Z|oV=`hJ~)Xuaz)|+<>nH2BReSAYKjHiPTUt1 zERGYJ`BM-d9I~)b*5ilaHZCCL<=mnT?x@SS47Ctu6I--2=FYVI&EU=47JardaOVA+ z5M?ri8E}zEh)#n*`R9WK_B(ImZvfI?(Mj0A_4+k|EHHReN4Ig9gFo`PaVau@t1~NjrJU{>;KY?w4GN>f$w{YOiOgj){Rh&?n}Sy_Crp zk=C5+)THAJFBY4!G;4e6QZBhB)xz5rDwbP7H|7;@%Ur5wllMu*@H03ace z3p47q{EjpGc!qAev-(n&>5U%gT3hlo@7sLc9IEo+hwxw=t~pa=hw&8ayJtRfY^izt zairqYSGTxF;BnVLxN(|n$snaJ-PumIe+&<_m5=3f=#=9Dm%B6Yn|e0CCvDMpV|;N+ zsh|h`@dNx&*}<5|4ab28o-Rhh)&!uqID;M%#Xt3Rf~?+*cLqwrelSp>lz3oh z1&q_6roTo2g+DUITz-lBu{Li1cI6cHqtG!-lMvz{I9d}oJ`md z`I6yg>`zC~>~}{U^CmxhEwoUc2;Tm9dUs%GvqkuT)(J!~VV^(N5kWxxb^1HT$MGn4 z+`m|Ebe%yRJ>WWA{A7WDpi25ADpHSg~`#y;;BU$mHerTrHuHQ|HfPDXJYUuBO&xf#AQlglkY7CwhqLt%qMJFx&zM921#FmAT=8u@;02f7 zbIeN(t+AQQk-zsEJ_h|7C@0f+5{5k8-wONoG_OF&UjW(&-8yeKz1yxk30&$ly&+q= zlijOu%1FP#gEYdcsnzFQ&RR*eklc+iL)BAq4y1!T4E?_dL#Zy zOD#cxqmDUC7WHS5+Xv{WKv_JX(OViz?WN=1MJ6oUUg5HwS{jr_?E%H8+`ZT`UsL3x zmmfWc5c50e79;5P;#Nz$iW<=M_8)&+0SikRbQ=ge{spRyy4-1~ehW z2%0hV4Pngz&=QStXTctCxaM7XHq>T>b3S*Z;qw*;Mpk%@z~IHvuT-`&-9|km;r1p( z=(B0>R_ro@hCFNh&$nbZ3CtmFLd_%R7cOm@e36JXP*0NrqfeY(j4eK)c^REKT()cN z^TSn!3o=$JE4dNRgg0-EO@#)^_IN32f^OI2NOhn@#VY+C$LsdM5x!(VP+ z6YuisZ`8yz-BOd9Owb8-QD8e;J~OGL(_bP7zkaY`QKoSkm77YA62jD_-5F-Q-%&<>*a%YGu00mi?r|*RtNNxa4WP*`=Y=~zhyksVGveh#finL@G~AfT z98)#5uy{q&&XM;^p{f3aw@6%NqRfko`%auT_Nlv2EYGm%j=*Z#elryN@F&m|EI4@; z7vk@R!vudPD&hfB@!?~#!^LAX2_9faPz6OSg0|_|D$utxHNpdRoFG6B8cer9$MQ;D zB_8lo1P8%)!~(p=T+gpx(i?_tK7nD@LCek<-cyhdpFRagkAY0Od^nEQq2Q2yxBF<8 z8YiRrUt#{0Edw_H??I$L|FX!(RSqdWdkd|z9nKy^$xQi|H~EDSu{;8& z)?nk?y(`}0pF3tLEln#fE)A{Uk8F|+4$Wn84yM?O%yYU|_3C}p@z|PKX$(^W4ZV(! z8K|}`QMjh{D|-j?$!o7a@(Cob=B**h6h1b_JvwfPD59f!UIIK)$owG)GB3|F*6ocX zf8jW5XJyTKez$-Y6W>Nie)|3=Ka9 zF4S)Zt73%;z+hX?iB%j%d{bTL`7?|J1^o|BKRR&n`x)8WYdMKi$$(kFLT#J0Q*c(hq+iEWWv= z$V_soH2@@<4c2fu%SL--Wjq|N^;`#Ix;C@ZkA`_S4S84i?h(+u!~h5--3Ry}DZh1p0Hn`p0Ya~PNlHTA?I1{GtG(Egn}%hT zY~EaDSy1Sgm{6V{x?Mfn?DUPtY-OM8TRpIOOQRVsO66uplxI(i>sv85hHl^#w)b@Zm>s9;Ej5J)*wp9+|a{e z(gLsBce8PWJtHmNQ2A@fyE@apt%zt@sZqW(FMk8j>yztn)Gy#8;c(Em!; z7d71##w};}^WuR!cwi$Ln8C4vr0+p6-h`}Aq4WEZ8grtp5f2)5V`yUl*W zpjqo=dblzDW!U+DPJY6fd%>UHmot*m2@A&1(lOtY3jqZ8$>K_48n`tREypT^ESo)( zzxDKs(aUQ}#=G$Tl~pMx8yd8ph{@PJ8+Z-_ zZ(gYV9(2IgxK1a8$ZozuTGiM zZXAs)r2XO6p{X(3k{%YBr6yN=FENHV?%HzwPy;bG7Vo*ZkD!M2)Tn!8Ps6QN@qpmV zW;c$6DOG+>w*;6+tpjzlJX`tD`i*Pp_e?a~NW{CAlGhi*Ht;}^N6i7`$p$Nej$mm( zPsm{|k7Kp@+*`v5!T68uW)AOuph5pahyEWv|7m4S|1uaa|Gv})cmV$qG?M?Z3ldoV zZduLj@7CP>4~c%BG?R?#Hl2t3bD;Cp3uO4WgrMeNL5FVVQngKH`zuZA6v_6Nd7d5Z zUMS7&p1q}ETcvx`7Vgh^l%Z$&c9~&JC)seEQ-kD7Qze4L&OoQ^rETI+;bR4m&>#WAL)gI1GT?9sjg$D*>A4OUoA z2^W|I-QS4CnD~Sp6I_68P6EEq_|3b#3tDnYz1>M-Z+|=;<;KYt0cr=N_X>1}5RA6g zyT_ti4+e6VJc-mbzk%_p)4ip)R29&I5=DaVM6W>@2t5mmb|`h_^i;|!RVFJ5EI@7v zj0RKG*_`9IN!10}vx+1UcWZ>7E~Tchb2LlVnRr6|S)UT{7f|-PY$Es?t5fq*5*#8LqT2std~z%;t@ezXB?M=<4A1bK&TipWX zzDA(Bf2$xARkKTdc)|!iT?On*3pBxgsMo)vz{c)2!(GC%$OpiNW&R>^Gqx?-JfWsG z8sttOs5X9Gx$rL-s{hHu@m&76ZXhf7+&6ZI5VT6E+td4IFw9^|hwS1xnuoDI z9{<#WWqP7c`K}zQxv7jqMLO$l`)gL)8uB8^0N0&3e#>pocRzAJ{?;{0IQ&K)TKyVT zdML7iO|NeF5%xMrF?*K*ui=M`t*?EE{-C<13))g#sRSV0uOExP{r$P|^YWsDA9Hl?ye zpJ}Na6ZcO8k)05?p|sNr6&M$nStaMNCv(<-k9lDc^w%=vTP*Q_{AE0_zXlKSGEQo9 z)Z}LDU)tD{YLa9l+iAzTIpkn2-wJ4UI+^jDJsR*h+u9EA{9Yaud3{en_+SeRGSpjQ z1;R0IbCt4o6q`KqritSYHLl#c_at?g`Njgdj_6~t2Zmq>u@Fb+AJK;M%fkbkBOtr- zon^tY!Rt+;gfX@AY@)$^B_I9yPf!=$#RJ_5Kb4?5@&Ug1c^Y>di+YE?9sz`{>B6?Z zeQ%yNjOLyI^q11l-v>ebA0OU{B!G+aB!}7!1Sbi9qMdX#7Ag9t+N|PeThpHcjj{g8IR~ z(w+HFB`(R5eI0O)|J-Nzk_m`RAgRoauYfRr+HeRQ&WAQ9ulcZ1G&033#Q8w&0d>le z&Vp6i)!|AJNGX?7@Ko&yp3U)(?}skCjE%Pu+R|&7&DEML|6wEUSM&O(Rk7N7Wb4e@ zE4Bn*BZal%mTv?6pP1;`XkN?`#HjoH1J)*}HF%&A$tu)nvi+Ck&(Fwb)sW0moP|b6 zt1R$FQuL727=Xh*1Ey#~|9!c7em@?VqTeX1M=w+N=!N2XdZjLlhRD!|s%HYun10+f zHt22xEbl?G86Jp)_~Ouc(+uEpol49l;#c&a#XG|F%;Z`f7}cX^Fhmcn?xeqp+DA|b zNwg%(!pJjwQXng|C`8Ocbv?1|ezHWvx`GLp*2Q}Y{*>O=QD``+;_S(1PwqN#j|^9i zdxb(zVL9zIazvC$1HqL!aVTn>oG^Sfy+9kS^Q|Q;EPtUa@(WxjR8F$sJmy40p6~;= zqb8HK_kr$_>z`=m%T3b})Gu)K4pj+BQ3V`KH^)aKgU6p4x8|X%wTsc@b{cl}Yqxt8 z7R9^$7--6)JfhyGy(~OPHl@rs?f2m2*{g9^!@k)A6GH)__EmDFHPkk^SKR(z+#(FA zW2Ez1>xo}oPAoilK^WKNW_sE$T4s(tp=H4Qe$zQ_Hj8&&ksAHG)RC99ma{~N2cdj7 zdq`YnVbNouk@=n3s@Vb|H$x%GeHeeV#bOJ24(qB%%goWDDNU*d#3t3|Zl}p7 zpE69+xV+N^Xrnnw-x*>}3}4KhwVfxj+$~T<$3}6L54tDT^}I=3m}Bjv(yes#0`WES zm988468XvwSgUi;n4MB4%}0+ESULDHZf|TeDV6yQTvZ4 zh4UI34~L&)ZeMe+kH|fn8xnJK%}!cpoitz&ZKzvO!nNKc@g;>Hl0Hx;w~|<%R2H6f zVTmcnOrS@e$!i79Zs#^(bmdGu!x!GMU%hwK!F4KOH}(`asE$?j9+Vmh?Np<5#DLWz8AHH zkhic@^ozAhc6M)FkU6b`<$BYRx!kgGGTu7|b^J;EMRkqRY|8Yi*hoF6Lq*WV_W<-f ziU_z7S?Y582i*J5cN+NX_c70b4l5d!yL(v;+&5lz1ACcYT+zdHs1s2Hj}*xNSff7< z6tyL=&)B@wPAl?gqAxrn(eZtS=JZgW21J8if!Y9N8V=ji5sTdq@%`q-*j%QK$;`O) zl<~oQ4@spVyzMneMC(NJg^F#`EqB}Gs8-N4?BpgMhCD5aJU$Dnf<4hr8@p_}y$wCy z;fHkO)e$U*=QyX@_-eRvcX=L$1?^N%lfxV33)f3pFA6vusdVB3KntlZ1p3=sFUm2V znTD7<>ePf?#k*Nccz|kWo$+eg^}zDcg|9RItM72VMc_t^FF-RVU3D)y35#vR1O8+{ zBPu&+O_rPOoz+R&%eUOMTKUQo8IFq1X<-ITf6e}fcNN&`L+jX=Q<(;woE-^hZ(nzA zjT8>^v5pN-Gme6m6n2OYz->q2-CyAQJ#T*#6>zH)#K7NT>Mf_*js|gDLmxi`P%N=L zOlP0xip=Ir-UMUt_v;rIU`I=u$8W9i089il&aMPXG1oCKU$Wn_7tHR8dzk!80ppyp z#K>6m>Ew|?0z5rG_qQT`XpJw=Wz1x~~qet*>ubwmp@=%(WNCZ4k zb86LS?EuaP0sYK`0raqNS)y#OS32bb7aF$BTc;bVVC$^H2M4jZL%LrZ2tg�wdc= zqiLY({ic4Zu?l5B{J4(IE|tC{;goZ-W~f_7e!*X?VPq^)Hfn zz(0tA{>AtH^Y$m;W}_H}&eghqC~GWz78X21#sS?WK5+kwl_W32B*z26lpf+aCK z--ww~P4N8qNsgbONBNryNx(wpA5wWQdEU`}iv|QLqRAx`HI*dN;u+`HZ?iga69xy5 zW$0)d@qa=9KrQh(Td=@w7!-R!{^9_#E@nABUjDIOmZky+hdjB1f|*z79CVY#6m#cr z`j|ojy5C#i37oa?@D4K8TQpD6qZ22+Pt7do=KiQMin_1odC|S9{P?uOsuCF zsa%$g>k=II9HoaS%-WbJcM+6?Oa>mm@nZilw@*=$Sxk%P%91wQy+9f(eWsjwvZnws zkuu>Ky7AX(27k;?V)^=B!GhTSoKT`Z1SYwB)9{Xs=(X`M^JU!}a5L*if56x{adATA zuKbxk%YmI``sXF+sFs-4@)apY=tZ^&;F~PhJF&!U^-8~~#sKqa`k}W@2HTT9eU2o} zr&fk;+%>vD<@Fzk-XSXdBMgh82j%YB@4JjG z?~C4eKw(9l&kuQA9CqY9%QX0OK~kkpMlVxE^!k2*9LCZ?@S()kS5cEY8fiCnt}Pk_itc^w?IHpo!fulP8$kAqG_VCuc=BQy$7YlYcsG|%Vhi8BhIg_w2ZxUb|JUp2&M1RGf~ z=m2gvnQpIof|2_klH6Vs%^!d1{qg4i`ePl&wtDgo>8lo%Di6s->q=KHZwqymxMfeo zDS;7T(!cJu{P9f+|I;>%Q;{SbrbJ&@&Xc{EAC~wW60yN^RJvFvY3}V!oIEX>NLdyr z?Myk=MjUd_l4+Zp!okb^J&TcvPDqKF*%^X}`hOhe5^voVNG*}#B8BkL6BT{_V)ZP@ zSA+0lap4vH=}m4%cbS|9L3`QH^!YZ zKyPw{Q{0E`cGSn^{&0<;PQlUJN;?(I*4{NW{7{in7`JKib?O9aY7X~^@pwz%a{vXr zeKZ$7?1o*P;+3IQ#VvIKZfU4TUd}kbGvMG-hW>D^*Nb&#D41n-4+(Qn#cC&-NQLgV z#$)a)g>y4cD=@&3Cs5N^j50VNB49sUFQ05^;r)HC{3zoBA^c@&e$~R>P&-CVON<6K#xQ$FF{g3#vgeT zd>aWp-a7YVc}q(ODmUCIVG!-@eryV|X@0oQkBI;le@y)2_1}CkieiX&I8rQE&PnKu zexZl(q>%;@9HUSp0Y(XE;L~Sff4Hu?B63}UZ4t|90)j7TC+j!kZpacLYhri4UmDY& zKSqLaz|;T{FZj(q@mpde;~%bmsr=ODv%k)YQz(Ohh~(1(I?OT%+}x7DRSWr=MB@QY zHR$0?TDu0(%HImA{LyFs5&M5gr7?O9tE2pAI{j`#vjk#5MZS*Uc=|;($KVTQE0V{+ zwStg=J)m?5qt#GFh@&rzH@`vkP9 zeupX;he3F;Hf5l*K(4W$1_?W;kHZP7Xc$CFPQt?AOY9`aXjLpH4wMJs z4&847T&7XACC~#TSP(b`{zK{SD55)?wkO)CMrkt4-acsYc>4**-VQFIxesRS4Q*wI z-0aKWDJv?CIdhMBtYTAv0x0vbkZeGOV>0EK2Kl+hDO4+^8SEjzy~=S;ox{b zT{d-qfX(e7p5C-dW?+y_tk~y+ixDoYb{S#BYy$uOXz;Jyd? zg~r|61)d;5I2PnWPKtvoWQoApnp8J8wa%q`(FE;=2RQnF+G6;VJDhGgl@Sx^E&qmR z%$2yM>(qB| zlf5?N;IJ3GeLecv&V5}-Y?{qrY=u^^kc7$Rn=NF(-88)FUamLqhnF#TliY$t9vQ)7 zaJ*yoJ}T+i<5#<>8VLhklADL(Cj&TF>n*j(_q1Y#mv5owbs@-m8T;gnV*$?f`#F$2 z6f8mz%ZDoZ?3?u^zHqC@gJ)>#y-FU9>ll2 zp^d%{`hLpqWX4U%w; z)R44!eNSw|q03KzDs>8q=6n5gV=<9!nDcs)e$QLiTL>pS;F$;b>PDgs)dxLf{H3qj zZrCsbQ97ZRw9FLyxob~kCa*jIw`n5EYqLnB7ZWc0pm2Y&^H8TgOn0vjtA-|5J8^Bw zoY}lDP`XxW*8S8(X6bVw!OG@9irL(*eA|5!vHrfRI{sqa7z_^cW|j5xcBDM zj(diexFZ%V2F-_X=j=Rt`AtPnJdklwV6V$Wd#aaLR+X2j#H-niVb}#MsGqPnV03mz zq4(_?ICkf8(4fh0XeC+xu0;tRUE>k+8Rk#zVe8!TDd2Y%47j-5SH(Nv%$!ij%$-wk ztt`PN=-lu|JA@3C#@vvVAB*h2|MVc_G_R`o`j`av(S6t|$P79Upy4rTTXg;K)uQ3j zrRgm~P{-wyVne*L+td%p?CN(%9maN?4^Duw;bB7D6>vM#Kg5CgdDo!7mR5`RPgFSn zpSf`eD(c_1{8jyJPliCj-_hTURDVZ~+xc~OqQ6$o-}s$i7F>@}xA6*x!g(y=s6mpQ z5~xY@Eo$cG$|w8bQ_!!qP*AsT@q>eW_lpMcpquF_@#X+QgC5HQSZ#tO6Vk!OVZTcb{;qC3;m?eTylq0U z#?DA*V8lt2w@G!YZPhT91rukN7iQSr^5K1E5a`a1_nLrS2jdLmv&SVuHsot|)%QxB z>Ufv;hDbdFb#P0&2&%D&?Mc?zczc%Key4T$uPqYku;%mYNzK=s4N!ti45L!JEx^MP zJ^E~{N@)#hU~C|6E#@4VMG*p1?|Aktov6X{(uAN7ZCSREzTr(Wv}p_sy`2dkHpi}x zS(x*X-mJxf{-vrE_J(-Z_mzrR9gDxMmCxn3Xg?LTudR4FQWFOGh#<7(N%kwY z5E;uO2n5#E{vJ?t?JiYTAj8vBZo!&23(l-7mCG%gMSi|{`q@Mep~=ne3&uG08y-uo zDXy^PXK-%a^R@ff;0^dHc&)%egR;b_bQ$8R(?FHZKNSz|7bVbuBag-8iaV(uZiDvh z3+vb~Flk_R2L`zuJL_HQ#&6Dt>KF1m!G+G7suqku8*!<`jto1;?j>!%g{})PDsbq# zpi+_Ij)(r+O4(ws#!iiNId~-@Ygk%RiuA9US3C}~;(KPi0ULv+FyR3^xHPaWM1r&$ zb1J=@?(2S*HmjAnn_g85Bje)X;wt3qmwWwDv-h$|dF)=;qRRKTfCmDozELc*^P8`q zCJfnoZ^*C&H{k)wjSsSW1Dnan33K`Tv$c%hh50$Xt2`~r(#uAps>)6&yqapTy5O}f zqs{R%1IeGtkC>gj;5bD}_S`(^k^)o~qtvJuz*jrSSz5hic2C~6+r**YS)OU63z_4- z>c>04{VlP|pS3BGg|4XM-uq}_p)QBH<4kbN*w60HkINr&a25|bIr|NjGc`zcxtp+} zqF7kp8O` zq`@#H_v-&+?>)n!ShsEAYJwpW+F-@QNjp{u*9dR9^O)_lhtV@yBW5iZm)a=q_N z5i~DL+nC2o?%sSdgtc8}u#sF?fROF$LSZ(&9)GET8=X4;iEjf$G{N&(3eDHwOo+7g ze#XE)p^!n4ba;)`ljD&(-aVt|OXfB%)jFfo67+JF823+XdtAIdy2SA|roIBUQ6Ck9 z=czdJlOYb=5JU07Zcm?s&wZ2ey_a^iy{r`(^7oLFhT=GSWM z_#QHS?v7kID5as6vq;C{vRnC#{c_sBX3Dd!vo?)wGu<&zB)tY&?d z5XkN&Mu<))ayN!VdTqG(*R#-NiwZ_ z&OszOu9-%T@a7#DwGki?Nx55K79&CJlP?2OF!1=KIP*x&US2UNdT?>U%bg^xo+vF+?K2)Y>v5vo|%%4LY5M6NK35E`>}v3RT}`h2Kq z+|7JjxRST%PJs4)&(-8Afy>?W^wX7x>5u2F#`XQgVA)X`XB}zPkgkpU0-eH@NO2qS z!TjAv{Di(-qtuYg_4|qOB2#KhAV}b;0&Cou>|6FYd3#urei6xItL;|RAsVY~M@VK1?Kw7GmK8tJ=Xa`*uh?RwJ5Uk@j1zeEuN_~=CVI)O=PDl4jq z032%?VDl${9{AM0jx1JxjT8oRTO9GzW$}2MU;Gq)7dKX7%dNFczpL?z(yicnNO!0L z!N7C?qx>XS2-%-01W53@7l{YCeKaf@bwALOn{8+SRFe03b|eUAnxj&33@vk&{wi^J z<(8LpnSZoP?8Vz`YuQix8}7y zPUcrbgeQapCuKwJG=#3~Hb*;(fl>pkw*)tNdTdk07dHg=68Fpfz$y>UnegHca?fNi z`t#1Sw*9wIq2p<0^!B!@Rt|77e*?LW8bpAYpU8i6_2=N!np6Tzam0m=H)RL$nbB9b z<LIiEUgJ*aQg-@ZpNWF_3R!^+EmQ80X50Ei5h%6cdWs} zY0wJ&jriXjTVOuY20x$u zvMJ;q(P^w6%FFA>-<+jgS4!C6;l=8{Oj_a;Di!lkGyhv3Chx`>LZ3 z+Dd865xM6ZV5fxRjK>sU?q;LCbe9R`L$C(k?*I7e-MBCL(#~ZYe!If#W;J=T)o-?6 zKPGT$BinORck6;AL+=3LEq@G0QZeU|YrNlkdlGE}gfMz>IJRx}=;al$;4=68$&@;J zNSd+T+1le0M9W@=o7FYqORw&62G&JYF{I0%qm^oW-L|w+^IRF1$b%v(+jDgEE~u_1 z@rt=aZW}L6rp1)lhL90Mu&2vYR=I98Y5iWY=662Bjr8t2lT)a#>h@T?0EGbDbiGxL45}CRE(MWdq+%JdyV%Wxcz$AD%f(a4p9|A z)Me7Rb#C*H*UH#++dF8ehhX0V(EhAYTBP4xdLi12#qll9Eo1@OR0<99KxHtRU;Jb} z{dl-MNkot-3i;5><2(tvQsR6|IAyL;1tHnW4Dt=M#m~M3h|Uj0qr90wmef9o>ZOH! zBQU|CKdce`!}|cyrT@XT+f-|-#!GT)8n~*}ac?o`yoC}q<1vN$%A7sVn}mT7N?pc) z_f0rw&y}wLmpn+iYRoS1WkZA%vy`qJ5ZSHk1%m#4SOIjQV;$bE51!MoStf5Ze*in_ zWa$-@wkV0IFVmuM~R-WVb<};LMT+G&qRx zy~to}1NzzYTa-Jqc~C2PIX(;+VyYgYK;obw$G z`k3(x7jjSJbkq>T5HJof+IxDYF;v+x23BiWd>uWzLgXUg7;zC4^JG>j1SmA*G>LH)_H_dMdH}zx5xRv~EM6oFCZq~tA|rdym3lB;zG||&1Y&`Pi6`K2 z{49M>%nAesXF-hSc*X&7@Z`J)rNu4-)^ezye+BB>-sS!kD)z_U|ND_muHs&3dI@$A9RaEHH+ttI?=i zp>f~vc`kQRXrc)7_kd%rT$%eh5vQtXirja&djnsaV?+dRDe>*a?ENJ4l*zcEb4VVX=A-L=u%e`SJa8UCxVKUDYExB|#nw3ya?b z`UdDq|GPuSuXdY*UpgEtfunbNj11reRouZKjvnj9L81B_*E>$tR%#4if#u`~LJ(U`jy`v{IWn@C{j{Dqxz(?5jhPs- zhl+PuOuuTA+;bR}$t`D3_KG^F)}PvQOl_<>)!6pzqou3%rIxB--A1rE{etbbt%{wH z7tu0zP_d3LI?Q(4L}v1;qBXrU`HNdy5)^5`Fj9IkQl?qaui$;{^LHlpp0w@-Za$xU z7MZ%qd0Y7RbnPCTD35I@Bixp#RHR-Y^pAQ~PBy?)Z#Vm&cu0cF!jdhC0^TexFQ7e;XVhaoV z5eH@EFq!yeal%7E#+sPRRS#Y|jgMD+oQsZhRywj4DV>K>s$Q^+;uN_v$6YgWa4zfS zLMDaolsvzShbmn#fplfJ%*NUX*r6)YWNi|k+HtD%Uek-6mL{X;z#zASU3sb1L{z*TKGlEwIZ_Wl?tNzy2q;KSJ_DMtmBuN* zPS9XT7~!c?*HoYRs6S0)2fH(5h-=Y6gD^9ceVHQa>RM3SI@8bgb~rBJHb0-P z+}FddE&SREqm#Vun^F_O53I(>BQCAdEcWreg?9cD`afd>+$ycXu*vBHNru!hY3^6= zH-pyWBJ(?D$;)lOe*}{i)n1PWu*tD@&61Nw7$W-USg(`OMof`|(f<<3kLL_Bs_zNC zThUmMIXtul7tuxmLwq5&j*tVV;RkG}nKIT}(C zVge*c?Ae{(qj@UEH0rCcPeT=EmgTIH!1Tp;V?FbroyqVzHX~|f=2^HYu3(&fH}{CKPj}Y^&1=Qo7sTOvoF|w+?@3{|A-T#lja;%kbR>7^15?hIsdkrwnTe- zrc1SDDf_RV> zbGFOz7G;V39cdhn1S@cn4rGBv+?zd5@gF`1%Eu@4QFYda_V%C+xJ$*3^%(Q z-k}Jn*ht)~0L?j)Ls@S{w|r>w9>z!{pev)NOgre;UAvc*?(R)+w@L=|_AQT(g> z_@CcHU{Dg&b;AuQKOzHJoSW}jn7YKnj)h7mq8=yMtz>j5e9+GC6UX5%&c;)|0g}Je zG{w+7t)_LA3JjTsuD@FbO9FqZvBUQ)=x;T6Xt-u{Ys>p9@N{}heS+S=;2?->dnYH1 zP^=$)$>zD(e&tY$F$kZ^PN9O5*HCztU_+RKe^}1mv4gJPEQ2mgLQyQyh#!}}``i9% ztN*tbmVdYN5;?`|@Yz67aZ5=+3(ikQeeIGt0VWGbIr%S?@k0+Nn0+KgCSDr%9 zdRl4zEH6N$Np82T+vM`J=$90mQhTxp(D-kAC_H_Cxh)=)XrqBo*2h>GUjcpF(N<7H z55RZ6e@ioyP9nbc7Rqu=lX#XD4ZZ?IgwI?S^N}Z)Xp1rHBi2Zd*u$Xy4T5*Vz7$Ui)HA(MBCn6mjV6Wzi%A9-S%@NKGFT> zBXZzNf*QSG)>mnQ&Ah7qwZ@f0vTT*~MeRgus+zL2r(x~w<^CtoM&@rX^scr#F&5}h zEJ_n<@2d&sEjN(GvyN?_h!+EJKNCY>>EGiQ|Hpb-U&J|&WoW<`;OX(t5dLv8eh7i; zd-&Pk57&65!b}*Gk@P=t4z!G$@c_>G_X86Cv(D>J0Dj8+aUXwj^5J;&gOZf`qR!m9$Qfnn~_#K$nZQcahSK4>( zEdH*ZCS-nh2bB4kfn2{4QxJl<_bng!&FLdCUeuA*j4-c*-c3-r%9X%dpw)g~Xc!0x zfkY_@{i8?Qw;Mn2O^+(b`xFj~P}t*G{e1KOoLT=NXa{wh{zZe=wRM((Uuj>#(k;1J zIN-)BAF(2hCTC+?m>?csnRf7jeUdP(#5)-gC&O zSaTOZNBiBK{`QCdIWFX%=sZ%sU>k_Y_rmey-X@NnQ35P{aX>a5IKiLNFpeLeN=ANL zL`O|0Zy}9JIf7yR#m%s8OKY&XRa3>8TE!Zr&bwNF{@u4VO%p`c4Al$^>9Df2wZ7zO zU;b!yQZ^2Sl>+p2(I?XlJ0zZseVtrjD`v8nFx#FT5onnVOqBYwVMT&9;IgIZ&-u2{ zXgyhLV&-ZjTu1BxGL1Cf#p{5FBxL8kH`9|}rt#iJQ5dTDEZ_dNkA@~l3(Pbeo#3^{zNu6*+@p)uz!`XbfARU!ZM+y=$s zTu2U0mo6w)udU12Qpnj%jPyLF4`mXz0z(Zgo||P4$(~h+Ea0|XEw$~NtMx5;qx;5HJ7{1p140X9}1E-XkLsU1> zu56eHS?do)inuMNqzrIx%2#iByjAt=;ps;4?TTeD7PzJo!McYz7-Ud%U@O8&^&;H^ zbiQ}_(XLZdDYAxsIrtZB-!(&)90+ZU1>@u=Zrs=A*OuNg`TtK-e<%Z6BZ$|RbL|lAKGjm(^FfLX!NA< zgFW1RrCiJLXGN&*+MA}XqpwTlP^y3CTS&Wz2rR0JM@1G4j+z)`p2N0!oIId}B9`ng zhH$@B^jv=*JWK(c)<;lMtf1(iZ<4@?gkhvQLaWTk^GOGn@m!@>RZwpk@(y^tai5_Y zD1a3d*aM}I>D-lXb7Dmtt!-H|4%J9;X!AR_&Tp^s-`-x~z~3q0{L7Y)wi%#AudlIm zHEco2Ok-??&}haWiOxB*!ddvTWEoC-I^m&DG$tZzt2>cPv0#G>C&z(ZmDgFOkt+nf zkje=u)kG5x-BUzLe+7&qkv*Os&pvZ*mx~BL%nx2cR7sC*-*|)K<%$x=RB2BJ4rqeK z_;)$OcHHWl6};nc7wP8GEcj7^ zJzhsKIkQ7$NWD>4-#)>bC>%HA{EG|Br-9MEujhNjDB>0#`4fbHn(1aM2F60Fyt0gOZ@42oQUFxGxUUW5iIwdp&W*lAl#(2`w zRik*HYMPxeE#jrjEw5F@c41BB-v!H}aUJQGMX-ty8Er>?wGj!ATVtEPnJ_FwHo5YmR{(bbmLxyqUkx#k*d>ibnq?`LTBiw* znNE0cJ(Ik;8?lfc$37_EOF*BeV(4A4D}F>1Y-lwqTT`|CveGXSxfY&0*e~8 zG_Gyb*Hez6ziIb?u{LE?g?&XgHA{BzmN`z{?jUQ(aQ3rqlz7uP?-0rC=IINed(W>G zxQ^Ea3#( za#v2RY9FuqRMIMGiP`9mE-qvZi=6sH2L7QKi>HA>Z9~n7Tlv9~8DF=(ojDzCc%KVe z{StY{R$r;}bbe1#v-koO{~jNin~|J)d~<)7%}9AHgB!g$)E_&FO$a`hZns%_ zJq+g~QpultOTX|i%ACqSfS|KJRsMtqB7*5dOE)*8O>}p`(&i-2C8`>-ovae=D_pvH zbZQj8RP(8)d>W=e>pD+Uzy=H%3&H(ZzN9ZkGHFfKP+c8#PdHYdIm#uh(0#iuV1{wH zK;1XmytXKMUV;ZR37h8e%bR|;AR`hJgqtuZFDiF0f%4ezgBhoFIsG?r-NpiN z%Wgb$`KiMccAGxE7wuWBuA%aS3+NAIy(MT%+S>K2fPT4TE3^{5H zG9}meFr^4GogSko;79ez@1b@rZ4v&P23yg*z24@If~RX#1?cIOh^%ClsAeOxMI#OS zbTeM358Vl8uPmJ&Ju>PeqfCqcB(vmzuLN^IC?sk<1|PVN?Gcnq)`s?<(zqg~@Zc!s z`6YsGIjf163fMui%J`q7Gux5HA@DDCVo%`os*TT-s#^yecLk;w_Ok=;a_(R+y`seT zvqJyaEV|3oIma|1UgbIF<|bIKFqgh^ZgfOQ|QHM z4HL-dWBTaF)v`SMC3mkTxfED?2MuAC`498IZq_9~c^(l3*&Zaw^}>oM(^QNB{u;DASG-H9#DnL|qP2HFFykp;Z5LL(A4)HBRLbsP2ye}Y$JZEe;)~^j|MXi4uLJ#uBFmgV z7&?-fFHP~i>2rY%T}FbE;x+1d<>C^Zy`f9+vcM1!d8Ne+p;+V2-wA5cxcueht ztw&i5vy-c@>W!5I?M7iAn0N~bd9`$)uMYxrK&qzJ-yH{W{8Noc=D?XOg6GoV0 zDzOp~?!^zKaWCTmk`9iR7~AdJcM_hlWqypN0!dYrz)dR<%8g)d&;2VusO;S9w78(k zH>>E`1drDPva|8AOSqQrXazvNRm_&^fa7z&&nV)4&xaa~+WnfJ!~57E85blS>n=4w z`dTDe3>6rKm}(5LiSGkqV6T~RL&mWICmLc{m@kRD6z;ajl#8JXIJN#q_|N(+5KP%nj0THE7_2wE}06p%qa}G z?6#tj6Z4(CdzsFXZ^_F29MC+y^1PH@_@tNj>ue*1^9-zq9#G;Od63bA?2l~QtEYLv z*;ch94b9h+YC zr1@m1N#rRmo4{=9Nt`3@XqF3jGDRO)mvS7~_J=&zZ^aQJXk>Meu7;=172_VcC^@-5 z>#%pUoj%0FQl8)i=Zl}(%P*3VQ?Ux%fpdhw_O>6|3kayo0KO-{D_bFynNzHfjw0O4 z+~g7>n)#jMhd1RG)R#vl70fSlZ1{s!QyV++E^muOjA4DLtAecv^isg{E70CSx0yV- z{1D4S&5%;);b7rXsr@8#x{L5-CleLxH0rTxkC@L{7f1a*V~0<5PAes39mCtRU?*na z(+CE|X|}drNIImtq8Tm|t8h^xD(`iQn!`n;vY-9xoV1-|?(@Jc<6}SYEOkvs6*ay% zDn1Gkd_%SQB@?D}O>?hx!X|PBm$P4j8Uo)$Y|fKej1w`*ug-QkmR{^`gEuqSMMlp1 zkZezi5sp;%cX(La7c!G!;A#eU3F(eUWiLlpr+JtLh|u?_DKhnhNM57bidd|wo*6>u zd<8Dsm$}_Gd6!0CQ`zH3z!}QhaERF!d)b~e+ca~k`C1ktfzL?llWw^b7B6IfDtLQk zobTL0Ka}*0_vwmm_&b>t)a7jnFO~O^y{wyfJe{Y?F?m#Cqo1^|l8Lye5@4H8daXP!mV# zRXs-$cKhylh=U>hP?z%MqH(lp3J8Of9@hZ2K7O;Du(vau)fTSK^G<0nlQaYwz#DHr2Bv~hyL6Z z#|s#_7ZyZ$CiAia=+dTfaxOXHy3h&-y$K8uYaT<^AM-pitnZ?9I|Yj*7fP%uPi(@k zc~h|Cl(f%6jC*ZD#fOg_){la2(?*&`V!?|dASc-1;n~VYy?Y=2zPXV8_Nhkk&_VhYn<*JqPAG_yT_q!Gk(geU7AsfcDF7xroPCcrG4%!@#aM3E{KMO z3@n&1yyFXHZ8QA}WZ%Wvk0@Y$bDV*{shgd~7_K`h|KUMQuO#*2)6DRT3C!8@OKKr^ zQ~~PFhMP6TA&63kY&>VaIy;d;*S6QG@147#DN(OnhinSI0%S-$N;K`si_{My3hJJ} zURYwlT(FEtYbii)xT8DH!mLFFkdaWe2_-4D z*KI@Qbw3-ONCq;uH<^TLj@f7dw8`UxUjbp?w0I%9-at)9@MisF4C80~CMEZY^b+e^w)_Ov zj$*Q4YkN7kPp=rw2$J;3NLoGW5_0sexc*KX%*<076@1IzZLke22;j?q{+!RS7Vdy# z9>N2SFbdFfz^gkFMsSMTaq^9-bFGu+fIN7=%mGDg3HAkU9EWyBz~_(k1B6r%x^tI7 zYSMd}R2q0?^L3El^HN+0BsjukJsr+U<^J|Pswu#wyVQz#95X-$%mmHTRzjM6is1bp z0-lQV6o+ZY6x#~D;wjvF@JQBWvPlL(4r_J>g{oAXNH&Ly&|wRL!RUX6?gE8piwK-g zW`93E$SAb47yjh@!hPiWKTpM!0LYWz>4JW;5&!w{B&eAFmv^_7wmTGsb3ncoRs-I~tbnNhA9ht*&}SIf^W6D3OBEds`KBBM?V4f$es8qXU}- z!G!OQ<>cexi*}0v#rk%JTnqtNtpsg09~#EDeF=8g)F*tEcc{{`?}u4>-)GAV%AjAt zh;HnPR@*Y}rz&mcQQ&poWq9p(tO-fk^qHbsgkD0V9UD`$J!#gt5yo6JsiWpKj3yqb z3D3`W&`1MCxd&&8(S)83i;Y&bvE7zUL7v+Y28O*19;|hh(*#sL8X~qJEtO!a?NYNq z?naFKR4unb$<~o`)`udJ`vzqF)B#ss5qayBT8ZQ5jk+p%-*h|6n{;cyouY_uJYkD| zs~$iNFr+oFQEKz1;~*7Fa?4T{O-R{~BJCXOsMYl`6Pz2)c3v$9IeTqMU=AT)^`xH% z451z$_9N&nw!x%47gcVG^d-Z2?8t@9)Vcj$I~|t$d`Po6FK#3I6y>xbU(s9erZPi& zGgB51@Lh6btb-GDegz1P?;KNzB|5Ic*&ft#CiBM%!yo&jPd460O6DL^jzZz9nb}Wb zXFgw%JBqs$p)7URxha4FH}I7khI_gEE;O_T&qJj)T6W5w*EYo(r|`+k6%4;A2?_e! z=bo#T&7uob`ZQN(5b52gpS=?@t?ef#D`#ddnuRHQEtTVbYC2QB@D+$?TgCz<6c3ER z+gkBKSrACRBZt1hpFwptI-nA|j4*#GDg7;#Yb~E_#^K82O&f(=T@8l)>8FNo$t=it zfl9fRUQ&j0>w|BS!EdZqr&p?I6MAOJI@8Kmrehh?^b|yB*I7ORe59tBgTGj|-+V1k zuRbuE>67sqLyOH%=I$E?wR%#9H6ZpwpC+-teB{5UU@{brD*f35@=}Oh@Q?U*MC(YD!~h(rKvwXuYCm_*{JtorK`-;SMu8G7 zaxK{5ZEg}^2ftr;;rNSX7ynx={M6)4jac!esmdq3pTuk%h+p?M(CS1ZQWo7~%6c2k z?N%6`5ZQ||qu0TyGAI~45M73QwpD5&B!h^%K9_ift=KrSlT0Z;i?U{aPfh;bzkjd# z1|Qlrzel-ic^(2vmPT3iK|ts?)0iK!pC2=!KYzc5d$R|S1<3>RJhIzv3MaB63tYRXVCPfY1T}%NCG3AJTduu6<8~>tGbC^sojki z!u$H^c--5AJW1AjIj`*su|s=d${P~6x+9lZgvQptGdP&g`82jumOm1GIn2N@58(FJ zv=(vZ(z-97lR(e=z{Bn^i`5f$Ry8_cye(eezPQpIzFLAidP5e?N)5HWXu2kvu`Psd7gt^dsF`vG*{# zy*oxhO!zk6)pxm<=)S5L(gmKvc`K70{=C`zgotvhDc{PcmL zx$1?GpSlSB#rXAS>-^14J}Ezr@|}sAXf=*;R!;=0)*A#R@{bDBUo?9fQ5+!mC2(Ud zXV3Qm*g;~N1_c=aIs3L5SpkAy0j6G>{qsz)-c31=bdUbkQX}XopZ@EOtbV=tfBime z1ebP;+P57%G8CA}HGTA6a2*W2bUM)idE3sQ$Z0WBUV&oHYS>6RP_$%HJ&cYiPvS)o zK0X-{fvL?`Aa04^1U38>fa5!$g!L)XV(_!flFWTt7(1#@E&V4~W3j|E-!cP97s;8iln=*$ z;IjQUQz?uE^I;5^yL9)Cw-xO7M0|3{cr$YPW8RS50FyN(wreaU0;=fxt~xlc(k11G z>BUybPsdDab!XprnQ07z)APp*76DhY(j1r_FEQobxsj|_5o{CHu%j)HRgiHJW=-xw zi$0ozO`7ow#b!e*c^4yv_^Q|h!<*5bklTy_)Km)X_f=|i8f;Tx574Owgytq_$uVNR zS4&heoLDcyk!c4jk(XCA337$LkHr7@TadiSV3*tLck^tYdSx|$N?snFAy9K_+ku%j zAhn}dy}OEWa!|AYa@E|u^VKgNAa%tNWP1aPVi&EFwY~zu z7705lLDm?3Y#VXLiJ%I)?Frbhfxs5*%-7=xg+Q0()4^6uTgI6ZvQUWKV<6ww03bwkLf?)KjSQ@D&sz z;@wi`98J_$K*`N-EtE2R8ctmYwuHHETLhBSN)tlp5E;HayFaMXP8hxMAq=q?L6YMZZg#e50D9s+eTfn-Vnc6i3pb zem^GtTzTFXkbn6v(fsq@qMb_&S(>MGRbuJt)E?E>mBbBo+NZmJRJIT6Lx$Cwd?8pd zjP4scxl$^=Rga3F@&yO@82iQ%S@Kg945o_eii&yWEN9gW@JQ6#69v=;!*je%mb}zL(C=@~ zuOua?Qcf1rn4d~(e6K_l&)`>6hX1;{{fgrt&w!i|Z&;18s4b~}lczme?*~4P#KO0N zghH`$yQ&we)!1&V#(i^F^j4S+Xom9xp6EW_>D&i>}_@qY_RV$!iW&5UzEgC&HF z>ZaANPCD9e^j+Vv;~)QWi(2Dgk~0Qe4L5xk<(SX=wk#_k@H)NNIE0UcQiH9(!CUi+ zl5_df#aU4+v`@ru`ney5;%V{3G3q!&Ldu0vJU)y~O-ZC`l zerDH-*L)+alLA;np@G%i7;(@{WU_@uy*2vYm}T>e$ja-Fyr*9If|cJGIw+{SEp;`y za;LAOPE6M0kzfy~;(}H)K&|WXa=F6U7NQWPUjc++1+??VdCU2$8JB2IzUAa=>*?@- zc{Z5XeBAiHI=(+4{{`8l2vw{?h264?&7#)DRD89wVgpGVhKar6q_Z}Sn8A|737fk7 z3*J*CE>1YUqNAod7bI`J3m(${?9VDgf#e;Yx0n)kR?!CrcBxzVtKdcN=B&uEA!ofi zI=&>kP!!=Obfpoczz0nZN$QAR=4=F4Ub7X+Q*ycn;Ta!KBok~ShQ!?Zg27~f=vGe~ z5gU>x(_r4q_)#4;wye-Rud&~`o{?Qn;n0>DKxMxwa$V&Dg{q;ldgF-i$ z)tu;va%vqp*#|51rd@)*+XqViYw}9$xv`AXl+<~zeVrCdiL9!dT70B=`kjI@qMHn( zQtU|PduyW(F@inc@QtE|ReLaxLStxUFdW6IArm%jS9Ch{ZvCw~U>+YVbSQgYFy(RaZh#jk zZBNMDU1eqWU+mx=V^HN%UutDhjDDuLsB*zZhkugbnshv97WoPxa}X~yy_tzOX<+}Q zCL4Ze8YelW37GbSy#MH6v6~I)dQD^Yv|d@MdP!k}BO69okDFy+cXlUE4K~mwS3jlj zoGwh51iHh?YYIhbI5I2zSO;~69Efb&ESLuNuYt2w0`-YjVFiccyS0sG3g7H|frY7u zg}(QyD&ZpjH$n+SuR*f0GRv>QcaA&}TE)*|)9vRz%z97_Gi z@Y%!QZNMB8z;IOlaLhqRZR~!NGRD(uBzt!zYYSmYVheeCG@!jMx3(@A(_Mp+t#VSS^NV&pGX#<@Kj$JFfs7~vn0^} z-))x^6}SV+s)w;!)r_$~=J8aw$thObHy3^;6GG_sEmJq+Y@GtX0&G7St2n1uZO+mh zuANK~Fh#b~^W)Y z0RqsE=JD1d=Q;X3>Li2Ue&d)$YunsAZLTf-gh?j@T1~ZdeRvx}xs?ud8WRQ0x{}3V zLWpNzI`-4X=rcRp51S+@o|Cr7*=5gk1j#P#7~lLMaHYh)HbT0P6-pv*w6F?P?TMmJ-_Fu#kFa?_Z*slH~sSERy|WWxo=;Nr7*!>E8^Om-r@&X>#T z#I6H&T8aiAEW!*}a*hgDiHOffx>PZeit0%H)jkv{roE^gx%aqwAl9aLSlN*o60_sk z=GDPFUK2@H%k8HGqAx#*F|@49CaL)o#Dem0jcMEO$IJ!LD0vVTnvE9a=omlXzRmhU zD^Fsprco7x%UF&#g_v^0=_ttQDwhTe3qia@K3J_^-=L;k9(_q~G5hAyaUpXC1^@}* z`fDX2U(TJg_gIqwR5E-TIdTz`6!8+#>XCn7tBmNY4oAPUTb0b@XF+Uc_AMhH1ep_)L z#3j;-LBHm3>ozo^d95geX9>2tIdg?+tj)W10d^uLIn&mkdzrT@>l~<9EB3(}N?O-` z&M%u06eDlfO!(3}WK>7cKgPXP(jOgsBtRh(5*S}Qed{6LhQF)H{sdG=WW8;z2(%&U z^-PBirZ1`xbmYHrSG4E47F9Ed5MEdoVysAxJnwqHOYm8YG8oJ&SMn`5 z2x;e;e6u}@fk@!xK$C+_)6&qB$vJ_Bsst}`v4JtFt=IcmKOM)&8aP82)dAJF0w4|Z zsjq^qrGsc!k$wd8g=lOfb99%-*6r2=-GIIqec=buLYya?ZK>2hM+oet8Z6ky7i{sE z+;|^z>17qmWZe`0t9l3@<)*4|i-+lgj4kMc&rsgwYjQtF7jS#$f+yNc$11#irFHDp z+FVt&N(hC2{31?^(yO;eu?pJjJjNmah$#E#O(m##ijg>qkq=g@np~@sj+^iA8l`2! zmsA?z`ku~=H!pXviP~2G<}@cNz)d?23fO#CXRe^(d5gu}Z!}K9OQtNbA*QHV0|z9`GtG`cM^&k4VACQu7>yu#aAU%gru)c zlh>u4#0(Fg*y^t-^%J64|r6XFMRsn1Y_O+H%heI`WBP!c-xVDG1Rz_YL8twxOQ z0mf1$R!rh|fl3)}1q|!PtWa34%O1?n3ay6(v;Td#$ctI4I_~H9vM&TMWfjfpH}|o! zf|g>TJj4$auZrab5SE$BcHO>^-b_3zNJ3Z>mhOX_{E```8efzdt-cA5v4^}c*IoV@ z%NMa17h{yA0;~@p+Lu=2TRp?EV?CE+oUU#2@qxiNtM`g~F`nv`CRkt=*?xekK)oi!3?A2WddFEZ-xd#- zt$X`I$ycDWZuj^cYkt4n9n_36p-9@I+t$Ut0w5)%6bXudB#)6>p9(SvE`fXmhozlU zg0?j|BrB8#It+d(bZonAkI+1J11iXu&L-cl-bb9RI|2!uHO+3dD$R#H&3)a z0LR(E^IRM~V%4qbi=Ty6_;1^mca_r!Ap6quOTDo|*eQ;V{Ok>1yh;uC(RmaQvKk=5 z`QM5Kq`qL!_st*BKnGim3175d*k5|W6&N=1$S1)dN*4w&FrxP*#yWH@Ri)vZY!T- z4CkNL7f_og3CTC8%>-M_*M?Ml-VXNjjK!W!izZK9Q@wH6 zMImy}ZXcA0hq00NwqCz& z1BVWe=XfSWwAS$M0B_`Pm&;9h4)3&W#py&KF|X$~JB{Qp=v3L7>|wNlQ#r6vFDu;j zy@*=j$?d__LE8xq*O?7-i|1=;@vGvPZOgV3Vx`7wY?a-)Irp(z0CTGmC3NmL_`=$K z2`P1U;L{;z_7PLxJvZu#^OP60^VVqktJiil?l2Jg^ zNwz#EV7aBOCyh%OBXL>UJx*)_Yd2qo>!~BRjf{**V}?crfttkS_C2AMUKT;r#HuOV zqhd`EpvNMFosJXSFJ}Zzg!^g?vH~cGF=oa!v@eb?Gk+T#uLBW;5~@O=Jm9|oApOZe z`V#;JvM(3|xI~PKYNKJrGoantWR7|MWUGHAqTi#ir6r+^ziaiun=h=BV(iAv)T9Zw zPrP&>avH{R@U4aOxdvX3|HIyQhc&gO{RR=RP?X+LigXa93j{@)h!iQ(RgfwmAP{Om zq<0XIA|Sm5r1v7dNN-9{=pc|#1B7@tXO3siIdjg;eD|AsXYO;qKX|gU**jTlXYaM% z^}fGyTq-2;sqAAYnGDlCh?n*420j`deBQwG+Ir2!LJ{bSjubwr>3Dd1 zqEs~8<8~?<(7ORF<3T6J_z~LUG*CEBt&@c zTZ#yBwB+4lLr~;Cp5L=00B-3ubP&PZ+t=^%#2ow{WoqKtLtg(LsrBJOANZ zLSQNd4TpS6 zHv;|eEX@x_0f~gW-YlvF7H*uiqk9{8`mHqG4EmFe?&HD(B=2R_4V7ix-OH-^dqL;=!KNe676ZHFbcT1}Jymm=5BmLW`or3O+E!sdkiMv_yI-v7qF0mWmc? z3Py|NFh#RgmD4CA6Xbo1Wt4Od>x)a#ZH`88dncPKryG|*pNFX5&GN~bz%1IWxujR( zokV&Nv#xYqGE(cCAVI}At;q%E1d2knLreLW4%y9p>`8wpkw{(GlzkA77wm^d`|x?yN1&VZ9xM?!$ad8Ak+5q zmhcy73&Br^K+p1Tzii?F);sQ}Tpr+;*(eD#X+mx;iP4&x}Z99kao$70v(%$&OiB9nd((%b+iDlD5OlK z;7hLxRiLfGQLs8@{3m3Je;}#;!RxaDQ%-)f{ zv~qdUstLovL=5Db_E%N_X^diBU`3OJB_|1ht{m^~0`kjeivohyrrlFlU?|_;7`I3x z0b&V1T)+ScTMs<_$9vEgALKT$W#k1tb=yzm!0pOHUxY6PO&iaI<*TxP2NfHH2hD@= ztrE*8H4`gZ3|XF>o3UQC{*a{9G!5=)yonOV92X1%4Byl^0paJy|1 zV12*8Hit~}xDAZj6RD}dw^TGzp%JR&YZn>X2xH`LK0Yj#{YOnAVfL1c$C6V85MY{S zp>xKkZkFiF@Z=}!RF9=Xp!*wx`_%kYykyU%@SX*kTaJpq@a;;wP|uC*RYZm;@g?wN zO*=duJL%)vlInk4JHG#R*7T`Ir2+B&)1|P76HfpaZo>D(yn$_b1hd5t;)$+*k)JI6 zAd$=DC*e&){gj&MFu#m$PSm@OYl$3iiRoFOTQ4^|?4xV>wyndFc43K+Od#BfgEb+X z)j%teDykovh2;~49$i!m?HleoEp_5tE313t&O z^7wADO|G_+OCO79L~+_VwWKt?G|O?c>=rC9**tL!{@739!uXaNxQ-Vvd5Y(s?4@1E zs8Q0l=(kdE3Vj}qCv-RXD=vQA*}O5s0aDUXt#y28t_37vM@Q}TGZnZKm0%gkPj}I3 z=Rd?Yt`V#$n#zgs5R8souTsP(1BVG(i{;o1B%jcNlCQ|$>B?|hq4N_F8|P@@zoRCc zy(YRPgku#Np=UeHGD#w=%e$;AOVtIWB3@}a1YNpH)2exsZMbUN;HnH|Zmzj*0`yfg ztxc@~pT`Oja1gncyYEewp0(Ljl7zCu_ZH{$xH8LnBK+>k>B_SSDhPqrxl*Sh-aYEJ zZLsQX{Bmf+J_(=?HG`48HwHN4r^kX!cSf9V0TFnb|Kfv_yHTof&jX(WIqSEY_C2Mc zFcL|NFV46dGNkH?MMZUQUrSl~BiL-Rxh^)*@wu9VTW| z2V0}_SP_>!%K=O}qYppG*YrK91uaRR2P!_Wqluj9`;`aVx01QeskjC-ryfx>No?1v zVU7KZro@gE`#@%B)s8qL?wUsbDgSaCSPH;RjQGY^ul7pp(=A+IBUNNAs+@#$u6$s} zz_xim--xC<5gh)Ib;&F;_JAB`Q`Aeeyd3pbn*NE$ksB?aq@#)5f?~Z;=i$yPse;!N zGE9sw9*SQ!mS8?<@xCRf0@rYswqY!sJYxP!Nxx6|68v;3FsZl5tV|rzJk43D% zZ0Wp?B}*rjphWs{Ng)%_h6K^RU!jC&Utvt(TZ&MkW<7GS&qgj)N@Fm5_)AXsfiG3>)F1xn38#{MxZO_dfg0V>nG}9? zadm92msu9~;kWZvbwLMd=VVK%>_-VFQX#iGY2yPWZSpM+)zhaYSDrGch^U5W>(Fjk z97w#HklYkZ>j6wZN!nRjn65bWc9zDi(KyUL20VRN9mj*0UZpZwCRX`pjW_Q^-&6{# z9Vd=K`FB1VdsY^sk~k}#^uiH5V+Goa6twP_R9R?HRX{B#r0aM1PcC^oxCJ*LQiCPz z{OwH2f@ijKpzwfbZXXmcaumw~aZ!uD^@8Qbh@E=YRz;v89{m>3(d%y{Ob#^O`ggrS$sofdw|d z{yZCVz62p|`$M*;pJ1xw9uGz^qAqy(`cjL-p?)DTG7J^0O{h)qNx+c~J3KW|gpob< z8?t%mf%J~3x}j++LhX%4$Y|nO2ca87p3^b86EfyL<8?9Hl{@Zz)AGwu( zcfRIFJAS;r2x$~i-9E?NRk7_mPIeh~2gSOWKr-Cmm6jsa)8n-fmhCMD^&hs}S<|?z zcwW`kS(LiZrN;rMn6HWi9>M4tE&Me{b@!HYpPQ*5H(_2+%AK@}xj+JyD`O2=-lCQ! z3@pDv0&2b1okNlx3jI{bxCjpy0)Fu2k?EiaYNR_~V#%(Cwe^18Y{ z<@(iMKfKVftp|z=4z~!+D;F@fSD$J|M$`0?xBdG7ZC z*v7+Rs=|FNn*6Sk)FK2khaR6)aztM1G0iG%9MdmA?sL=t`RdPl>08f--k(kBg=zXgKgUAsj`^h z&**9>BJz>X;mI&WwS~4ZAh(luJcs9CweH>v2yB}g;_9KA>G`JSPMtUqw$)a~95ngI zi4Jn;+Dt395w|4GciK@xN>#M_PawRQdL}jQ>aiD_7*6D|J55)la3Eu5AUBg)MEg?CwoVZ`#|^@w z_T?em>ZQVP^$afD^w>GA%*d*AfZV3$YQ(t)W{62mxwS67iPNM)1;|zPlNir{|5i4a z|6ZLfZ|DRV?x&4X2x;Z2+M3Gkb8-eE&YTesMJJ-$n$dJ-FUq+f!Wmf@Nfq#;vEuV> zNqdtDSs>SYX7`ZqhuaiGW9pdnriU@yA_eJdWYfm10v|rh(32Trqmawv1M+nvIi4HR zUM7>JLQQWDDc!Q_OV@WQUrBMs$0PTB`&qtm5ljGLm?QTF z!yC*mj%JpQW<*@l@wPZea-P)^#jde~1iLwgzqg*`1COd=;b(QSOPiBSR5K9*IRK7R zD5t?4z^<$Vy?l8Fdqt`S%=buBh{euKX zl>bsYFFDR(Pbi1SYI3y)H|y!Ka*VfqgEzUTRKH|0RG6g>}KHh2=LMBW}%K5u;k zdDD_TDAPFVqs2KZuFJ0y@Y!CDe%<=aUw-eilpIJmJtNpyK-7duPhH4#UaSw0SNsQk z|Fi$s@CP;Rs8$#sFB#f6&WZvmEST%LkDG7tl)x=;1JI;7*sBi~LQ|~AM5?kp7Sb%5 zNb7G|9vJdg%B{*-pB4kIuZK*rAos@cy$owNoj0C8?_sh&^Lv%*1l%FED;hW^XJg^N z>{6J-@&T((d%$a}Zqx3*NCV`TJ?aNdfPL(=mnP2EiNR1s19yw`1j+^L9?|p8u8|Kn zLed;i0vjkodrh@zTUxtD(N@BPE3C8IpFiP&Ke$I_j=EjP zT8NJUB5Vfehv1f79xsq%T|Y4tl(L#32X(VOj(4QL^g>7Ap(20=c4w|`1t~O$h?xXN z2U1DD#bKk+b2p2v;_>tJQ@&K1Jucqq28s^OJ+vXuGL$yfD=nhIC4LK9=ln3b_w;Ba z_kZ(e>>J-#6nf9)o;S^$PfxZH465G_$G=#l+J@yZZgAV_5Rl(Z{WQx|c_mCwNp1#!FNj4ZZyu!KAqV_YXrL9s&)Az{md{7j zZ5rlZ!;J)UT@~ow_?Z{^X9Ly0djEgm{Pc4dFDyRTk(i)Cz|LtuEwJ>pSv0=2P+c^e z9xb^;0GFYk@b^%)gXzCv@2QPgf=uNJk7W2W?zfur(M%qc(=BwL=rgsxw|L7S?xkK^eR9DpjyksXiYLgsU~E8_4mEy(FtYm=Y2(10>o zjE}M|Bm4W!dQndybK(+GB9O&t(KNIdD9&tuP?+2V3{dN#fE8?_2Y&{-wc}9K&b-j` zJ+sMJ!$ua6w|ulPcT7EjJx(LBKQU~=9G+FiJd5VA?ww~PFXT2_OIqqX=tCHEJ0A?! zL?2@Pg#q+uF7C9~gdH%KEdX!)n5?S+;LuMsr25-f3e^bcs)_N*dc?2J1syU~Oab%T zPp!IBU&&w&d=UkF4w>)a{v9Ms3#8gLnfw?fSyHbSpYF>rjvtN}%1{YJbkr9hW|o#= zmmpA;mk)B-J|Ri~7SAKdHrAi*tQ|lPlonn)IIZ?VA%Io_dkY|O-d4yu!5^i$`^M_f zj>y8wBhi)>>|Yc!A6^X2vz$=!6o^7N)UXTT zY`p#55B>Mbq3Ywpk6#&z7n=oJYATT{({o*}>t^ooHudSfNuLP71KuQVVEsHDv1s2j z^4#x4cG8HUSW@faV~YKO69mbbyA$h#@gDa^>R}rb#`z}-a^>UoSAISKBGs68h{s}+Y^z$nYdDKcIcjyG>#^%e(qR8dhBk}9dh{?KO6Zwl> z^MeF*@Cb^qJ7NB5jq)Fu@aRHMCZ0q)+x6GHhqlBW7kFlq9k`DzD%MjLTJw_`uZnV- z6yIy1ylwK1xJeJRcb_Y(VOW{AUV|sF^;%w^9wD`<+PNVh@$$Py{L}9>u8^n$nHk|I zL+6i(58-MOg7e3s^WAIiU%iSz%EYPXK&zBdv;&#QF>c`tbg7`C4bwgm7st4dre5#TYp=U~WKkslm-FWdap$e}hMFnIEZLxuG zZ~A10?2Be@UX9S36=wi2(Z~pYTENx~vS8R)51Cx2A&J(l>37%3glJFbl#f+hbkZ+( zcQ#q_n0uv0U>vg{uL=|W9ALXGE!9}(&nemE07{fh@qM}M&GeW5dEA@7|K`{>J7IGa zUi6e;usZFcpr=Lmes*~j^Omc+&Pn@6PEy4znqbXHw+u6HL5!vHMJEQBTk z41sC^4^iPYBQBsQZFY#Q5q2$ZwnOg&KEQxDy2alKF@GO#;r?E#R0sUq!BJIb?At3| zK2Oz0)szP>LC@dj*`!4hfXGIJL3MJ^)}(m`_h(2w%~eK8J*B6s<2*w@h=lb;%1E9g zxo_@|d7cKTHh6zoP5+ZkRX;PkN?ln*J-*l4nhag}+2F3NRTcEgy$_&KE4<#<`wmi7 zJ5(osx^xcbdv?4FH45072#7mYHiZWel(_c7QHOnpZ?9yeonKb9~jSGd#4h#0b!cqsRF${r$zG#zAk7V;KRU8kpc&ls`yI>@~<2r-7v%Nf|Q~KT4 zIqBa6}^rmu@XZkFaVDC1#w?lV$ zjR5??4XoC3Do)eFggSsD>hP9g!IGt3ifBL(i4!>N=KJik`>2L=G?FI-wyPw|O=I0* zz#0;0Aa)GJjKtCeMHK1u&ri()f zHUb+463ph(`&HKzFl?m7#{)zgL2D<0bKt|?)NyZ;Uu%&)21G%ji!mDj`lAPYO8piR z(77>GB4n5AT|ZQ_<+}LA0xx*ry1Q`k+O?^TJj0blYeh37xi(H-2WGHRQnX9XZ`_ftOa$acG zp?-nsJxXcVbK+u(sUXuXD4udc0)?!3ek!*BpD z((i5Ho8}#=F7PC?yK!q)q~>y9u3IZ<7&l@uiZX<1KvldnYblD!uflJrLfQSP1$>^g zos}hR(mkRxZ7p<=fCf%SR}c{h0L)))I;sJ-p6xcv^;%b77y8_L*N-!Kr^9XBLwlAN zY3|E5B&>SLvXK>;NZ?#k`WD|}=W(M>in#bxC(PxTsRjPD01~{dHI}NW;yilCf$>V{ z6($-f*t`5ZW-DdHIM0XL={q(0#RwaY@Q zeyWrvtCrwPEdZ#T_Y-g3)@^x%ua;xaN~++M?5>9lXyaZLhPkLVj7_!CI>jX)`!#$A zeU`b+;-z03(Naz91K&^~dlc8IhCJeb4nYNpQi|JbOjEAxBFZsfxSwwCCIC3wQ6r%(0HKts{vXulYCwxT=n^v47 z;SkrLLF!8~H9PfL%OPxDVw_b;RGg_EN<2x}RO7sJV>+5T*JNO1P4hZh1;K42RWEM0 zplgC`N@RVESG_xEJM&RYk}z}y?Dqm40AK!Kk7&5v=0!I?q0&@YL1}joD2YT7hVHo9 zy6-nHd*6h47#B-|DQGIF*yYV>psz-{UrIH z=2$D)Xl6-${1DWv&Q5a#qtT_>RerskPP#=o+_UXq(-+na-!e zCvAs>yiW}3n;gBlN9u2-%fg!o*Cr)#oF`>Uq8n&x%e;7$FxKpCUWA^2AS~TP+|g4* zhDEbC?bW??48-yhZnU7?DNlZVRD8S2WrK)MyJ&~r2W(q>>}nBU4g8z8*5g8}+phoG0Hz*XTcwU3zKCB{|k3eOUH_Svw=-O}EgsCj|74-79mI9OnXB=P0a=*h*1+;m3(ahF`)eY4a*?25F7G zzQrdHsgScW=Y-*>IDGw$7Xx*o{2-Egy*6cD(IhBA`O0IWH18a077A%!ILz_kP{reY zCNhJ$^;&O-D#GgEvB2vdnFAoQl&{Te!EGq^)){D93hqbb(m-%fqBvoEyq&F5&0_3% zd}>^laIe)gLe+~n3(yeN1qQy(Z*G)HR^u-RmR_7#zi*EEb_@MfVdRVT0OtC96D7pq zxSe0}Nqntbp_#ywxQka@B>l61 z%zt1dLNYTsNG&7JvDvPOOP3;iHo50?N3_PVdeIU*1R zkaMM~H!QTE^@CN$3&_7ECV;u)L3BEbk7$LO@(1z6SkW2wHuS5*6!wv>ISYvR!c>^M zS!n0UrMAPJ_#>^kTTHGkrxv)MN>IwCh|KHk$_Uh{1peG?Dc^HY)WhH~CA~KD{T0XNNM~mE%vCu3Z@a z<-@1`^3@CdkA^kDVH}PrAJCBMhKqt8r8uEj;MIR8-Zy=_c?wIYVO+4P5|&cxw%F!eR=&Dv-1qs51b!{lq;HzSYQT2`bm_7K+(p;-@LBvGp)PJdiuEw>F(&Ga}}|tsdP! z1uLo?9&*#V(@)?b<`|`xeO-woOedVbWeQcV>C>9Gc3rc-k>SdA;L3Tu3ub)9QpB0@ z$|z~i*mXu-F?AV6CnR~9XT!UvL97uS4avKa)+@$-Sjiy|HmPH)j>liWY+m==7;1t$ zqeZdqKswq(jUX-as=QM8&8*sar)JbF^hiT_^^k*grmeOPKD-@q>c{RDRrD5H3Y4h6f3o z3s@M#&jR7QhTMQB2OFaeX90k9$}V({oGA=TEM*ReOs0{@L{n$UM9UXuq_s=pXvt9oOC7H&>N; zeo<5%q=|*~?zvIAX4Q zJ@TzKT{P9+s>`>65=nB-ZxiUR4^0{v+UdhoyLaDQpmThoA-;qZTWu(7Ca6$1x-$>> zvQVL{-IkMF3#tNNok)onZ*DhsAGp}~^3zb`HW5tid=Ah@ozAsdZ!?jQ$M`9@!sEmYAmkcpHa-+$7WwdmtrJU{Vo!u0%lg@03aZC!= z=w_qPI_-lh+exX)U|a0xt6pd>B?6lMTL5^SIrwNunjIayEtlFBg)S8-g?9$f9hllhg(2*af}HtUO4_d`bg9 zhV8&D=j*$;>Wa!QJ9i1L_GA(jIuOfj&cU4LE`BR6#4=i{xaL)?tJ;x&Ba?=&lW4y-sF( z+PcG6A!jwcO^YHW0-l|74)&4ww@Dt#NVTM&2;nap99=zvJ0I2Ie{(Z0;_iNBsNa!# zb!#7{dJjcvQTsf$SO4ps1EHAy=QN-FYCubF=6Q&+B5B?Y7ck+glLDvLBv%aAp!3LOnlCegnmqB~wn1mguQb@;NbxUrZ zTTAE^dy6s(QPc#2aYc-E{;GKo3h!-<(#R{>;B}!UiZ!=nX1Q8LY9JpkPE2IeXHM87 z+e+tqy42@T8_~MSxMT7%kJW|Y&LbZg27_BiX@XZa*16lHg(^MNvq|LjHX{5z44-m{ z(58nx$DVU7=0k_L=Jg`#E>uwW?>o^o0N`#{}W``Hq!S;w8C z?;!c_ph${{QwO~rfIn%x!zb?^kVbq7dN&P5{R>(>zQ->(w94%uX`3X12*W0FyR4Qc2CYVrgw|N;^y03gqSPT; z;9nh4dO!j`B+KT5~Gr;OKtZvW`XDFECi&siushRFx!E^?xEkIAM-*{6w48 zw^S7()Xp!FUnZXs={ATz*D7_n{g|?hd1Iu!vY2s+btMsjQ7?w1s-ykvGcBp`6vfmN zHydd%YS_8J)#F-M9c0l=XM?Lt&_3NMJ0kN?&y-iVSzOC#4`&J@iomZ+M^{7a+B$h& zQshbBz{rg*O+0GVqiKu2a+$=f3wij)Lk zp`oH;3{&Rixbt^%!)i7St3HK^J57PFuE8rq{J^5)-h!{bdf1`x54JUji)L7S%0ANW zLn*A>vV)M7oJ$V1ue0e-CSulfj)BQ%j#OIF}c)-Eyt(EXHW+<+AQ&zL!6zfb?Ikv8ZP#G)T6J$67IdP|=HkXM5A%@4lrp zx12^`>~VLb@JQd)mf-XjO+N2JL70lOWgMBp^;J{7^+J!^Icw{bmz}ObJW9x|1{DjCb$?$UA-PmBZbd1M}u8G)rg z9_}F3K?m>Z*|%K18xgDUbT|tjv2rlv-%f&T!DcVYt9M+;vq&SBF!qK8P? zoB#lZ%UZsJcIQ(MyNZT`K?ndLpbas`dXQm{$e}HT$R-S${d9-BJl$KY39Xev1*m`n zU~@q15m_L~4_LYbN*x}-n*byL5YRC910W=yz}ry@7_I@JnmO%ghp92>t9Qf(N zp+`v7lSLps{pVjv(UgvMR~@`A@VJdd_KP;`zf{x3`K{EvODINimKz!V;X_terFFR$ z8Tl*~Azik-o7;%T^WSLHljC%+&*GI$NHctbD<6p-QI^Otv=m)ZqQ%n%9fzm93I3D{ zkIQj{&*0NY-ovj;Q&b60ul$N9)*=z@I7qmXwl?0t6%1OGlmc>QG{5A`(t(_rg-J!2 zfbW|DjoT=I4xIu?f@2%t#sPYpp2N+!E%^G^5e(?$e zxe75}s6iRGHk~tGt4&-x&W^DmJQ$X|dyh5$Wh?falsl@=X0?fge^b(qKWP8Glatcc zt6g(Rvr+lXXz5h~92t-ajb!q!AreQE%Ns-ua?VO4;VDC#AZ!?iRY>GenUzM2mY;J& z?65Hxc&pR9NFMA!ECV+)~pwhgC@XK(EVMoy!?^W(cAUE4kWj`lNMd*U59^Elm| z(jjsnS0A(`f=JbPP+^<6i-l|sQ z`@*?;27K#LA-f~c7og0=mNRQPE)o2qu_F8x11^x7?@eJr?!{s0MkH0v2_CsSfR-DK zJUu;BkRCH!m5U)J_WkxoF*hQzmCbk-OM_qmiovLR67mUl7B<&QgLoqzHv@2#J|<#m zW<9iK5?z?s=iy%OrCXti2mGWSY88WpLt8eN6}U`^8XF4o8A*}zFBcRl35oA~osHK- z_D2-Te4P0z-_zv6k_GZOnSW=7GH=t}x2BVS{e?c6@KPBa1$tbk*Q9(tx?X3H)+i`@ z_2ZEV)K@7wsBf+G)49K9r`q~64`Q4e=XbU zqNhE!%D1A`PA!mm+Efwl1fHd72YE~^G%*dJc)tm~2lU?vMd_V{>rgCm(oATbtS^%0 z{d6u*bjmDKhz5lcJf>`G9wL``r4(%91GW)wt3we1I&pA{0ad9hru?%3&ou1x$mIs zuv@1~#YTWGM@Ssgew!LTaWS&9Rj)M8{k)Q@!nq2-q3KJ#)Ds)#m)%q0u{Clag~ecX z(qPXs3fFCoc>t{WH%Y!93CaJ)>)+y8#1~vmd|OLYgo5bR*WDcJ>Yi%JEwVApb~hNB6{qI%h#tPcIEXE*?@;Q#h1YLcFC03z6RpX6k{#tyCS#el`k9S#9zipBxZ zCehP93*1n29fE;hXS{s7#ITcZ++b6@*x||*Sc3$mF|8xA`y*|qH>MeE8!qna1@_5pJl`{NKqr(57#Q*tg!R(ygT4jWjtAy+& z6TX$2d7O16U;!e8^Q?qVIANR5v}7o6JS!5FhMU`i`8FjAf~wor)?u8@%`B&If~?gjaJl!-X&9OMw_T&c!8U+{uxQ zCt{7)84gu(ktPh6!WYwGh?T(|VND$Vokl4q&1+7RK?h6A3xpR~t_>0p0rG>5R28L- zA5%57s&{(6Z71#&`$-E7zT!1jPf~AqtZ~szE-A|Yt!U7N^MD}A zIuW@VKCVT)gfdON6py_^a^rgeusQVbLN|cIslBw{v$zafn_OzZY+CX-=&oO=OX;5n z%|l)7TZ>QbEAD?nRB)waWa(NB^5{ece3@E!dB0xebn)qH*wzIh90vf?HB?|BX~a`o zlnh>4X6^edds?o3@(DXkH1{n<<;B<8DJ#l6Cv$sxq@rM{{3jm_Af)~4x$8e|`~R&d zfU{_g-i9?aH~6BNi8p9VYw%hIQKL^;B#xc> zc-;8ncpqgL1pH~>BJ>5MCIx;$U$!o4T4y9)B0Ry#hLyyH@hf@W za)}2xbCr>)I!<3d@J%#8I4T5jc}w5~>&ZQLBFwzvc2)V0Jt|F%ELb*Gp;-nD(x?5V z&kctjLe~mC@B#h2D|4GB!C%w81#Fxa7)G6G`>H=SL~aJg&ES0ka=i{uOuvIln?;Q- zELY~!73jNf=<*iLheKHDjKs+WKOW+jcy;El8jB~FZ{WTj4{5wKd#h|(jJpilyH9aiiH*Bt-oZ9}sXbnkFkvA(u z-%$F~8P)BlE5kJ9B&EI3KOuRmP^wns*$Djc0~P}R$ON3Ix_R%6!AROFFr4j-A*T;u zlYe5!{i`l$Qiiqq2B%Bq`0}{E5+>+FjTSMigq7)4R9GqJ#%y`PKk#4ORSn!xjOOcL zS+(}2B3n2$@p78;P|!HM5OSF0V-Sd3&emjN`zY_GhDTDa3LtRkcGCypZ?M+-@I6V;buY>^l044D6AbKOqaOT<@k82$#8*bm9cu@h7)$hqF=~>Bw3;@*@ zpf(Ukbfg*g(aMbhL)ebcmXa{@mKqQ4HoVtr@?xM@j3STDPG+_owEnxv@TNIRMn(Rh zXF`6AU$0*-*phcx%ICB74Qcc9n4+8OfOd==5Q$#s_YJhZ-MR3w~_cbJWoL|c}>%hTuSmV}Ps|2#r9 zKT|#box@9iQ;1|hz@{5xf=J!{8nti@#ru{!Jf%(|{^K8+Ik7CM(PR0$&aRFeX<;N``r^ z>vxbzP4N63PX9-AwwLD5X+}-sQF!M=&7z2C>DJtCg>rSUfUQ9b%IU)O3<%HMF(N*TdtzJ z*Pvin<-a3{+gUO7R4PbK2K=ZUc%>=w7H2yA1o zqocP#USru7GPBxv15;TpqHA_N%{O?#lqk#ZCZtU8<(kBriM(D4&RuMKJSDZ z?b^?4)uD=tiv}RHa~i`B6AxM>Db9yhe%l2A?+cq=1gG)vneQNf9bH*RSGRaxmje^; zT+qcTmy=HMZ5b*LSp@ism6zCX{Z)8_ycAE;RVP=E!Hb4E^j!W6BiQ4OP65kV(FqU! zB0xlBmbE@aGe&ttU!%PK%8?2emv2cdWZmtAvEBsQh6UA*?!O1O(NcbV)!^JQ_if|W zUDj}mBlz1>RmuIe;RN_V0Pl1A!gV9&F(#d{ia?@@(Vi3y9@Z!69Ba+=C&W@Rl2dx| z9f<()1}F`YuS>J|TkDSz9$S=Y-3z@>Ze!o|L`HHYLT_r!L!iL;E1IfJnxT4RWn5_U z2A-kFemogxD1ENfku7BPf~3|QT2tZ(IWypw)L{n@_6~1M&V36upx?ro66c~zCT^VJ zHr7Kwb#$Q$C@v4P-`jM*SEj7E7025xnD5uh2O(JAhX-C8#Aot%TDA4!)N4l!5I{}P z`HvZFwx1@{*Noy1^bnKK)v(nPzoY2yMTzQ-%U2alp=+hC!^~cd?D^!-yy@{}ao-f< z9Vs@xW8?!!6_3TYA7D9A#)09m+{uoiDLL|U9O>sx#2ApOPbV5Q0T>BTo@ZXrs6bYQ zfJ^sm?wchlJK8iVJKHusGBpXmZ33v$(o_L7E#bKA4!H@Urwm_faHKHNl*u3qg>i3UbTF zh=_Fi;rJG>((P4Bg;^0*kip%PuZ~%+bL|g)R4Nt;^$tC=4BRh&DWDA&PRS0Cq z@lp@6j@qoN<; zY|I63=r>0*F+iYgCTfO>Dn4a5T@89;pU)(t4r>9;Vqz=zF!zUO7~Gh|V1wI> zx}!YwR(H_Hc@q};m&C;4>(+^A>kLS=G5X=d1ccJFTK_G?wI;KOQ|5*DrKFBkQ6o{^ z#Tug?w1;z~FJky-HD3q$#~5U;z=SDj-z_ zr346_P=g@72|R$(LI;r|NRg^Yuc3!t5?ZJUH9+8*^M2pVvqs-ZjaVnba2KXoW}RYkSj%QU7F#-Gy2|9el8jh90`zOsf1DEJlIv9o--*; zxa=yk0sGOwwOoS?frzh~@((J!C>X2#G%%x;7Yd9aQ|_L3WQq9-mI{=V50HyN~53D<~4E9_5A~9 z66P~mkpLs{G?n30v$RubBRa(`HT#`B;q1;*DN)s5fJj#{XSDOpfGW^=sf@MCV>08r?1Asn zH^UZqP*O`tNX1d4U~{N-E^Nc1KD3CkJA0#D1iEtagWOPuKpewq0WxCqbEybMwE8e&$xCzQ=Eft;t zEU!ruO&!w7>}~My_ZT-E>pSkZ`}_FuTJ29tb#i)d&Ql9_&zT->=Pnq}7tp-f+{Fzyu$fGlkY)PrS2RCn zwapAO6K=9~2)Hr2tfC4|gF&02XT60Bt@R1x)_QK9ft{6IjTc@%A1mZ1-y2w`K(WaPp7P`P2Nnn>XMWn(J%Avr`RjJQkQeA2+wAc9`zL8L zE^dWzo~0wr39Bx9R;mgHo9Rbp%L$}$aivQhp@6CT`hm`(Ao)*F)q;+>9#E&0_Z0tx zM5oq+)c^To z7+&^GkwTu^hyHY;gz+uStxO|on?1YtJD-n~qt~{FG#u`E58_ z_+#Rg+QiZ_7>AJ0R7BW-7|$J6U&&R&#d@q31NjlEF^y-Kzd!wRIg7M=+MOQ$gmES9 zN%KWBpj7)19WWbOMe_8PNa{vf`KZCOYmUSl&(+?sn>t*oE{<-VJ~bpl)=s-dXstSq zDSYo8?oSAP`Bih`j~#wWO!~5l6=hNdDY%$qjA&CO(tKW#3ktNYl1jWI=I`p0;a)(H zb-}Or+%~R?FegTCHp17B&6=%!?D9jdCUmWZ_%m731R6hI+VB^jnUKVL@-&@?!MG5s z<8NzH^t^kNSFZrKiy z1qDhI(E_^NJk360zl%IaN^H7hU1ivS%4=gA6y@@DnMmzC%QK_cD$|%v$O{pEO^UB- zKB4ou)Dml0o71gZ8a2nrHFHfy;ri0zQN7a{7j8Zh%o&+)EjJxlEEQjjuk5lFWC&Ip zqIr=BS;7PihAGGswjT$#e8Qrb5PmC%DGucfs+_>?t4pmwSAClJW(WunmNEa|qTMSR0cHCBF#>^9xAn-f*`7(-%lZ3zreN^QJx=8kbLG6+8kuL|$B zii2GYE1FrbZf5&PWgn=A0X9(o>_h@FL}lpQ=D0$O4zdy=fYa9YzJ2 zJ)`AExNOu(l_qSTI4(v}%x+i76jz#2DWDj6iO~~(2)I$9*BbN%=2IuWYz{K2&$h*3 z-$KNXoZd!#A3IL$oKK0Xb@MrV>8Fr4=bMa00x5G>8v1t+_~Wmn+O0E>(OH@acfX19 zcz$lZRkmmX6(ZO0Z4P?caM?YV7H;(Q!er+g*36dXLVYkBR9gAFEMH(z%0#k$6iiZ5=IB451I5=B*sC^}ge6n7AL?ox600-F|d{uZ`E@e2O2~ z_xR{gB!JM8IV4%6)vQl2owgYX>NQvwetSXS-iy!jrQhdIDvUHp&e(d$beD=5M-TTK z%WH^%arzqz?=E_OxvVG)`KI|Ev}$ilRtBJo+dAb#*ytv_{g1_t#HEBg95BkNN_}9f zHfu(o@5)2y8$j6m>?};Qy1x!@WIGMypO%`ZnMBn&$gmb;Hy;e=5(9%i(v=hN4tF{r zDVO*xc|T8lX}u+nq;>SnYobN2d)7AuU@@ir6(86(gpveF0`}a@9oWJ;?UrOBn;m`kT`?X8tp9S#0yn=(4e=QfG zM|OLpo05!^(u$mf3$Zu2bqhxYW*ySgvh{DESWkFr3+OL2pXa3QdkDrpeEt*~h1yc9 z&^p9}Pa+Ms{{%53KIsgRF(e;Deq;T*Mfe-1Lc%TrBKk8+%H@q2u5g&!4yN>8z(9 zghMl!2!@rv7YPorFF(5Lnrj+<_w3gLU))uy2LcXYLC6rr8l%1+=`oh-lh;RlxI3<& z_Ne=lSMJKV4Uk^8VD8GvNw}qdsITV!5z%BwYAZ%qJ|v#Q*SOYaKem_Z5K{dkdV_NE zi@O3%AGkQ-aE%`|sBpT8q_BlLZX_GeR> z%iL{XE|2^QMI$Wz+qx@xr17I>2OBZ<1vU4aiX=WhwTLs0y(&tFKwz$78Y^#Q$o_lWZ z@(bA`N3wHOuGN3RHd|`W(A3zXfZ$kl*>xSjGHID+Pw0rpCt1bT>W;Ws5sP@;BlTgI zVZV!>g_;3uXi5P$T*b4Ilgl=SiBXbMa!}^Hpu(Mmt;@>K?b#P~Qof|-oqy-)#vhgI zr`S*(iNvx5dW+^qLJfyw2bNo}TzGE*|09;7^CMTJ9_bY}8O?$ap}ngUqUysLd3r%R z-_7`ipW-cQs4<2T$F>^|j~*$rGJL|Gy16HIYTDzTjlT2zJh27jsUJ-CnS(Q#)aQm5 z-gR{duWPA@sXX)pe9MYs>qOP7>$Rc`HTJ`I5IY=WcHBU~rgjNa*Eyd+bJAd8!JA|aXgb~ zACJ`#Y@MO!!?^B@T-cQq;;l3=m7d|A+af$6Mv(zyZXMI70KB8#ly;Tanurx@a!PUm z>kLMOeX8N^h^JI26U9glk|j_^bp+v{4D9);>V|qMoJd&mg$Ar22xm`^Q(~$6rONzk zg%)U)o%*W|8krZ$WBwqc{_MwVl+i@Xz)i{OSfgi8&!t3+XcN$(KLStsjVYq*P1c8W zA0_Kljv)7drEhx(NFxVu{U5in$U|ztO;wf54-o{)%VB_2^63cjRS(ce)LK&AGoJao zOSQXZd)&6Lg0&5*2E7g%Zf0Z7Nc7`_{^LYx@-C27_;`q)!D#He!EF(W78ho~I{y;> znX0OrtED$C2X-%q|D2aL)YT<1C2j z8~*n5yG2(8t(NXU1B4WYdqh}WEknM($31n`pi^YDck?~xPAgcU51fzi`pdMA0GQTo z0H$?Pib~JV@;qFIHIdH*=;9rWzf4hR!oIbEh_ucOqKn2p8Nf#w{g)S?CW*DtaV{t^*ncm zY!k2>ha=sZ#C8?$Iw*)vu~*CZ$sR;}Xr5$-jeLk{sZ46#Q>z)-;DFyiyumMKfo`{P zdTu#>2bc7layS=x-yQVj#7`^2FWi+AaOi-%-wU~beaYhJ*kS%oQyc>**FTb~Oo{H1 zg>~X{KKHB{kd{|7+z}(ILVhcS1sPwLyYNHXz~fcHw7_l|uAr7@!!1TAE=6*!@5SXR zuBT;j@=3iKrJl@+i0ni{D!RG=)fWR<@C&h@_z1}#$o#T{I{s0vLM^V?3q%Dj0(l)X z;d~*)-U@TCxq~?E+WwvMt7obc4tqN+;gUgaTx1XxeTm|V5j@0w-15h|vxynQC?X8@ zj9Fd{S0&b-JbL4x|DBkM^JaSokP7fkdur;gxuxP%*MWmFhdTdkYC#s@gV?7Zygb7o znat(hltX?7$Q4c-rgYFAe;D*el_j>GlhJv1wr%dfb3Yt8{|JLz<8k~GlsWEqb+E!m zv{~+=jo#xcBgt}=Tv?ap{GT@Hv8~YCgg1Hag=2*UOqN+Lpv^hnD@RF1KJ`28N6np8 z0g$Q3FzlJCCOgQ?143&2VnXRd{_5BRo%e8`Hfvc{S)M=(((RV220GGN$-ShHdlQi_ zieAJj$A^?%pH%fe1KjXFT=x-eK-=OYAg@sy;AsIj*SKXC#fgFTF3UClr0MUCCRuZ{m(*(5WB}dsm zH7yl2w019nolN&pyk;WeN!X&7Y0cNt+>trzp+V0!ZpfCtCG}9SY$}?&NH$aPdIko$@O>wwTc$6)SxwsE31)9;{W2FI zi3z#s+F|}7Zr!c){fVg<7d5N>F<1xl5wx2B&uhXzIHD~7r=S^shkN{2`p*0+A^Lxu zR{z${{W-XT4%XJd1ZPLw*}SV>YBgAHdsTds5*CDy!9T4tniYaFlWr)UTDkwM2&W8p z|8iB9(cJBJUlcXka}`KkmmPv|u3+4f&X6H|3?$V3kS6Y|J@2AsAE}y4_?R?Ll&Pcy zih4CP&!(%0RCc&>q+@)uGW$n@x8s6{CcUN?ZZ)kl478Q}EzonLevgCaA}NXXu0~nB z#WUu1;h_vqp$BUG{!UIXb{|oFK!{>Re~Ih-GdUA7ySGT0#2thAGkj-Ev~=2K*OW@& zxgmWIET}WkXZ+>?;^Mp2%=w}svUG{{;V?NVaIx;h?zpogahp!xYCTBcXhe&ABh^c{ zysTeA8N2N>*Ttd|HZHFn`|#8L(-}n&uHLgAU_7Dz;ocfmM5pP37CO|PxE0^Np!}D? zwD*NQ(sSh_awXxL`o?L@M9SbO^{3(;Hg|8I;!rrA!>9Sc`mO=oWa6A#ZPBE4DFOvJ zbdAWld=!9ly)*i-w?ltjU}rUAX|=~}$d_l;ElqH!qJ)|hDv?!yTd&+U^2j%!-wj98 zc0hGK)=fk2gIbIcxK$OHk)X{uwP3wJy4>Ny`F{wdEcERu#6^$PUkw9oe}pjL?FjP-4N-fh z=08EUM{W>j$3YJ^e3W=v>UPin?Y1at>GesPF_6m5Ch;uR5{^ab_pW7Ml;IZ{H7?yL z(FQUv&toIx^rKF$SQ&DMyGkU5c--98y3R_SsegK-_jYv3K9}OB>5L$G1iwGySw@=+ zj4s+#pxibXoMu3s^MXK`(?&i8{Ntu>ANU`+#{NsmG@>(0;LWZ?tW1=Y+j4rGnIa;u z6>^!VAF(t*mgT?c)~P;ws7*;$En2CmYGt)u+vFCq8hyn`fGtx;we!<8@hZtehPS~@ z9=XZbGwX{5s>#-DH?^E@jFjMbSP(TQTR3&Mpx(ZictuAgo=3acH`8ZhP(_HU0N?8! zVE+xl;bdusQ;cczddva&h>4b16GY@It2JJMK=kQzphFJ+A>DcIpgKw*4zEJk5NG5y z_OQ*4gPPzKhJ0J+RSXT5G&*X%qVEur1lq4}8q%p&>Q#YMYz59Vi?VUCPL)R_tTlss zg!iMpEowy4w%a=>KabCD4N>g+s@zVyPATMa`Ir__TutO#?D|n-5}6XPzHh@cg`O&g z-yx<|&uK9>T6%c`ro|pj79xO8!&4@LDY{JeR*-HX#pA})uIcm_`yiY! z->U?=H!mEqd1f?dIBj<&-lavVa9L=Ku`8#0J^e^mZ+|2e9~xs*R?+QHobJC|g9W zg(LrPb2gk*v8ecZuGXD(dkck5CtKlB)a#F%OfL`a!idi9#Wfv{l6B{49LiEV7Sizn z2S@rj0DXa)4kjVb&xU($C|fjO5@#u&>&1FpySz700} z-v;!}6z#oJo%%AHBgOqnoSOk;v1t~91}Zph*;um9i8tkH-^7PxnU0hF5}SF6&471} zgmJU8rZ%l=w3`zz>cY5k1;0}QHX9k6)AcHV-GB@Ic|;klCzpCNM8s>kC`-J>62=n8 z_yLW+3|>^&X?xM*EauHSQY4{a*5uZ3Jxci0q3Q?oBi7sYm!IFZ-0;tmS&bSiF$R{Q zReci7!z&wMqt0dfj1~H!dZ= zwpqJLx*Ow1kBJ&RInDYEkb>k_p-rD&_KtF1Xq>-5(%1Muj}=n|NHf`m8Pxe?i@LGc4SovYhF#bY7{uLzP6KX-+e?8ri+5>7 z4Tkvw$sOvPZ$^hr=v$d&?eC6cm@>8&^u=^LsFm~z1%o7A}(dkX`D=&4%wdi#|$u7TZTtD;T2ga?^N z;iKB%o;3c-vxLDr6=AnTt~h=RlN?RDM>u(R>B=)Fq2+2af9B*}8r`u^0#FA}U1&hL zbZyu|;ZPULB>W-hpti;E;TWPzvvRnrDX;R@v6xVvhI}I}bB1eHqpM;|(knryhl}-} zObNcB*eCagZ;qItTz2>pH3>nXIo7e(dq9r%7LANT9H|f7dqVr}TcCn^{$%T;4f+H} zBhyoAKm_IZ)Hb=Sn}f2t#I}my7Hns+=lJYKqu{ieVT||ntlSh^=KlMoE2;UET}aDh zwU+~~=RfHD(S6Xd+2i#}XHX(sn0uzZ^v%oYzNagH$@YG!I05QAT2Z3`7xV>0F~_lP z=YZZ2&LM76z*c|Ftw}~OSDF0D?B}KBH*Wtw$%sJzC*`4JpFRiR*0r2C{wk*;tu${^ z^RPIz@|wNQSgFTZ8PGi8Y;ouRhHeoovptaO?)4Q`3wBpV3bQq4;qhNkjTy=7s5H7^vhg#vJn3wCG(+Kldl-FUUOW_w|2c@P8T~YUbWy z)>}q*3T01UKK$X-{!_4n zZYDwciQp5&IC4gUV!Gd$WgG%5vS<#iqs8d*zh(5LNul<8K6Mx`OI{*Lx literal 0 HcmV?d00001 diff --git a/doc/html-multipage/ar01s02.html b/doc/html-multipage/ar01s02.html new file mode 100644 index 0000000..579c26c --- /dev/null +++ b/doc/html-multipage/ar01s02.html @@ -0,0 +1,19 @@ +ModSecurity Core Rules™
ModSecurity

ModSecurity Core Rules

Overview

ModSecurity is a web application firewall engine that provides + very little protection on its own. In order to become useful, + ModSecurity must be configured with rules. In order to enable users to + take full advantage of ModSecurity out of the box, Breach Security, Inc. + is providing a free certified rule set for ModSecurity 2.x. Unlike + intrusion detection and prevention systems, which rely on signatures + specific to known vulnerabilities, the Core Rules provide generic + protection from unknown vulnerabilities often found in web applications, + which are in most cases custom coded. The Core Rules are heavily + commented to allow it to be used as a step-by-step deployment guide for + ModSecurity. The latest Core Rules can be found at the ModSecurity + website - http://www.modsecurity.org/projects/rules/.

Core Rules Content

In order to provide generic web applications protection, the Core + Rules use the following techniques:

  • HTTP protection - detecting violations of the HTTP protocol + and a locally defined usage policy.

  • Common Web Attacks Protection - detecting common web + application security attack.

  • Automation detection - Detecting bots, crawlers, scanners and + other surface malicious activity.

  • Trojan Protection - Detecting access to Trojans horses.

  • Error Hiding - Disguising error messages sent by the + server.

\ No newline at end of file diff --git a/doc/html-multipage/ar01s10.html b/doc/html-multipage/ar01s10.html new file mode 100644 index 0000000..a6365e9 --- /dev/null +++ b/doc/html-multipage/ar01s10.html @@ -0,0 +1,14 @@ +Macro Expansion
ModSecurity

Macro Expansion

Macros allow for using place holders in rules that will be expanded + out to their values at runtime. Currently only variable expansion is + supported, however more options may be added in future versions of + ModSecurity.

Format:

%{VARIABLE}
+%{COLLECTION.VARIABLE}

Macro expansion can be used in actions such as initcol, setsid, + setuid, setvar, setenv, logdata. Operators that are evaluated at runtime + support expansion and are noted above. Such operators include @beginsWith, + @endsWith, @contains, @within and @streq. You cannot use macro expansion + for operators that are "compiled" such as @pm, @rx, etc. as these + operators have their values fixed at configure time for efficiency.

Some values you may want to expand include: TX, REMOTE_ADDR, USERID, + HIGHEST_SEVERITY, MATCHED_VAR, MATCHED_VAR_NAME, MULTIPART_STRICT_ERROR, + RULE, SESSION, USERID, among others.

\ No newline at end of file diff --git a/doc/html-multipage/ar01s11.html b/doc/html-multipage/ar01s11.html new file mode 100644 index 0000000..28f496c --- /dev/null +++ b/doc/html-multipage/ar01s11.html @@ -0,0 +1,30 @@ +Persistant Storage
ModSecurity

Persistant Storage

At this time it is only possible to have three collections in which + data is stored persistantly (i.e. data available to multiple requests). + These are: IP, SESSION and USER.

Every collection contains several built-in variables that are + available and are read-only unless otherwise specified:

  1. CREATE_TIME - date/time of + the creation of the collection.

  2. IS_NEW - set to 1 if the + collection is new (not yet persisted) otherwise set to 0.

  3. KEY - the value of the + initcol variable (the client's IP address in the example).

  4. LAST_UPDATE_TIME - date/time + of the last update to the collection.

  5. TIMEOUT - date/time in + seconds when the collection will be updated on disk from memory (if no + other updates occur). This variable may be set if you wish to specifiy + an explicit expiration time (default is 3600 seconds).

  6. UPDATE_COUNTER - how many + times the collection has been updated since creation.

  7. UPDATE_RATE - is the average + rate updates per minute since creation.

To create a collection to hold session variables (SESSION) use action setsid. To create a collection to hold user + variables (USER) use action setuid. To create a collection to hold client + address variables (IP) use action + initcol.

Note

ModSecurity implements atomic updates of persistent variables only + for integer variables (counters) at this time. Variables are read from + storage whenever initcol is encountered in the rules + and persisted at the end of request processing. Counters are adjusted by + applying a delta generated by re-reading the persisted data just before + being persisted. This keeps counter data consistent even if the counter + was modified and persisted by another thread/process during the + transaction.

Note

ModSecurity uses a Berkley Database (SDBM) for persistant storage. + This type of database is generally limited to storing a maximum of 1008 + bytes per key. This may be a limitation if you are attempting to store a + considerable amount of data in variables for a single key. Some of this + limitation is planned to be reduced in a future version of + ModSecurity.

\ No newline at end of file diff --git a/doc/html-multipage/ar01s12.html b/doc/html-multipage/ar01s12.html new file mode 100644 index 0000000..b4b0936 --- /dev/null +++ b/doc/html-multipage/ar01s12.html @@ -0,0 +1,45 @@ +Miscellaneous Topics
ModSecurity

Miscellaneous Topics

Impedance Mismatch

Web application firewalls have a difficult job trying to make + sense of data that passes by, without any knowledge of the application + and its business logic. The protection they provide comes from having an + independent layer of security on the outside. Because data validation is + done twice, security can be increased without having to touch the + application. In some cases, however, the fact that everything is done + twice brings problems. Problems can arise in the areas where the + communication protocols are not well specified, or where either the + device or the application do things that are not in the specification. + In such cases it may be possible to design payload that will be + interpreted in one way by one device and in another by the other device. + This problem is better known as Impedance Mismatch. It can be exploited + to evade the security devices.

While we will continue to enhance ModSecurity to deal with various + evasion techniques the problem can only be minimized, but never solved. + With so many different application backend chances are some will always + do something completely unexpected. The only solution is to be aware of + the technologies in the backend when writing rules, adapting the rules + to remove the mismatch. See the next section for some examples.

PHP Peculiarities for ModSecurity Users

When writing rules to protect PHP applications you need to pay + attention to the following facts:

  1. When "register_globals" is set to "On" request parameters + are automatically converted to script variables. In some PHP + versions it is even possible to override the $GLOBALS + array.

  2. Whitespace at the beginning of parameter names is ignored. + (This is very dangerous if you are writing rules to target + specific named variables.)

  3. The remaining whitespace (in parameter names) is converted + to underscores. The same applies to dots and to a "[" if the + variable name does not contain a matching closing bracket. + (Meaning that if you want to exploit a script through a variable + that contains an underscore in the name you can send a parameter + with a whitespace or a dot instead.)

  4. Cookies can be treated as request parameters.

  5. The discussion about variable names applies equally to the + cookie names.

  6. The order in which parameters are taken from the request and + the environment is EGPCS (environment, GET, POST, Cookies, + built-in variables). This means that a POST parameter will + overwrite the parameters transported on the request line (in + QUERY_STRING).

  7. When "magic_quotes_gpc" is set to "On" PHP will use + backslash to escape the following characters: single quote, double + quote, backslash, and the nul byte.

  8. If "magic_quotes_sybase" is set to "On" only the single + quote will be escaped using another single quote. In this case the + "magic_quotes_gpc" setting becomes irrelevant. The + "magic_quotes_sybase" setting completely overrides the + "magic_quotes_gpc" behaviour but "magic_quotes_gpc" still must be + set to "On" for the Sybase-specific quoting to be work.

  9. PHP will also automatically create nested arrays for you. + For example "p[x][y]=1" results in a total of three + variables.

\ No newline at end of file diff --git a/doc/html-multipage/breach-logo-small.gif b/doc/html-multipage/breach-logo-small.gif new file mode 100644 index 0000000000000000000000000000000000000000..d732ac5018a0110c7a1bc11349528f3e1bb966c3 GIT binary patch literal 2389 zcmV-b399x-Nk%w1VPpU#0Qdg@ML|McT3h=4{`dU;_51$D>Gx8+=R7z$h0yK^pxxE) z`E_%1e|&wEl9R^8#i-u%N4VyvrKPT{tSl)i%gV}?*6;+oF*4iR+tSg|>gwuDy5^?c^DVC8a>?wW+wu~m-oCxPP)$x* zR#t4s>uJU6`27CW)z#ke`WU9)U|wG6=;+Su_~hi|go1+I-Q9c4?XTeUGO**y>-cze zcH{K>jEahg(eL2%``PgNZEI_u+VZ;O_O|2o&d$y~wdISknQA*$huh=@S85%O zJw7U};+oj;fPH=pqTVPZC4+&1Nx9}FtKk5h+&DBf{r&y>`}$VAR*S));~Nw{QUem zHaG9@@9p^glaZ0Qw^LA2W@BWBg@)AA(+8m4@A>`N*x0J6sjI1~_4M>? zX=*}0Kr${bV#DcM!048gm4D9d6{X)-zUYtC@RQZ>*w@#jqNCUF`mnFBdUtrh=k|z( zhjVaopq`#PI5+{F+<43EZ^-LTOH6urdC14dt*fla$H;+yfNN-JURzw9o18tG(x>HY3FR$a`;^M%+zbhvwJGA6EH8%D2^_bW3cFOGL_55JM>71IIT31-l z?f4=dAOHXVA^8LW00930EC2ui0Av6p000R80RIUbNU)&6g9sBUT*$DY!-o(fN}Ncs zqC*h*pgarpEENb47DI|W__5?i0R#wKxUlNU5CkW%%#g_i0+k>6R$fYJvgF9021^P6 zu}Z-dDkg%UV1@<)mo!Z*sF_N&s+vJ*xbP@pz(uYiCNlL9HDG{GpcFq6xFl*v5Erq& zq)}nDuHCzJEntC%M&GkB1s3fYigsa1Pog@7GH_x>0=wQKCrD5R%b-Cs1`V^DAajCY z2`og$>rDlhFW^kr_%ZZj;eQ~?+DP%u3tg)!u!#8rAzCvRE)Z0xFy>aLPT4v=qsK*s zieB)nq)L8o+C3=1H$^i*Z%LXNx2;Km;5IY2tpX4#R+AU zw$(R9^w5tCt9;_&YleaF$tt3}(nAWlaFB#8k9ord8u#>bphGBu@q#TXG*JQqDfBbI zCom8OV@M|vAb=2=K!L)02|yFeJwFhj5CJmeB83?0ykOLI~#uF|YYN=raECR*@kY4KPr=W%^ zDq89N)P^d;#Gq;nBD5n%P=BQVs;V&5#B&EpbI7`C48o{l&q0(FL(QuQu|WbHntY%^ z4DGlHLJlL`;2{Y1s4_wviWJjMLG3Iv!31W^W5xk|;84ShYye}%1mc>pOgL|hKuJNf zw6Jct^WUB8%z`w zPr@CXQi}&6Bn&_d1hHXC!g-wHK_dyzL&}Sar#k64S-NgzXW~k&o+$o!H6Y5B<#bl0;%jzBO-_`$2A@J z%YI zjJVkc9a3Ko+XrU&;|!nwc#TcP#T?*|8_KJFK<@(GfsNp@52OeH{){rbLiR-Ak22fH z&HX@egyGK{w>>2%{i&!$SwYHGxR5paurvM#9{Y1Nm*^5Cn3&SbUdM#4Ox3WF%Zi)P>%CpZBBCJc=rlwg5BSn!WF zkij1Z7(o_O$i;%R5D&`OBPWzmkA&IKj0xMu4gTL_(Y2L%;Ez9y zSO^#an+PNf2o4ip?SQcmHdFy&u)~AyXdo?tpm2)|X`v~U2LfLZ@si3k8$nPhHE61> z8&HhiB>VyYfIlFSe4|*%9FVt+7VyChEvRG%#_^vx?2`!|LPQQI_>cQpu3{e$XENuR zum#*;7KexjAdbcav_;b&YshCGfaVXU)y<0m_`@t_ItxV{;y)m;=KR`mgP!^#VdfBJ zANYVcd0-I{zBmOFG$6|sP7R~YgC{}$kg#RYpam_E-`YmtAvREM8QX#l1&$Vua}5L$ z)-wYQ_`p^^n1Tj``$rs@;ExGtfFL#4CjfFF5K3GlVP;^04~RfSf28ASYh(dC|LPA+ zK#v6B@BkgcLD_Kp!Us7(*BkN>fI18W6+j4sDJb9}5+uU|m94A?Ofe3D{Gk;9h=K=a zp#%Ujct9QlIm9jkkqAN*VjhWj2RTgo4@P7G01N0t#We5>07L+Kql&I{r%T=HTKBpU H2?zi?XVITh literal 0 HcmV?d00001 diff --git a/doc/html-multipage/configuration-directives.html b/doc/html-multipage/configuration-directives.html new file mode 100644 index 0000000..affdf93 --- /dev/null +++ b/doc/html-multipage/configuration-directives.html @@ -0,0 +1,637 @@ +Configuration Directives
ModSecurity

Configuration Directives

The following section outlines all of the ModSecurity directives. + Most of the ModSecurity directives can be used inside the various Apache + Scope Directives such as VirtualHost, + Location, LocationMatch, + Directory, etc... There are others, however, that can + only be used once in the main configuration file. This information is + specified in the Scope sections below. The first version to use a given + directive is given in the Version sections below.

These rules, along with the Core rules files, should be contained is + files outside of the httpd.conf file and called up with Apache "Include" + directives. This allows for easier updating/migration of the rules. If you + create your own custom rules that you would like to use with the Core + rules, you should create a file called - + modsecurity_crs_15_customrules.conf and place it in + the same directory as the Core rules files. By using this file name, your + custom rules will be called up after the standard ModSecurity Core rules + configuration file but before the other Core rules. This allows your rules + to be evaluated first which can be useful if you need to implement + specific "allow" rules or to correct any false positives in the Core rules + as they are applied to your site.

Note

It is highly encouraged that you do not edit the Core rules files + themselves but rather place all changes (such as + SecRuleRemoveByID, etc...) in your custom rules file. + This will allow for easier upgrading as newer Core rules are released by + Breach Security on the ModSecurity website.

SecAction

Description: Unconditionally processes the + action list it receives as the first and only parameter. It accepts one + parameter, the syntax of which is identical to the third parameter + of SecRule.

Syntax: SecAction + action1,action2,action3

Example Usage: SecAction + nolog,phase:1,initcol:RESOURCE=%{REQUEST_FILENAME}

Processing Phase: Any

Scope: Any

Version: 2.0.0

Dependencies/Notes: None

SecAction is best used when you unconditionally execute an action. + This is explicit triggering whereas the normal Actions are conditional + based on data inspection of the request/response. This is a useful + directive when you want to run certain actions such as + initcol to initialize collections.

SecArgumentSeparator

Description: Specifies which character to use + as separator for + application/x-www-form-urlencoded content. Defaults to + &. Applications are sometimes + (very rarely) written to use a semicolon (;).

Syntax: SecArgumentSeparator character

Example Usage: SecArgumentSeparator ;

Processing Phase: Any

Scope: Main

Version: 2.0.0

Dependencies/Notes: None

This directive is needed if a backend web application is using a + non-standard argument separator. If this directive is not set properly + for each web application, then ModSecurity will not be able to parse the + arguments appropriately and the effectiveness of the rule matching will + be significantly decreased.

SecAuditEngine

Description: Configures the audit logging + engine.

Syntax: SecAuditEngine On|Off|RelevantOnly

Example Usage: SecAuditEngine On

Processing Phase: N/A

Scope: Any

Version: 2.0.0

Dependencies/Notes: Can be set/changed with + the "ctl" action for the current transaction.

Example: The following example shows the various audit directives + used together.

SecAuditEngine RelevantOnly 
+SecAuditLog logs/audit/audit.log
+SecAuditLogParts ABCFHZ
+SecAuditLogType concurrent
+SecAuditLogStorageDir logs/audit
+SecAuditLogRelevantStatus ^(?:5|4\d[^4])

Possible values are:

  • On - log all transactions + by default.

  • Off - do not log + transactions by default.

  • RelevantOnly - by default + only log transactions that have triggered a warning or an error, or + have a status code that is considered to be relevant (see SecAuditLogRelevantStatus).

SecAuditLog

Description: Defines the path to the main + audit log file.

Syntax: SecAuditLog + /path/to/auditlog

Example Usage: SecAuditLog + /usr/local/apache/logs/audit.log

Processing Phase: N/A

Scope: Any

Version: 2.0.0

Dependencies/Notes: This file is open on + startup when the server typically still runs as + root. You should not allow non-root users to have write + privileges for this file or for the directory it is stored in..

This file will be used to store the audit log entries if serial + audit logging format is used. If concurrent audit logging format is used + this file will be used as an index, and contain a record of all audit + log files created. If you are planning to use Concurrent audit logging + and sending your audit log data off to a remote Console host or + commercial ModSecurity Management Appliance, then you will need to + configure and use the ModSecurity Log Collector (mlogc) and use the + following format for the audit log:

SecAuditLog "|/path/to/mlogc /path/to/mlogc.conf"

SecAuditLog2

Description: Defines the path to the + secondary audit log index file when concurrent logging is enabled. See + SecAuditLog2 for more details.

Syntax: SecAuditLog2 + /path/to/auditlog2

Example Usage: SecAuditLog2 + /usr/local/apache/logs/audit2.log

Processing Phase: N/A

Scope: Any

Version: 2.1.2

Dependencies/Notes: A main audit log must be + defined via SecAuditLog before this + directive may be used. Additionally, this log is only used for + replicating the main audit log index file when concurrent audit logging + is used. It will not be used for non-concurrent + audit logging.

SecAuditLogDirMode

Description: Configures the mode + (permissions) of any directories created for concurrent audit logs using + an octal mode (as used in chmod). See SecAuditLogFileMode for controlling the mode + of audit log files.

Syntax: SecAuditLogDirMode octal_mode|"default"

Example Usage: SecAuditLogDirMode 02750

Processing Phase: N/A

Scope: Any

Version: 2.5.10

Dependencies/Notes: This feature is not + available on operating systems not supporting octal file modes. The + default mode (0600) only grants read/write access to the account writing + the file. If access from another account is needed (using mpm-itk is a + good example), then this directive may be required. However, use this + directive with caution to avoid exposing potentially sensitive data to + unauthorized users. Using the value "default" will revert back to the + default setting.

Note

The process umask may still limit the mode if it is being more + restrictive than the mode set using this directive.

SecAuditLogFileMode

Description: Configures the mode + (permissions) of any files created for concurrent audit logs using an + octal mode (as used in chmod). See SecAuditLogDirMode for controlling the mode of + created audit log directories.

Syntax: SecAuditLogFileMode + octal_mode|"default"

Example Usage: SecAuditLogFileMode 00640

Processing Phase: N/A

Scope: Any

Version: 2.5.10

Dependencies/Notes: This feature is not + available on operating systems not supporting octal file modes. The + default mode (0600) only grants read/write access to the account writing + the file. If access from another account is needed (using mpm-itk is a + good example), then this directive may be required. However, use this + directive with caution to avoid exposing potentially sensitive data to + unauthorized users. Using the value "default" will revert back to the + default setting.

Note

The process umask may still limit the mode if it is being more + restrictive than the mode set using this directive.

SecAuditLogParts

Description: Defines which part of each + transaction are going to be recorded in audit log. Each part is assigned + a single letter. If a letter appears in the list then the equivalent + part of each transactions will be recorded. See below for the list of + all parts.

Syntax: SecAuditLogParts PARTS

Example Usage: SecAuditLogParts ABCFHZ

Processing Phase: N/A

Scope: Any

Version: 2.0.0

Dependencies/Notes: At this time ModSecurity + does not log response bodies of stock Apache responses (e.g. 404), or the Server and Date response headers.

Default: ABCFHZ.

Note

Please refer to the ModSecurity Data Formats document for a + detailed description of every available part.

Available audit log parts:

  • A - audit log header + (mandatory)

  • B - request headers

  • C - request body (present + only if the request body exists and ModSecurity is configured to + intercept it)

  • D - RESERVED for + intermediary response headers, not implemented yet.

  • E - intermediary response + body (present only if ModSecurity is configured to intercept + response bodies, and if the audit log engine is configured to record + it). Intermediary response body is the same as the actual response + body unless ModSecurity intercepts the intermediary response body, + in which case the actual response body will contain the error + message (either the Apache default error message, or the + ErrorDocument page).

  • F - final response headers + (excluding the Date and Server headers, which are always added by + Apache in the late stage of content delivery).

  • G - RESERVED for the actual + response body, not implemented yet.

  • H - audit log + trailer

  • I - This part is a + replacement for part C. It will log the same data as C in all cases + except when multipart/form-data + encoding in used. In this case it will log a fake application/x-www-form-urlencoded body + that contains the information about parameters but not about the + files. This is handy if you don't want to have (often large) files + stored in your audit logs.

  • J - RESERVED. This part, + when implemented, will contain information about the files uploaded + using multipart/form-data encoding.

  • K - This part contains a + full list of every rule that matched (one per line) in the order + they were matched. The rules are fully qualified and will thus show + inherited actions and default operators. Supported as of + v2.5.0

  • Z - final boundary, + signifies the end of the entry (mandatory)

SecAuditLogRelevantStatus

Description: Configures which response status + code is to be considered relevant for the purpose of audit + logging.

Syntax: SecAuditLogRelevantStatus REGEX

Example Usage: SecAuditLogRelevantStatus + ^(?:5|4\d[^4])

Processing Phase: N/A

Scope: Any

Version: 2.0.0

Dependencies/Notes: Must have the + SecAuditEngine set to + RelevantOnly. The parameter is a regular + expression.

The main purpose of this directive is to allow you to configure + audit logging for only transactions that generate the specified HTTP + Response Status Code. This directive is often used to the decrease the + total size of the audit log file. Keep in mind that if this parameter is + used, then successful attacks that result in a 200 OK status code will + not be logged.

SecAuditLogStorageDir

Description: Configures the storage directory + where concurrent audit log entries are to be stored.

Syntax: SecAuditLogStorageDir + /path/to/storage/dir

Example Usage: SecAuditLogStorageDir + /usr/local/apache/logs/audit

Processing Phase: N/A

Scope: Any

Version: 2.0.0

Dependencies/Notes: SecAuditLogType must be + set to Concurrent. The directory must already be created before starting + Apache and it must be writable by the web server user as new files are + generated at runtime.

As with all logging mechanisms, ensure that you specify a file + system location that has adequate disk space and is not on the root + partition.

SecAuditLogType

Description: Configures the type of audit + logging mechanism to be used.

Syntax: SecAuditLogType Serial|Concurrent

Example Usage: SecAuditLogType Serial

Processing Phase: N/A

Scope: Any

Version: 2.0.0

Dependencies/Notes: Must specify + SecAuditLogStorageDir if you use concurrent + logging.

Possible values are:

  1. Serial - all audit log + entries will be stored in the main audit logging file. This is more + convenient for casual use but it is slower as only one audit log + entry can be written to the file at any one file.

  2. Concurrent - audit log + entries will be stored in separate files, one for each transaction. + Concurrent logging is the mode to use if you are going to send the + audit log data off to a remote ModSecurity Console host.

SecCacheTransformations + (Deprecated/Experimental)

Description: Controls caching of + transformations. Caching is off by default starting with 2.5.6, when it + was deprecated and downgraded back to experimental.

Syntax: SecCacheTransformations On|Off + [options]

Example Usage: SecCacheTransformations On + "minlen:64,maxlen:0"

Processing Phase: N/A

Scope: Any

Version: 2.5.0

Dependencies/Notes: N/A

First parameter:

  • On - cache transformations + (per transaction, per phase) allowing identical transformations to + be performed only once. (default)

  • Off - do not cache any + transformations, forcing all transformations to be performed for + each rule executed.

The following options are allowed (comma separated):

  • incremental:on|off - + enabling this option will cache every transformation instead of just + the final transformation. (default: off)

  • maxitems:N - do not allow + more than N transformations to be cached. The cache will then be + disabled. A zero value is interpreted as "unlimited". This option + may be useful to limit caching for a form with a large number of + ARGS. (default: 512)

  • minlen:N - do not cache the + transformation if the value's length is less than N bytes. (default: + 32)

  • maxlen:N - do not cache the + transformation if the value's length is more than N bytes. A zero + value is interpreted as "unlimited". (default: 1024)

SecChrootDir

Description: Configures the directory path + that will be used to jail the web server process.

Syntax: SecChrootDir + /path/to/chroot/dir

Example Usage: SecChrootDir /chroot

Processing Phase: N/A

Scope: Main

Version: 2.0.0

Dependencies/Notes: This feature is not + available on Windows builds. The internal chroot functionality provided + by ModSecurity works great for simple setups. One example of a simple + setup is Apache serving static files only, or running scripts using + modules.builds. Some problems you might encounter with more complex + setups:

  1. DNS lookups do not work (this is because this feature requires + a shared library that is loaded on demand, after chroot takes + place).

  2. You cannot send email from PHP because it uses sendmail and + sendmail is outside the jail.

  3. In some cases Apache graceful (reload) no longer works.

You should be aware that the internal chroot feature might not be + 100% reliable. Due to the large number of default and third-party + modules available for the Apache web server, it is not possible to + verify the internal chroot works reliably with all of them. A module, + working from within Apache, can do things that make it easy to break out + of the jail. In particular, if you are using any of the modules that + fork in the module initialisation phase (e.g. + mod_fastcgi, mod_fcgid, + mod_cgid), you are advised to examine each Apache + process and observe its current working directory, process root, and the + list of open files. Consider what your options are and make your own + decision.

SecComponentSignature

Description: Appends component signature to + the ModSecurity signature.

Syntax: SecComponentSignature + "COMPONENT_NAME/X.Y.Z (COMMENT)"

Example usage: SecComponentSignature + "Core Rules/1.2.3"

Processing Phase: N/A

Scope: Main

Version: 2.5.0

Dependencies/Notes: This directive should be + used to make the presence of significant ModSecurity components known. + The entire signature will be recorded in transaction audit log. It + should be used by ModSecurity module and rule set writers to make + debugging easier.

SecContentInjection

Description: Enables content injection using + actions append and prepend.

Syntax: SecContentInjection + (On|Off)

Example Usage: SecContentInjection + On

Processing Phase: N/A

Scope: Any

Version: 2.5.0

Dependencies/Notes: N/A

SecCookieFormat

Description: Selects the cookie format that + will be used in the current configuration context.

Syntax: SecCookieFormat 0|1

Example Usage: SecCookieFormat 0

Processing Phase: N/A

Scope: Any

Version: 2.0.0

Dependencies/Notes: None

Possible values are:

  • 0 - use version 0 + (Netscape) cookies. This is what most applications use. It is the + default value.

  • 1 - use version 1 + cookies.

SecDataDir

Description: Path where persistent data (e.g. + IP address data, session data, etc) is to be stored.

Syntax: SecDataDir + /path/to/dir

Example Usage: SecDataDir /usr/local/apache/logs/data

Processing Phase: N/A

Scope: Main

Dependencies/Notes: This directive is needed + when initcol, setsid an setuid are used. Must be writable by the web + server user.

SecDebugLog

Description: Path to the ModSecurity debug + log file.

Syntax: SecDebugLog + /path/to/modsec-debug.log

Example Usage: SecDebugLog + /usr/local/apache/logs/modsec-debug.log

Processing Phase: N/A

Scope: Any

Version: 2.0.0

Dependencies/Notes: None

SecDebugLogLevel

Description: Configures the verboseness of + the debug log data.

Syntax: SecDebugLogLevel 0|1|2|3|4|5|6|7|8|9

Example Usage: SecDebugLogLevel 4

Processing Phase: N/A

Scope: Any

Version: 2.0.0

Dependencies/Notes: Levels 1 - 3 are always sent to the Apache error log. + Therefore you can always use level 0 + as the default logging level in production. Level 5 is useful when debugging. It is not + advisable to use higher logging levels in production as excessive + logging can slow down server significantly.

Possible values are:

  • 0 - no logging.

  • 1 - errors (intercepted + requests) only.

  • 2 - warnings.

  • 3 - notices.

  • 4 - details of how + transactions are handled.

  • 5 - as above, but including + information about each piece of information handled.

  • 9 - log everything, + including very detailed debugging information.

SecDefaultAction

Description: Defines the default action to + take on a rule match.

Syntax: SecDefaultAction + action1,action2,action3

Example Usage: SecDefaultAction + log,auditlog,deny,status:403,phase:2

Processing Phase: Any

Scope: Any

Version: 2.0.0

Dependencies/Notes: Rules following a + SecDefaultAction directive will inherit this setting + unless a specific action is specified for an individual rule or until + another SecDefaultAction is specified. Take special + note that in the logging disruptive actions are not allowed, but this + can inadvertently be inherited using a disruptive action in + SecDefaultAction.

The default value is minimal (differing from previous + versions):

SecDefaultAction phase:2,log,auditlog,pass

Note

SecDefaultAction must specify a disruptive + action and a processing phase and cannot contain metadata + actions.

Warning

SecDefaultAction is not + inherited across configuration contexts. (For an example of why this + may be a problem for you, read the following ModSecurity Blog entry + http://blog.modsecurity.org/2008/07/modsecurity-tri.html).

SecGeoLookupDb

Description: Defines the path to the + geographical database file.

Syntax: SecGeoLookupDb /path/to/db

Example Usage: SecGeoLookupDb + /usr/local/geo/data/GeoLiteCity.dat

Processing Phase: N/A

Scope: Any

Version: 2.5.0

Dependencies/Notes: Check out + maxmind.com for free database files.

SecGuardianLog

Description: Configuration directive to use + the httpd-guardian script to monitor for Denial of Service (DoS) + attacks.

Syntax: SecGuardianLog |/path/to/httpd-guardian

Example Usage: SecGuardianLog + |/usr/local/apache/bin/httpd-guardian

Processing Phase: N/A

Scope: Main

Version: 2.0.0

Dependencies/Notes: By default httpd-guardian + will defend against clients that send more than 120 requests in a + minute, or more than 360 requests in five minutes.

Since 1.9, ModSecurity supports a new directive, SecGuardianLog, + that is designed to send all access data to another program using the + piped logging feature. Since Apache is typically deployed in a + multi-process fashion, making information sharing difficult, the idea is + to deploy a single external process to observe all requests in a + stateful manner, providing additional protection.

Development of a state of the art external protection tool will be + a focus of subsequent ModSecurity releases. However, a fully functional + tool is already available as part of the Apache httpd tools + project. The tool is called httpd-guardian and can be used to + defend against Denial of Service attacks. It uses the blacklist tool + (from the same project) to interact with an iptables-based (Linux) or + pf-based (*BSD) firewall, dynamically blacklisting the offending IP + addresses. It can also interact with SnortSam (http://www.snortsam.net). + Assuming httpd-guardian is already configured (look into the source code + for the detailed instructions) you only need to add one line to your + Apache configuration to deploy it:

SecGuardianLog |/path/to/httpd-guardian

SecMarker

Description: Adds a fixed rule marker in the + ruleset to be used as a target in a skipAfter action. + A SecMarker directive essentially creates a rule that + does nothing and whose only purpose it to carry the given ID.

Syntax: SecMarker + ID

Example Usage: SecMarker 9999

Processing Phase: Any

Scope: Any

Version: 2.5.0

Dependencies/Notes: None

SecRule REQUEST_URI "^/$" \
+    "chain,t:none,t:urlDecode,t:lowercase,t:normalisePath,skipAfter:99"
+SecRule REMOTE_ADDR "^127\.0\.0\.1$" "chain"
+SecRule REQUEST_HEADERS:User-Agent \
+    "^Apache \(internal dummy connection\)$" "t:none"  
+SecRule &REQUEST_HEADERS:Host "@eq 0" \
+    "deny,log,status:400,id:08,severity:4,msg:'Missing a Host Header'"
+SecRule &REQUEST_HEADERS:Accept "@eq 0" \
+    "log,deny,log,status:400,id:15,msg:'Request Missing an Accept Header'"
+
+SecMarker 99

SecPdfProtect

Description: Enables the PDF XSS protection + functionality. Once enabled access to PDF files is tracked. Direct + access attempts are redirected to links that contain one-time tokens. + Requests with valid tokens are allowed through unmodified. Requests with + invalid tokens are also allowed through but with forced download of the + PDF files. This implementation uses response headers to detect PDF files + and thus can be used with dynamically generated PDF files that do not + have the .pdf extension in the request URI.

Syntax: SecPdfProtect On|Off

Example Usage: SecPdfProtect On

Processing Phase: N/A

Scope: Any

Version: 2.5.0

Dependencies/Notes: None

SecPdfProtectMethod

Description: Configure desired protection + method to be used when requests for PDF files are detected. Possible + values are TokenRedirection and + ForcedDownload. The token redirection approach will + attempt to redirect with tokens where possible. This allows PDF files to + continue to be opened inline but only works for GET requests. Forced + download always causes PDF files to be delivered as opaque binaries and + attachments. The latter will always be used for non-GET requests. Forced + download is considered to be more secure but may cause usability + problems for users ("This PDF won't open anymore!").

Syntax: SecPdfProtectMethod method

Example Usage: SecPdfProtectMethod TokenRedirection

Processing Phase: N/A

Scope: Any

Version: 2.5.0

Dependencies/Notes: None

Default: + TokenRedirection

SecPdfProtectSecret

Description: Defines the secret that will be + used to construct one-time tokens. You should use a reasonably long + value for the secret (e.g. 16 characters is good). Once selected the + secret should not be changed as it will break the tokens that were sent + prior to change. But it's not a big deal even if you change it. It will + just force download of PDF files with tokens that were issued in the + last few seconds.

Syntax: SecPdfProtectSecret secret

Example Usage: SecPdfProtectSecret + MyRandomSecretString

Processing Phase: N/A

Scope: Any

Version: 2.5.0

Dependencies/Notes: None

SecPdfProtectTimeout

Description: Defines the token timeout. After + token expires it can no longer be used to allow access to PDF file. + Request will be allowed through but the PDF will be delivered as + attachment.

Syntax: SecPdfProtectTimeout timeout

Example Usage: SecPdfProtectTimeout 10

Processing Phase: N/A

Scope: Any

Version: 2.5.0

Dependencies/Notes: None

Default: 10

SecPdfProtectTokenName

Description: Defines the name of the token. + The only reason you would want to change the name of the token is if you + wanted to hide the fact you are running ModSecurity. It's a good reason + but it won't really help as the adversary can look into the algorithm + used for PDF protection and figure it out anyway. It does raise the bar + slightly so go ahead if you want to.

Syntax: SecPdfProtectTokenName name

Example Usage: SecPdfProtectTokenName PDFTOKEN

Processing Phase: N/A

Scope: Any

Version: 2.5.0

Dependencies/Notes: None

Default: PDFTOKEN

SecRequestBodyAccess

Description: Configures whether request + bodies will be buffered and processed by ModSecurity by default.

Syntax: SecRequestBodyAccess On|Off

Example Usage: SecRequestBodyAccess On

Processing Phase: N/A

Scope: Any

Version: 2.0.0

Dependencies/Notes: This directive is + required if you plan to inspect POST_PAYLOAD. This + directive must be used along with the "phase:2" processing phase action + and REQUEST_BODY variable/location. If any of these 3 + parts are not configured, you will not be able to inspect the request + bodies.

Possible values are:

  • On - access request + bodies.

  • Off - do not attempt to + access request bodies.

SecRequestBodyLimit

Description: Configures the maximum request + body size ModSecurity will accept for buffering.

Syntax: SecRequestBodyLimit NUMBER_IN_BYTES

Example Usage: SecRequestBodyLimit 134217728

Scope: Any

Version: 2.0.0

Dependencies/Notes: 131072 KB (134217728 + bytes) is the default setting. Anything over this limit will be rejected + with status code 413 Request Entity Too Large. There is a hard limit of + 1 GB.

SecRequestBodyNoFilesLimit

Description: Configures the maximum request + body size ModSecurity will accept for buffering, excluding the size of + files being transported in the request. This directive comes handy to + further reduce susceptibility to DoS attacks when someone is sending + request bodies of very large sizes. Web applications that require file + uploads must configure SecRequestBodyLimit to a high + value. Since large files are streamed to disk file uploads will not + increase memory consumption. However, it's still possible for someone to + take advantage of a large request body limit and send non-upload + requests with large body sizes. This directive eliminates that + loophole.

Syntax: SecRequestBodyNoFilesLimit + NUMBER_IN_BYTES

Example Usage: SecRequestBodyLimit 131072

Scope: Any

Version: 2.5.0

Dependencies/Notes: 1 MB (1048576 bytes) is + the default setting. This value is very conservative. For most + applications you should be able to reduce it down to 128 KB or lower. + Anything over the limit will be rejected with status code 413 + Request Entity Too Large. There is a hard limit of 1 + GB.

SecRequestBodyInMemoryLimit

Description: Configures the maximum request + body size ModSecurity will store in memory.

Syntax: SecRequestBodyInMemoryLimit + NUMBER_IN_BYTES

Example Usage: SecRequestBodyInMemoryLimit 131072

Processing Phase: N/A

Scope: Any

Version: 2.0.0

Dependencies/Notes: None

By default the limit is 128 KB:

# Store up to 128 KB in memory
+SecRequestBodyInMemoryLimit 131072

SecResponseBodyLimit

Description: Configures the maximum response + body size that will be accepted for buffering.

Syntax: SecResponseBodyLimit NUMBER_IN_BYTES

Example Usage: SecResponseBodyLimit 524228

Processing Phase: N/A

Scope: Any

Version: 2.0.0

Dependencies/Notes: Anything over this limit + will be rejected with status code 500 Internal Server Error. This + setting will not affect the responses with MIME types that are not + marked for buffering. There is a hard limit of 1 GB.

By default this limit is configured to 512 KB:

# Buffer response bodies of up to 512 KB in length 
+SecResponseBodyLimit 524288

SecResponseBodyLimitAction

Description: Controls what happens once a + response body limit, configured with + SecResponseBodyLimit, is encountered. By default + ModSecurity will reject a response body that is longer than specified. + Some web sites, however, will produce very long responses making it + difficult to come up with a reasonable limit. Such sites would have to + raise the limit significantly to function properly defying the purpose + of having the limit in the first place (to control memory consumption). + With the ability to choose what happens once a limit is reached site + administrators can choose to inspect only the first part of the + response, the part that can fit into the desired limit, and let the rest + through. Some could argue that allowing parts of responses to go + uninspected is a weakness. This is true in theory but only applies to + cases where the attacker controls the output (e.g. can make it arbitrary + long). In such cases, however, it is not possible to prevent leakage + anyway. The attacker could compress, obfuscate, or even encrypt data + before it is sent back, and therefore bypass any monitoring + device.

Syntax: SecResponseBodyLimitAction + Reject|ProcessPartial

Example Usage: + SecResponseBodyLimitAction ProcessPartial

Processing Phase: N/A

Scope: Any

Version: 2.5.0

Dependencies/Notes: None

SecResponseBodyMimeType

Description: Configures which MIME types are to be considered for response + body buffering.

Syntax: SecResponseBodyMimeType mime/type

Example Usage: SecResponseBodyMimeType text/plain + text/html

Processing Phase: N/A

Scope: Any

Version: 2.0.0

Dependencies/Notes: Multiple SecResponseBodyMimeType directives can be + used to add MIME types.

The default value is text/plaintext/html:

SecResponseBodyMimeType text/plain text/html

SecResponseBodyMimeTypesClear

Description: Clears the list of MIME types considered for response body + buffering, allowing you to start populating the list from + scratch.

Syntax: SecResponseBodyMimeTypesClear

Example Usage: SecResponseBodyMimeTypesClear

Processing Phase: N/A

Scope: Any

Version: 2.0.0

Dependencies/Notes: None

SecResponseBodyAccess

Description: Configures whether response + bodies are to be buffer and analysed or not.

Syntax: SecResponseBodyAccess On|Off

Example Usage: SecResponseBodyAccess On

Processing Phase: N/A

Scope: Any

Version: 2.0.0

Dependencies/Notes: This directive is + required if you plan to inspect HTML responses. This directive must be + used along with the "phase:4" processing phase action and RESPONSE_BODY + variable/location. If any of these 3 parts are not configured, you will + not be able to inspect the response bodies.

Possible values are:

  • On - access response bodies + (but only if the MIME type matches, see above).

  • Off - do not attempt to + access response bodies.

SecRule

Description: SecRule is the main ModSecurity directive. It + is used to analyse data and perform actions based on the results.

Syntax: SecRule + VARIABLES OPERATOR [ACTIONS]

Example Usage: SecRule REQUEST_URI "attack" \

+ "phase:1,t:none,t:urlDecode,t:lowercase,t:normalisePath"

Processing Phase: Any

Scope: Any

Version: 2.0.0

Dependencies/Notes: None

In general, the format of this rule is as follows:

SecRule VARIABLES OPERATOR [ACTIONS]

The second part, OPERATOR, + specifies how they are going to be checked. The third (optional) part, + ACTIONS, specifies what to do + whenever the operator used performs a successful match against a + variable.

Variables in rules

The first part, VARIABLES, + specifies which variables are to be checked. For example, the + following rule will reject a transaction that has the word + dirty in the URI:

SecRule ARGS dirty

Each rule can specify one or more variables:

SecRule ARGS|REQUEST_HEADERS:User-Agent dirty

There is a third format supported by the selection operator - + XPath expression. XPath expressions can only used against the special + variable XML, which is available only of the request body was + processed as XML.

SecRule XML:/xPath/Expression dirty

Note

Not all collections support all selection operator format + types. You should refer to the documentation of each collection to + determine what is and isn't supported.

Collections

A variable can contain one or many pieces of data, depending on + the nature of the variable and the way it is used. We've seen examples + of both approaches in the previous section. When a variable can + contain more than one value we refer to it as a + collection.

Collections are always expanded before a rule is run. For + example, the following rule:

SecRule ARGS dirty

will be expanded to:

SecRule ARGS:p dirty
+SecRule ARGS:q dirty

in a requests that has only two parameters, named + p and q.

Collections come in several flavours:

Read-only

Created at runtime using transaction data. For example: + ARGS (contains a list of all request + parameter values) and REQUEST_HEADERS + (contains a list of all request header values).

Transient Read/Write

The TX collection is created (empty) + for every transaction. Rules can read from it and write to it + (using the setvar action, for example), but + the information stored in this collection will not survive the + end of transaction.

Persistent Read/Write

There are several collections that can be written to, but + which are persisted to the storage backend. These collections + are used to track clients across transactions. Examples of + collections that fall into this type are IP, + SESSION and USER.

Operators in rules

In the simplest possible case you will use a regular expression + pattern as the second rule parameter. This is what we've done in the + examples above. If you do this ModSecurity assumes you want to use the + rx (regular expression) operator. + You can also explicitly specify the operator you want to use by using + @, followed by the name of an + operator, at the beginning of the second SecRule + parameter:

SecRule ARGS "@rx dirty"

Note how we had to use double quotes to delimit the second rule + parameter. This is because the second parameter now has whitespace in + it. Any number of whitespace characters can follow the name of the + operator. If there are any non-whitespace characters there, they will + all be treated as a special parameter to the operator. In the case of + the regular expression operator the special parameter is the pattern + that will be used for comparison.

The @ can be the second character if you are using negation to + negate the result returned by the operator:

SecRule &ARGS "!@rx ^0$"

Operator negation

Operator results can be negated by using an exclamation mark at + the beginning of the second parameter. The following rule matches if + the word dirty does not appear + in the User-Agent request header:

SecRule REQUEST_HEADERS:User-Agent !dirty

You can use the exclamation mark in combination with any + parameter. If you do, the exclamation mark needs to go first, followed + by the explicit operator reference. The following rule has the same + effect as the previous example:

SecRule REQUEST_HEADERS:User-Agent "!@rx dirty"

If you need to use negation in a rule that is going to be + applied to several variables then it may not be immediately clear what + will happen. Consider the following example:

SecRule ARGS:p|ARGS:q !dirty

The above rule is identical to:

SecRule ARGS:p !dirty
+SecRule ARGS:q !dirty

Warning

Negation is applied to operations against individual + operations, not agains the entire variable list.

Actions in rules

The third parameter, ACTIONS, + can be omitted only because there is a helper feature that specifies + the default action list. If the parameter isn't omitted the actions + specified in the parameter will be merged with the default action list + to create the actual list of actions that will be processed on a rule + match.

SecRuleInheritance

Description: Configures whether the current + context will inherit rules from the parent context (configuration + options are inherited in most cases - you should look up the + documentation for every directive to determine if it is inherited or + not).

Syntax: SecRuleInheritance On|Off

Example Usage: SecRuleInheritance Off

Processing Phase: Any

Scope: Any

Version: 2.0.0

Dependencies/Notes: Resource-specific + contexts (e.g. Location, Directory, etc) cannot override + phase1 rules configured in the main server or in + the virtual server. This is because phase 1 is run early in the request + processing process, before Apache maps request to resource. Virtual host + context can override phase 1 rules configured in the main server.

Example: The following example shows where ModSecurity may be + enabled in the main Apache configuration scope, however you might want + to configure your VirtualHosts differently. In the first example, the + first VirtualHost is not inheriting the ModSecurity main config + directives and in the second one it is.

SecRuleEngine On
+SecDefaultAction log,pass,phase:2
+...  
+
+<VirtualHost *:80>
+ServerName app1.com 
+ServerAlias www.app1.com
+SecRuleInheritance Off
+SecDefaultAction log,deny,phase:1,redirect:http://www.site2.com 
+... 
+</VirtualHost>  
+
+<VirtualHost *:80> 
+ServerName app2.com 
+ServerAlias www.app2.com
+SecRuleInheritance On SecRule ARGS "attack" 
+... 
+</VirtualHost>

Possible values are:

  • On - inherit rules from the + parent context.

  • Off - do not inherit rules + from the parent context.

    Note

    Configuration contexts are an Apache concept. Directives + <Directory>, + <Files>, + <Location> and + <VirtualHost> are all used to create + configuration contexts. For more information please go to the + Apache documentation section Configuration + Sections.

SecRuleEngine

Description: Configures the rules + engine.

Syntax: SecRuleEngine On|Off|DetectionOnly

Example Usage: SecRuleEngine On

Processing Phase: Any

Scope: Any

Version: 2.0.0

Dependencies/Notes: This directive can also + be controlled by the ctl action (ctl:ruleEngine=off) for per rule + processing.

Possible values are:

  • On - process rules.

  • Off - do not process + rules.

  • DetectionOnly - process + rules but never intercept transactions, even when rules are + configured to do so.

SecRuleRemoveById

Description: Removes matching rules from the + parent contexts.

Syntax: SecRuleUpdateActionById RULEID + ACTIONLIST

Example Usage: SecRuleRemoveByID 1 2 "9000-9010"

Processing Phase: Any

Scope: Any

Version: 2.0.0

Dependencies/Notes: This directive supports + multiple parameters, where each parameter can either be a rule ID, or a + range. Parameters that contain spaces must be delimited using double + quotes.

SecRuleRemoveById 1 2 5 10-20 "400-556" 673

SecRuleRemoveByMsg

Description: Removes matching rules from the + parent contexts.

Syntax: SecRuleRemoveByMsg REGEX

Example Usage: SecRuleRemoveByMsg "FAIL"

Processing Phase: Any

Scope: Any

Version: 2.0.0

Dependencies/Notes: This directive supports + multiple parameters. Each parameter is a regular expression that will be + applied to the message (specified using the msg action).

SecRuleScript (Experimental)

Description: This directive creates a special + rule that executes a Lua script to decide whether to match or not. The + main difference from SecRule is that there are no + targets nor operators. The script can fetch any variable from the + ModSecurity context and use any (Lua) operator to test them. The second + optional parameter is the list of actions whose meaning is identical to + that of SecRule.

Syntax: SecRuleScript + /path/to/script.lua [ACTIONS]

Example Usage: SecRuleScript "/path/to/file.lua" + "block"

Processing Phase: Any

Scope: Any

Version: 2.5.0

Dependencies/Notes: None

Note

All Lua scripts are compiled at configuration time and cached in + memory. To reload scripts you must reload the entire ModSecurity + configuration by restarting Apache.

Example script:

-- Your script must define the main entry
+-- point, as below.
+function main()
+    -- Log something at level 1. Normally you shouldn't be
+    -- logging anything, especially not at level 1, but this is
+    -- just to show you can. Useful for debugging.
+    m.log(1, "Hello world!");
+
+    -- Retrieve one variable.
+    local var1 = m.getvar("REMOTE_ADDR");
+
+    -- Retrieve one variable, applying one transformation function.
+    -- The second parameter is a string.
+    local var2 = m.getvar("ARGS", "lowercase");
+
+    -- Retrieve one variable, applying several transformation functions.
+    -- The second parameter is now a list. You should note that m.getvar()
+    -- requires the use of comma to separate collection names from
+    -- variable names. This is because only one variable is returned.
+    local var3 = m.getvar("ARGS.p", { "lowercase", "compressWhitespace" } );
+
+    -- If you want this rule to match return a string
+    -- containing the error message. The message must contain the name
+    -- of the variable where the problem is located.
+    -- return "Variable ARGS:p looks suspicious!"
+
+    -- Otherwise, simply return nil.
+    return nil;
+end

In this first example we were only retrieving one variable at the + time. In this case the name of the variable is known to you. In many + cases, however, you will want to examine variables whose names you won't + know in advance, for example script parameters.

Example showing use of m.getvars() to retrieve + many variables at once:

function main()
+    -- Retrieve script parameters.
+    local d = m.getvars("ARGS", { "lowercase", "htmlEntityDecode" } );
+
+    -- Loop through the paramters.
+    for i = 1, #d do
+        -- Examine parameter value.
+        if (string.find(d[i].value, "<script")) then
+            -- Always specify the name of the variable where the
+            -- problem is located in the error message.
+            return ("Suspected XSS in variable " .. d[i].name .. ".");
+        end
+    end
+
+    -- Nothing wrong found.
+    return nil;
+end

Note

Go to http://www.lua.org/ to find more + about the Lua programming language. The reference manual too is + available online, at http://www.lua.org/manual/5.1/.

Note

Lua support is marked as experimental as + the way the progamming interface may continue to evolve while we are + working for the best implementation style. Any user input into the + programming interface is appreciated.

SecRuleUpdateActionById

Description: Updates the action list of the + specified rule.

Syntax: SecRuleRemoveById RULEID ACTIONLIST

Example Usage: SecRuleUpdateActionById 12345 + deny,status:403

Processing Phase: Any

Scope: Any

Version: 2.5.0

Dependencies/Notes: This directive merges the + specified action list with the rule's action list. There are two + limitations. The rule ID cannot be changed, nor can the phase. Further + note that actions that may be specified multiple times are appended to + the original.

SecAction \
+  "t:lowercase,phase:2,id:12345,pass,msg:'The Message',log,auditlog"
+SecRuleUpdateActionById 12345 "t:compressWhitespace,deny,status:403,msg:'A new message'

The example above will cause the rule to be executed as if it was + specified as follows:

SecAction \
+  "t:lowercase,phase:2,id:12345,log,auditlog,t:compressWhitespace,deny,status:403,msg:'A new message'"

SecServerSignature

Description: Instructs ModSecurity to change + the data presented in the "Server:" response header token.

Syntax: SecServerSignature "WEB SERVER + SOFTWARE"

Example Usage: SecServerSignature + "Netscape-Enterprise/6.0"

Processing Phase: N/A

Scope: Main

Version: 2.0.0

Dependencies/Notes: In order for this + directive to work, you must set the Apache ServerTokens directive to + Full. ModSecurity will overwrite the server signature data held in this + memory space with the data set in this directive. If ServerTokens is not + set to Full, then the memory space is most likely not large enough to + hold the new data we are looking to insert.

SecTmpDir

Description: Configures the directory where + temporary files will be created.

Syntax: SecTmpDir + /path/to/dir

Example Usage: SecTmpDir /tmp

Processing Phase: N/A

Scope: Any

Version: 2.0.0

Dependencies/Notes: Needs to be writable by + the Apache user process. This is the directory location where Apache + will swap data to disk if it runs out of memory (more data than what was + specified in the SecRequestBodyInMemoryLimit directive) during + inspection.

SecUploadDir

Description: Configures the directory where + intercepted files will be stored.

Syntax: SecUploadDir + /path/to/dir

Example Usage: SecUploadDir /tmp

Processing Phase: N/A

Scope: Any

Version: 2.0.0

Dependencies/Notes: This directory must be on + the same filesystem as the temporary directory defined with SecTmpDir. This directive is used with + SecUploadKeepFiles.

SecUploadFileMode

Description: Configures the mode + (permissions) of any uploaded files using an octal mode (as used in + chmod).

Syntax: SecUploadFileMode octal_mode|"default"

Example Usage: SecUploadFileMode 0640

Processing Phase: N/A

Scope: Any

Version: 2.1.6

Dependencies/Notes: This feature is not + available on operating systems not supporting octal file modes. The + default mode (0600) only grants read/write access to the account writing + the file. If access from another account is needed (using clamd is a + good example), then this directive may be required. However, use this + directive with caution to avoid exposing potentially sensitive data to + unauthorized users. Using the value "default" will revert back to the + default setting.

Note

The process umask may still limit the mode if it is being more + restrictive than the mode set using this directive.

SecUploadKeepFiles

Description: Configures whether or not the + intercepted files will be kept after transaction is processed.

Syntax: SecUploadKeepFiles On|Off|RelevantOnly

Example Usage: SecUploadKeepFiles On

Processing Phase: N/A

Scope: Any

Version: 2.0.0

Dependencies/Notes: This directive requires + the storage directory to be defined (using SecUploadDir).

Possible values are:

  • On - Keep uploaded + files.

  • Off - Do not keep uploaded + files.

  • RelevantOnly - This will + keep only those files that belong to requests that are deemed + relevant.

SecWebAppId

Description: Creates a partition on the + server that belongs to one web application.

Syntax: SecWebAppId + "NAME"

Example Usage: SecWebAppId "WebApp1"

Processing Phase: N/A

Scope: Any

Version: 2.0.0

Dependencies/Notes: Partitions are used to + avoid collisions between session IDs and user IDs. This directive must + be used if there are multiple applications deployed on the same server. + If it isn't used, a collision between session IDs might occur. The + default value is default. + Example:

<VirtualHost *:80> 
+ServerName app1.com 
+ServerAlias www.app1.com
+SecWebAppId "App1"
+SecRule REQUEST_COOKIES:PHPSESSID !^$ chain,nolog,pass 
+SecAction setsid:%{REQUEST_COOKIES.PHPSESSID} 
+... 
+</VirtualHost>  
+
+<VirtualHost *:80> 
+ServerName app2.com 
+ServerAlias www.app2.com
+SecWebAppId "App2"
+SecRule REQUEST_COOKIES:PHPSESSID !^$ chain,nolog,pass 
+SecAction setsid:%{REQUEST_COOKIES.PHPSESSID} 
+... 
+</VirtualHost>

In the two examples configurations shown, SecWebAppId is being + used in conjunction with the Apache VirtualHost directives. What this + achieves is to create more unique collection names when being hosted on + one server. Normally, when setsid is used, ModSecurity will create a + collection with the name "SESSION" and it will hold the value specified. + With using SecWebAppId as shown in the examples, however, the name of + the collection would become "App1_SESSION" and "App2_SESSION".

SecWebAppId is relevant in two cases:

  1. You are logging transactions/alerts to the ModSecurity Console + and you want to use the web application ID to search only the + transactions belonging to that application.

  2. You are using the data persistence facility (collections + SESSION and USER) and you need to avoid collisions between sessions + and users belonging to different applications.

\ No newline at end of file diff --git a/doc/html-multipage/index.html b/doc/html-multipage/index.html new file mode 100644 index 0000000..4bbedbf --- /dev/null +++ b/doc/html-multipage/index.html @@ -0,0 +1,6 @@ +ModSecurity® Reference + Manual
ModSecurity

ModSecurity® Reference + Manual

Version 2.5.11 (Nov 4, 2009)


Table of Contents

Introduction
HTTP Traffic Logging
Real-Time Monitoring and Attack Detection
Attack Prevention and Just-in-time Patching
Flexible Rule Engine
Embedded-mode Deployment
Network-based Deployment
Portability
Licensing
ModSecurity Core Rules
Overview
Core Rules Content
Installation
Configuration Directives
SecAction
SecArgumentSeparator
SecAuditEngine
SecAuditLog
SecAuditLog2
SecAuditLogDirMode
SecAuditLogFileMode
SecAuditLogParts
SecAuditLogRelevantStatus
SecAuditLogStorageDir
SecAuditLogType
SecCacheTransformations + (Deprecated/Experimental)
SecChrootDir
SecComponentSignature
SecContentInjection
SecCookieFormat
SecDataDir
SecDebugLog
SecDebugLogLevel
SecDefaultAction
SecGeoLookupDb
SecGuardianLog
SecMarker
SecPdfProtect
SecPdfProtectMethod
SecPdfProtectSecret
SecPdfProtectTimeout
SecPdfProtectTokenName
SecRequestBodyAccess
SecRequestBodyLimit
SecRequestBodyNoFilesLimit
SecRequestBodyInMemoryLimit
SecResponseBodyLimit
SecResponseBodyLimitAction
SecResponseBodyMimeType
SecResponseBodyMimeTypesClear
SecResponseBodyAccess
SecRule
SecRuleInheritance
SecRuleEngine
SecRuleRemoveById
SecRuleRemoveByMsg
SecRuleScript (Experimental)
SecRuleUpdateActionById
SecServerSignature
SecTmpDir
SecUploadDir
SecUploadFileMode
SecUploadKeepFiles
SecWebAppId
Processing Phases
Phase Request Headers
Phase Request Body
Phase Response Headers
Phase Response Body
Phase Logging
Variables
ARGS
ARGS_COMBINED_SIZE
ARGS_NAMES
ARGS_GET
ARGS_GET_NAMES
ARGS_POST
ARGS_POST_NAMES
AUTH_TYPE
ENV
FILES
FILES_COMBINED_SIZE
FILES_NAMES
FILES_SIZES
FILES_TMPNAMES
GEO
HIGHEST_SEVERITY
MATCHED_VAR
MATCHED_VAR_NAME
MODSEC_BUILD
MULTIPART_CRLF_LF_LINES
MULTIPART_STRICT_ERROR
MULTIPART_UNMATCHED_BOUNDARY
PATH_INFO
QUERY_STRING
REMOTE_ADDR
REMOTE_HOST
REMOTE_PORT
REMOTE_USER
REQBODY_PROCESSOR
REQBODY_PROCESSOR_ERROR
REQBODY_PROCESSOR_ERROR_MSG
REQUEST_BASENAME
REQUEST_BODY
REQUEST_COOKIES
REQUEST_COOKIES_NAMES
REQUEST_FILENAME
REQUEST_HEADERS
REQUEST_HEADERS_NAMES
REQUEST_LINE
REQUEST_METHOD
REQUEST_PROTOCOL
REQUEST_URI
REQUEST_URI_RAW
RESPONSE_BODY
RESPONSE_CONTENT_LENGTH
RESPONSE_CONTENT_TYPE
RESPONSE_HEADERS
RESPONSE_HEADERS_NAMES
RESPONSE_PROTOCOL
RESPONSE_STATUS
RULE
SCRIPT_BASENAME
SCRIPT_FILENAME
SCRIPT_GID
SCRIPT_GROUPNAME
SCRIPT_MODE
SCRIPT_UID
SCRIPT_USERNAME
SERVER_ADDR
SERVER_NAME
SERVER_PORT
SESSION
SESSIONID
TIME
TIME_DAY
TIME_EPOCH
TIME_HOUR
TIME_MIN
TIME_MON
TIME_SEC
TIME_WDAY
TIME_YEAR
TX
USERID
WEBAPPID
WEBSERVER_ERROR_LOG
XML
Transformation functions
base64Decode
base64Encode
compressWhitespace
cssDecode
escapeSeqDecode
hexDecode
hexEncode
htmlEntityDecode
jsDecode
length
lowercase
md5
none
normalisePath
normalisePathWin
parityEven7bit
parityOdd7bit
parityZero7bit
removeNulls
removeWhitespace
replaceComments
replaceNulls
urlDecode
urlDecodeUni
urlEncode
sha1
trimLeft
trimRight
trim
Actions
allow
append
auditlog
block
capture
chain
ctl
deny
deprecatevar
drop
exec
expirevar
id
initcol
log
logdata
msg
multiMatch
noauditlog
nolog
pass
pause
phase
prepend
proxy
redirect
rev
sanitiseArg
sanitiseMatched
sanitiseRequestHeader
sanitiseResponseHeader
severity
setuid
setsid
setenv
setvar
skip
skipAfter
status
t
tag
xmlns
Operators
beginsWith
contains
endsWith
eq
ge
geoLookup
gt
inspectFile
le
lt
pm
pmFromFile
rbl
rx
streq
validateByteRange
validateDTD
validateSchema
validateUrlEncoding
validateUtf8Encoding
verifyCC
within
Macro Expansion
Persistant Storage
Miscellaneous Topics
Impedance Mismatch
\ No newline at end of file diff --git a/doc/html-multipage/installation.html b/doc/html-multipage/installation.html new file mode 100644 index 0000000..abd7032 --- /dev/null +++ b/doc/html-multipage/installation.html @@ -0,0 +1,65 @@ +Installation
ModSecurity

Installation

ModSecurity installation requirements:

  1. ModSecurity 2.x works only with Apache 2.0.x or higher. Version + 2.2.x is highly recommended.

  2. Make sure you have mod_unique_id installed.

    mod_unique_id is packaged with Apache httpd.

  3. libapr and libapr-util

    http://apr.apache.org/

  4. libpcre

    http://www.pcre.org/

  5. libxml2

    http://xmlsoft.org/downloads.html

  6. liblua v5.1.x

    This library is optional and only needed if you will be using + the new Lua engine.

    http://www.lua.org/download.html

    Note that ModSecurity requires the dynamic libraries. These are + not built by default in the source distribution, so the binary + distribution is recommended.

  7. libcurl v7.15.1 or higher

    If you will be using the ModSecurity Log Collector (mlogc) to + send audit logs to a central repository, then you will also need the + curl library.

    http://curl.haxx.se/libcurl/

    Note

    Many have had issues with libcurl linked with the GnuTLS + library for SSL/TLS support. It is recommended that the + openssl library be used for SSL/TLS support in libcurl.

ModSecurity installation consists of the following steps:

  1. Stop Apache httpd

  2. Unpack the ModSecurity archive

  3. Building differs for UNIX (or UNIX-like) operating systems and + Windows.

    • UNIX

      1. Run the configure script to generate a Makefile. + Typically no options are needed.

        ./configure

        Options are available for more customization (use + ./configure --help for a full list), but + typically you will only need to specify the location of the + apxs command installed by Apache httpd with + the --with-apxs option.

        ./configure + --with-apxs=/path/to/httpd-2.x.y/bin/apxs

        Note

        There are certain configure options that are meant for + debugging an other development use. If enabled, these + options can substantially impact performance. These options + include all --debug-* options as well as + the --enable-performance-measurements + options.

      2. Compile with: make

      3. Optionally test with: make + test

        Note

        This is step is still a bit experimental. If you have + problems, please send the full output and error from the + build to the support list. Most common issues are related to + not finding the required headers and/or libraries.

      4. Optionally build the ModSecurity Log Collector with: + make mlogc

      5. Optionally install mlogc: Review the + INSTALL file included in the + apache2/mlogc-src directory in the distribution.

      6. Install the ModSecurity module with: make + install

    • Windows (MS VC++ 8)

      1. Edit Makefile.win to configure the + Apache base and library paths.

      2. Compile with: nmake -f + Makefile.win

      3. Install the ModSecurity module with: nmake -f + Makefile.win install

      4. Copy the libxml2.dll and + lua5.1.dll to the Apache + bin directory. Alternatively you can follow + the step below for using LoadFile to load these + libraries.

  4. Edit the main Apache httpd config file (usually + httpd.conf)

    On UNIX (and Windows if you did not copy the DLLs as stated + above) you must load libxml2 and lua5.1 before ModSecurity with + something like this:

    LoadFile /usr/lib/libxml2.so
    +LoadFile /usr/lib/liblua5.1.so

    Load the ModSecurity module with:

    LoadModule security2_module modules/mod_security2.so

  5. Configure ModSecurity

  6. Start Apache httpd

  7. You should now have ModSecurity 2.x up and running.

Note

If you have compiled Apache yourself you might experience problems + compiling ModSecurity against PCRE. This is because Apache bundles PCRE + but this library is also typically provided by the operating system. I + would expect most (all) vendor-packaged Apache distributions to be + configured to use an external PCRE library (so this should not be a + problem).

You want to avoid Apache using the bundled PCRE library and + ModSecurity linking against the one provided by the operating system. + The easiest way to do this is to compile Apache against the PCRE library + provided by the operating system (or you can compile it against the + latest PCRE version you downloaded from the main PCRE distribution + site). You can do this at configure time using the --with-pcre switch. If you are not in a + position to recompile Apache, then, to compile ModSecurity successfully, + you'd still need to have access to the bundled PCRE headers (they are + available only in the Apache source code) and change the include path + for ModSecurity (as you did in step 7 above) to point to them (via the + --with-pcre ModSecurity configure option).

Do note that if your Apache is using an external PCRE library you + can compile ModSecurity with WITH_PCRE_STUDY defined,which would possibly + give you a slight performance edge in regular expression + processing.

Non-gcc compilers may have problems running out-of-the-box as the + current build system was designed around the gcc compiler and some + compiler/linker flags may differ. To use a non-gcc compiler you may need + some manual Makefile tweaks if issues cannot be solved by exporting + custom CFLAGS and CPPFLAGS environment variables.

If you are upgrading from ModSecurity 1.x, please refer to the + migration matrix at http://www.modsecurity.org/documentation/ModSecurity-Migration-Matrix.pdf

\ No newline at end of file diff --git a/doc/html-multipage/introduction.html b/doc/html-multipage/introduction.html new file mode 100644 index 0000000..a374041 --- /dev/null +++ b/doc/html-multipage/introduction.html @@ -0,0 +1,86 @@ +Introduction
ModSecurity

Introduction

ModSecurity is a web application firewall (WAF). With over 70% of + attacks now carried out over the web application level, organisations need + all the help they can get in making their systems secure. WAFs are + deployed to establish an increased external security layer to detect + and/or prevent attacks before they reach web applications. ModSecurity + provides protection from a range of attacks against web applications and + allows for HTTP traffic monitoring and real-time analysis with little or + no changes to existing infrastructure.

HTTP Traffic Logging

Web servers are typically well-equipped to log traffic in a form + useful for marketing analyses, but fall short logging traffic to web + applications. In particular, most are not capable of logging the request + bodies. Your adversaries know this, and that is why most attacks are now + carried out via POST requests, rendering your systems blind. ModSecurity + makes full HTTP transaction logging possible, allowing complete requests + and responses to be logged. Its logging facilities also allow + fine-grained decisions to be made about exactly what is logged and when, + ensuring only the relevant data is recorded. As some of the request + and/or response may contain sensitive data in certain fields, + ModSecurity can be configured to mask these fields before they are + written to the audit log.

Real-Time Monitoring and Attack Detection

In addition to providing logging facilities, ModSecurity can + monitor the HTTP traffic in real time in order to detect attacks. In + this case, ModSecurity operates as a web intrusion detection tool, + allowing you to react to suspicious events that take place at your web + systems.

Attack Prevention and Just-in-time Patching

ModSecurity can also act immediately to prevent attacks from + reaching your web applications. There are three commonly used + approaches:

  1. Negative security model. A negative security model monitors + requests for anomalies, unusual behaviour, and common web + application attacks. It keeps anomaly scores for each request, IP + addresses, application sessions, and user accounts. Requests with + high anomaly scores are either logged or rejected altogether.

  2. Positive security model. When a positive security model is + deployed, only requests that are known to be valid are accepted, + with everything else rejected. This model requires knownledge of the + web applications you are protecting. Therefore a positive security + model works best with applications that are heavily used but rarely + updated so that maintenance of the model is minimized.

  3. Known weaknesses and vulnerabilities. Its rule language makes + ModSecurity an ideal external patching tool. External patching + (sometimes referred to as Virtual Patching) is about reducing the + window of opportunity. Time needed to patch application + vulnerabilities often runs to weeks in many organisations. With + ModSecurity, applications can be patched from the outside, without + touching the application source code (and even without any access to + it), making your systems secure until a proper patch is applied to + the application.

Flexible Rule Engine

A flexible rule engine sits in the heart of ModSecurity. It + implements the ModSecurity Rule Language, which is a specialised + programming language designed to work with HTTP transaction data. The + ModSecurity Rule Language is designed to be easy to use, yet flexible: + common operations are simple while complex operations are possible. + Certified ModSecurity Rules, included with ModSecurity, contain a + comprehensive set of rules that implement general-purpose hardening, + protocol validation and detection of common web application security + issues. Heavily commented, these rules can be used as a learning + tool.

Embedded-mode Deployment

ModSecurity is an embeddable web application firewall, which means + it can be deployed as part of your existing web server infrastructure + provided your web servers are Apache-based. This deployment method has + certain advantages:

  1. No changes to existing network. It only takes a few minutes to + add ModSecurity to your existing web servers. And because it was + designed to be completely passive by default, you are free to deploy + it incrementally and only use the features you need. It is equally + easy to remove or deactivate it if required.

  2. No single point of failure. Unlike with network-based + deployments, you will not be introducing a new point of failure to + your system.

  3. Implicit load balancing and scaling. Because it works embedded + in web servers, ModSecurity will automatically take advantage of the + additional load balancing and scalability features. You will not + need to think of load balancing and scaling unless your existing + system needs them.

  4. Minimal overhead. Because it works from inside the web server + process there is no overhead for network communication and minimal + overhead in parsing and data exchange.

  5. No problem with encrypted or compressed content. Many IDS + systems have difficulties analysing SSL traffic. This is not a + problem for ModSecurity because it is positioned to work when the + traffic is decrypted and decompressed.

Network-based Deployment

ModSecurity works equally well when deployed as part of an + Apache-based reverse proxy server, and many of our customers choose to + do so. In this scenario, one installation of ModSecurity can protect any + number of web servers (even the non-Apache ones).

Portability

ModSecurity is known to work well on a wide range of operating + systems. Our customers are successfully running it on Linux, Windows, + Solaris, FreeBSD, OpenBSD, NetBSD, AIX, Mac OS X, and HP-UX.

Licensing

ModSecurity is available under two licenses. Users can choose to + use the software under the terms of the GNU General Public License + version 2 (licence text is included with the distribution), as an Open + Source / Free Software product. A range of commercial licenses is also + available, together with a range of commercial support contracts. For + more information on commercial licensing please contact Breach + Security.

Note

ModSecurity, mod_security, ModSecurity Pro, and ModSecurity Core + Rules are trademarks or registered trademarks of Breach Security, + Inc.

\ No newline at end of file diff --git a/doc/html-multipage/modsecurity-reference.css b/doc/html-multipage/modsecurity-reference.css new file mode 100644 index 0000000..1c89c88 --- /dev/null +++ b/doc/html-multipage/modsecurity-reference.css @@ -0,0 +1,102 @@ + +body { + font: 13px/20px Arial, Helvetica; + background-color: white; + width: 800px; +} + +/* TEXT */ + +PRE { + font-size: 100%; + padding: 5px; + border-style: solid; + border-width: 1px; + border-color: #CCCCCC; + background-color: #F5F8FA; +} + +p, td, tr, li, ol, ul { + /*font-family: Trebuchet MS, Verdana, Tahoma, Arial, Helvetica, Geneva;*/ + /*font-family: Arial, Helvetica; + font-size: 14px; + line-height: 24px;*/ +} + +.copyright { + font-size: 10px; +} + +h1 { + padding-top: 40px; + font: 24px/30px Arial, Helvetica; + font-weight: bold; +} + +h2 { + font: 20px/30px Arial, Helvetica; + font-weight: bold; +} + +h3 { + padding-top: 15px; + font: 16px/10px Arial, Helvetica; + font-weight: bold; +} + +h4 { + padding-top: 15px; + font: 14px/10px Arial, Helvetica; + font-weight: bold; +} + + + + +.header { + background-color: #00448B; + border-top: 6px solid #002B6E; + height: 84px; + vertical-align: top; + padding-left: 20px; + padding-top: 10px; +} + +.topNavigation { + background-color: #EEEEEE; + background: url('g/topnav-background.gif'); + height: 23px; + line-height: 12px; + vertical-align: top; + padding-left: 12px; + padding-top: 5px; +} + +.topLink, A.topLink:link, A.topLink:active, A.topLink:visited { + font-weight: bold; + color: black; + text-decoration: none; + padding-left: 8px; + padding-right: 8px; +} + +A.topLink:hover { + color: #BB0000; +} + +#navheader td { + font-size: 12px; +} + +#navfooter td { + font-size: 12px; +} + +h3.title { + margin-top: 0px; +} + +.note { + border-top: 1px solid #CCCCCC; + border-bottom: 1px solid #CCCCCC; +} diff --git a/doc/html-multipage/modsecurity.gif b/doc/html-multipage/modsecurity.gif new file mode 100644 index 0000000000000000000000000000000000000000..76f5ca1632677cb890e0a5ad57cf47cb8a4a6c8d GIT binary patch literal 2585 zcmV+!3g-1kNk%w1VR!%}0OkMyMS8T;+UNWG{a1IVdy~1WyVD0Zeqx@~4m^P!N{eWu z+9FMj7(|8^LWB}Nfh<&!G+UL8qQhB|$|qKpQi;NvtjcVu-t+bNJ#npVhq6Rxo$c`T zLUys-;_OO*x;kyDV4KktK!Rze+>)imRgK2z?DH^Tp62TExy0F|w9hJ9nIlkm!FW4o`jp2nVgKB zq^Y5Xm8+(xjgO_8v$Kh)u)Ds!qmsX!s<67EtCPvKoXpL&uf)R3$-S!6vX{oYmAI#* z&bZvK!l91m;Mvx|+RCY{*wxL%^V;^HuJyjove%iC0NcSUc8j1fWRs8y)Fn?|EL+tW z4ntRt*D!AL^tB3x1c66$qb#ngn5&qk227Z6`E*ekvt!2^vTS&z$%qjI^!bBn5Z|;- z45V=2aAe9Elk4cUqIK?8J5w7SAt=zN&z?V1o<4e6GS|$dhZ?l7V1WXcK~oxJZF-L& zz@7g8;{HOAqG|xF0zF+z2ba^)jDH$7HbWKmr3Zf}n#4JaCv9CkUjWWd{Wapd}0_XnBVLwf5n}4pdZyf&l|)nZplS_OJpA zI)DLy76+7}02FG(p@0}lz%fG^B4FSE8ZU$a1_cy=A%+fJ*l++CWI*8n6k&Lp2OK)Q z0Kym|P(a5QUwF`k9tU`;M;tGRF@qOOupx%PUX+-PDXmsD1Ox_9)rS>+AmC;HA3H#x z>5;^42r&j22l&9i1Uv|_0tO0@K|u%(*zkfG2joEk z8473-0uvb6@d5=CoQw3jOE(Qh3@SkGLDeC6k#!g*gh0U;I(&ct2Sb0r#80fcsVGyWC~JF93lH*jZiK_?N@~v0)BBTL7|1@P{*m1QZHn;M*W5K`T}80diQL207?K zophCkSl2@Zgt4oe3w9|BQ-L&VzA zcz_r^d_fN;c!2`o&<2orBZ|RuAQk6U1iNAJ0T-ys04h)wEYL>(O~&y<0unFGMj7EqvKT2Me3D6oa@MZpgakbxKu z0D={?U<^6{0OUB(Ckdcomoh*A6v)6seEm?E`zvO;LePdII4uTdh=C1oV34LrbBe^P z$_^Hg$vzNa3Y^px7b@9@Av^&BRX7m5J4Ht0D>@#Aq+fdT@)0sh8V;k3cFgC5GDNExmM8iPPU21-zZ008d> zti?hD`$hj>cRl zsK&T_h{3^PKmiqS0S7YB!@)@KfpX3OjUWI49L~Z80Hn7DHS|IYK;YOFgaBURLj!c4 z0S)N7;JRz*v#P0yOXh4J-fwC6dGc1D>#iEck)IeozAgR-ghlCUw1InS3@}1?F@-E- zfub`svUP5QgDhC*5I8^rZYj!%Ea3JGMaIDa?bsa>se*=F0HP$m)14(V0?bE24wJBq z97M3WL;)rhauOh39e6-hjmZZBF~SR|xMLX<`3GR=F%f9``67Pc!UQ~}0Nsg1BogUM zL}t>HL1!c&0oeyMD9wpBe82+goWM$uLLWW@de621OEd_*7nZDg9GGznBN%W500003 zo6g5V9s-PhoI=pO21j1d5 zX!p4s=Gcr&{EX?<{6jK)dC0c6{f>>eWHOItb-0yM>~3GD-K-|aUm!y4K6{%X--tCx voOperators
ModSecurity

Operators

A number of operators can be used in rules, as documented below. The + operator syntax uses the @ symbol followed by the + specific operator name.

beginsWith

Description: This operator is a string + comparison and returns true if the parameter value is found at the + beginning of the input. Macro expansion is performed so you may use + variable names such as %{TX.1}, etc.

Example:

SecRule REQUEST_LINE "!@beginsWith GET" t:none,deny,status:403
+SecRule REQUEST_ADDR "^(.*)\.\d+$" deny,status:403,capture,chain
+SecRule ARGS:gw "!@beginsWith %{TX.1}"

contains

Description: This operator is a string + comparison and returns true if the parameter value is found anywhere in + the input. Macro expansion is performed so you may use variable names + such as %{TX.1}, etc.

Example:

SecRule REQUEST_LINE "!@contains .php" t:none,deny,status:403
+SecRule REQUEST_ADDR "^(.*)$" deny,status:403,capture,chain
+SecRule ARGS:ip "!@contains %{TX.1}"

endsWith

Description: This operator is a string + comparison and returns true if the parameter value is found at the end + of the input. Macro expansion is performed so you may use variable names + such as %{TX.1}, etc.

Example:

SecRule REQUEST_LINE "!@endsWith HTTP/1.1" t:none,deny,status:403
+SecRule ARGS:route "!@endsWith %{REQUEST_ADDR}" t:none,deny,status:403

eq

Description: This operator is a numerical + comparison and stands for "equal to."

Example:

SecRule &REQUEST_HEADERS_NAMES "@eq 15"

ge

Description: This operator is a numerical + comparison and stands for "greater than or equal to."

Example:

SecRule &REQUEST_HEADERS_NAMES "@ge 15"

geoLookup

Description: This operator looks up various + data fields from an IP address or hostname in the target data. The + results will be captured in the GEO + collection.

You must provide a database via SecGeoLookupDb before this operator can be + used.

Note

This operator matches and the action is executed on a + successful lookup. For this reason, you probably want to + use the pass,nolog actions. This allows for + setvar and other non-disruptive + actions to be executed on a match. If you wish to block on a failed + lookup, then do something like this (look for an empty GEO + collection):

SecGeoLookupDb /usr/local/geo/data/GeoLiteCity.dat
+...
+SecRule REMOTE_ADDR "@geoLookup" "pass,nolog"
+SecRule &GEO "@eq 0" "deny,status:403,msg:'Failed to lookup IP'"

See the GEO variable for an + example and more information on various fields available.

gt

Description: This operator is a numerical + comparison and stands for "greater than."

Example:

SecRule &REQUEST_HEADERS_NAMES "@gt 15"

inspectFile

Description: Executes the external + script/binary given as parameter to the operator against every file + extracted from the request. As of v2.5.0, if the supplied filename is + not absolute it is treated as relative to the directory in which the + configuration file resides. Also as of v2.5.0, if the filename is + determined to be a Lua script (based on its extension) the script will + be processed by the internal engine. As such it will have full access to + the ModSecurity context.

Example of using an external binary/script:

# Execute external script to validate uploaded files.
+SecRule FILES_TMPNAMES "@inspectFile /opt/apache/bin/inspect_script.pl"

Example of using Lua script:

SecRule FILES_TMPNANMES "@inspectFile inspect.lua"

Script inspect.lua:

function main(filename)
+    -- Do something to the file to verify it. In this example, we
+    -- read up to 10 characters from the beginning of the file.
+    local f = io.open(filename, "rb");
+    local d = f:read(10);
+    f:close();
+   
+    -- Return null if there is no reason to believe there is ansything
+    -- wrong with the file (no match). Returning any text will be taken
+    -- to mean a match should be trigerred.
+    return null;
+end

le

Description: This operator is a numerical + comparison and stands for "less than or equal to."

Example:

SecRule &REQUEST_HEADERS_NAMES "@le 15"

lt

Description: This operator is a numerical + comparison and stands for "less than."

Example:

SecRule &REQUEST_HEADERS_NAMES "@lt 15"

pm

Description: Phrase Match operator. This + operator uses a set based matching engine (Aho-Corasick) for faster + matches of keyword lists. It will match any one of its arguments + anywhere in the target value. The match is case insensitive.

Example:

SecRule REQUEST_HEADERS:User-Agent "@pm WebZIP WebCopier Webster WebStripper SiteSnagger ProWebWalker CheeseBot" "deny,status:403

The above would deny access with 403 if any of the words matched + within the User-Agent HTTP header value.

pmFromFile

Description: Phrase Match operator. This + operator uses a set based matching engine (Aho-Corasick) for faster + matches of keyword lists. This operator is the same as + @pm except that it takes a list of files as + arguments. It will match any one of the phrases listed in the file(s) + anywhere in the target value.

Notes:

  1. The contents of the files should be one phrase per line. End + of line markers will be stripped from the phrases, however, + whitespace will not be trimmed from phrases in the file. Empty lines + and comment lines (beginning with a '#') are ignored.

  2. To allow easier inclusion of phrase files with rulesets, + relative paths may be used to the phrase files. In this case, the + path of the file containing the rule is prepended to the phrase file + path.

Example:

SecRule REQUEST_HEADERS:User-Agent "@pm /path/to/blacklist1 blacklist2" "deny,status:403

The above would deny access with 403 if any of the patterns in the + two files matched within the User-Agent HTTP header value. The + blacklist2 file would need to be placed in the same + path as the file containing the rule.

rbl

Description: Look up the parameter in the RBL + given as parameter. Parameter can be an IPv4 address, or a + hostname.

Example:

SecRule REMOTE_ADDR "@rbl sc.surbl.org"

rx

Description: Regular expression operator. + This is the default operator, so if the "@" operator is not defined, it + is assumed to be rx.

Example:

SecRule REQUEST_HEADERS:User-Agent "@rx nikto"

Note

Regular expressions are handled by the PCRE library (http://www.pcre.org). ModSecurity + compiles its regular expressions with the following settings:

  1. The entire input is treated as a single line, even when there + are newline characters present.

  2. All matches are case-sensitive. If you do not care about case + sensitivity you either need to implement the lowercase transformation function, or use + the per-pattern(?i)modifier, as + allowed by PCRE.

  3. The PCRE_DOTALL and + PCRE_DOLLAR_ENDONLY flags are set + during compilation, meaning a single dot will match any character, + including the newlines and a $ + end anchor will not match a trailing newline character.

streq

Description: This operator is a string + comparison and returns true if the parameter value matches the input + exactly. Macro expansion is performed so you may use variable names such + as %{TX.1}, etc.

Example:

SecRule ARGS:foo "!@streq bar" t:none,deny,status:403
+SecRule REQUEST_ADDR "^(.*)$" deny,status:403,capture,chain
+SecRule REQUEST_HEADERS:Ip-Address "!@streq %{TX.1}"

validateByteRange

Description: Validates the byte range used in + the variable falls into the specified range.

Example:

SecRule ARGS:text "@validateByteRange 10, 13, 32-126"

Note

You can force requests to consist only of bytes from a certain + byte range. This can be useful to avoid stack overflow attacks (since + they usually contain "random" binary content). Default range values are + 0 and 255, i.e. all byte values are allowed. This directive does not + check byte range in a POST payload when + multipart/form-data encoding (file upload) is used. + Doing so would prevent binary files from being uploaded. However, after + the parameters are extracted from such request they are checked for a + valid range.

validateByteRange is similar to the ModSecurity 1.X + SecFilterForceByteRange Directive however since it works in a rule + context, it has the following differences:

  • You can specify a different range for different + variables.

  • It has an "event" context (id, msg....)

  • It is executed in the flow of rules rather than being a built + in pre-check.

validateDTD

Description: Validates the DOM tree generated + by the XML request body processor against the supplied DTD.

Example:

SecDefaultAction log,deny,status:403,phase:2
+SecRule REQUEST_HEADERS:Content-Type ^text/xml$ \
+    phase:1,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML
+SecRule REQBODY_PROCESSOR "!^XML$" nolog,pass,skipAfter:12345
+SecRule XML "@validateDTD /path/to/apache2/conf/xml.dtd" "deny,id:12345"

Note

This operator requires request body to be processed as + XML.

validateSchema

Description: Validates the DOM tree generated + by the XML request body processor against the supplied XML + Schema.

Example:

SecDefaultAction log,deny,status:403,phase:2
+SecRule REQUEST_HEADERS:Content-Type ^text/xml$ \
+    phase:1,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML
+SecRule REQBODY_PROCESSOR "!^XML$" nolog,pass,skipAfter:12345
+SecRule XML "@validateSchema /path/to/apache2/conf/xml.xsd" "deny,id:12345"

Note

This operator requires request body to be processed as + XML.

validateUrlEncoding

Description: Verifies the encodings used in + the variable (if any) are valid.

Example:

SecRule ARGS "@validateUrlEncoding"

Note

URL encoding is an HTTP standard for encoding byte values within a + URL. The byte is escaped with a % followed by two hexadecimal values + (0-F). This directive does not check encoding in a POST payload when the + multipart/form-data encoding (file upload) is used. + It is not necessary to do so because URL encoding is not used for this + encoding.

validateUtf8Encoding

Description: Verifies the variable is a valid + UTF-8 encoded string.

Example:

SecRule ARGS "@validateUtf8Encoding"

Note

UTF-8 encoding is valid on most web servers. Integer values + between 0-65535 are encoded in a UTF-8 byte sequence that is escaped by + percents. The short form is two bytes in length.

check for three types of errors:

  • Not enough bytes. UTF-8 supports two, three, four, five, and + six byte encodings. ModSecurity will locate cases when a byte or + more is missing.

  • Invalid encoding. The two most significant bits in most + characters are supposed to be fixed to 0x80. Attackers can use this + to subvert Unicode decoders.

  • Overlong characters. ASCII characters are mapped directly into + the Unicode space and are thus represented with a single byte. + However, most ASCII characters can also be encoded with two, three, + four, five, and six characters thus tricking the decoder into + thinking that the character is something else (and, presumably, + avoiding the security check).

verifyCC

Description: This operator verifies a given + regular expression as a potential credit card number. It first matches + with a single generic regular expression then runs the resulting match + through a Luhn checksum algorithm to further verify it as a potential + credit card number.

Example:

SecRule ARGS "@verifyCC \d{13,16}" \
+              "phase:2,sanitiseMatched,log,auditlog,pass,msg:'Potential credit card number'"

within

Description: This operator is a string + comparison and returns true if the input value is found anywhere within + the parameter value. Note that this is similar to + @contains, except that the target and match values + are reversed. Macro expansion is performed so you may use variable names + such as %{TX.1}, etc.

Example:

SecRule REQUEST_METHOD "!@within get,post,head" t:lowercase,deny,status:403
+
+SecAction "pass,setvar:'tx.allowed_methods=get,post,head'"
+SecRule REQUEST_METHOD "!@within %{tx.allowed_methods}" t:lowercase,deny,status:403
\ No newline at end of file diff --git a/doc/html-multipage/processing-phases.html b/doc/html-multipage/processing-phases.html new file mode 100644 index 0000000..5778032 --- /dev/null +++ b/doc/html-multipage/processing-phases.html @@ -0,0 +1,56 @@ +Processing Phases
ModSecurity

Processing Phases

ModSecurity 2.x allows rules to be placed in one of the following + five phases:

  1. Request headers (REQUEST_HEADERS)

  2. Request body (REQUEST_BODY)

  3. Response headers (RESPONSE_HEADERS)

  4. Response body (RESPONSE_BODY)

  5. Logging (LOGGING)

Below is a diagram of the standard Apache Request Cycle. In the + diagram, the 5 ModSecurity processing phases are shown.

In order to select the phase a rule executes during, use the phase + action either directly in the rule or in using the + SecDefaultAction directive:

SecDefaultAction "log,pass,phase:2"
+SecRule REQUEST_HEADERS:Host "!^$" "deny,phase:1"

Note

Keep in mind that rules are executed according to phases, so even + if two rules are adjacent in a configuration file, but are set to + execute in different phases, they would not happen one after the other. + The order of rules in the configuration file is important only within + the rules of each phase. This is especially important when using the + skip and skipAfter actions.

Note

The LOGGING phase is special. It is executed at + the end of each transaction no matter what happened in the previous + phases. This means it will be processed even if the request was + intercepted or the allow action was used to pass the + transaction through.

Phase Request Headers

Rules in this phase are processed immediately after Apache + completes reading the request headers (post-read-request phase). At this + point the request body has not been read yet, meaning not all request + arguments are available. Rules should be placed in this phase if you + need to have them run early (before Apache does something with the + request), to do something before the request body has been read, + determine whether or not the request body should be buffered, or decide + how you want the request body to be processed (e.g. whether to parse it + as XML or not).

Note

Rules in this phase can not leverage Apache scope directives + (Directory, Location, LocationMatch, etc...) as the post-read-request + hook does not have this information yet. The exception here is the + VirtualHost directive. If you want to use ModSecurity rules inside + Apache locations, then they should run in Phase 2. Refer to the Apache + Request Cycle/ModSecurity Processing Phases diagram.

Phase Request Body

This is the general-purpose input analysis phase. Most of the + application-oriented rules should go here. In this phase you are + guaranteed to have received the request arguments (provided the request + body has been read). ModSecurity supports three encoding types for the + request body phase:

  • application/x-www-form-urlencoded - used to + transfer form data

  • multipart/form-data - used for file + transfers

  • text/xml - used for passing XML data

Other encodings are not used by most web applications.

Phase Response Headers

This phase takes place just before response headers are sent back + to the client. Run here if you want to observe the response before that + happens, and if you want to use the response headers to determine if you + want to buffer the response body. Note that some response status codes + (such as 404) are handled earlier in the request cycle by Apache and my + not be able to be triggered as expected. Additionally, there are some + response headers that are added by Apache at a later hook (such as Date, + Server and Connection) that we would not be able to trigger on or + sanitize. This should work appropriately in a proxy setup or within + phase:5 (logging).

Phase Response Body

This is the general-purpose output analysis phase. At this point + you can run rules against the response body (provided it was buffered, + of course). This is the phase where you would want to inspect the + outbound HTML for information disclosure, error messages or failed + authentication text.

Phase Logging

This phase is run just before logging takes place. The rules + placed into this phase can only affect how the logging is performed. + This phase can be used to inspect the error messages logged by Apache. + You cannot deny/block connections in this phase as it is too late. This + phase also allows for inspection of other response headers that weren't + available during phase:3 or phase:4. Note that you must be careful not + to inherit a disruptive action into a rule in this phase as this is a + configuration error in ModSecurity 2.5.0 and later versions.

\ No newline at end of file diff --git a/doc/html-multipage/transformation-functions.html b/doc/html-multipage/transformation-functions.html new file mode 100644 index 0000000..ca18dc1 --- /dev/null +++ b/doc/html-multipage/transformation-functions.html @@ -0,0 +1,75 @@ +Transformation functions
ModSecurity

Transformation functions

When ModSecurity receives request or response information, it makes + a copy of this data and places it into memory. It is on this data in + memory that transformation functions are applied. The raw request/response + data is never altered. Transformation functions are used to transform a + variable before testing it in a rule.

Note

There are no default transformation functions as there were in + previous versions of ModSecurity.

The following rule will ensure that an attacker does not use mixed + case in order to evade the ModSecurity rule:

SecRule ARGS:p "xp_cmdshell" "t:lowercase"
+ multiple transformation actions can be used in the same rule, for example + the following rule also ensures that an attacker does not use URL encoding + (%xx encoding) for evasion. Note the order of the transformation + functions, which ensures that a URL encoded letter is first decoded and + than translated to lower case.

SecRule ARGS:p "xp_cmdshell" "t:urlDecode,t:lowercase"

One can use the SecDefaultAction command to ensure the translation + occurs for every rule until the next. Note that transformation actions are + additive, so if a rule explicitly list actions, the translation actions + set by SecDefaultAction are still performed.

SecDefaultAction t:urlDecode,t:lowercase

The following transformation functions are supported:

base64Decode

This function decodes a base64-encoded string.

base64Encode

This function encodes input string using base64 encoding.

compressWhitespace

It converts whitespace characters (32, \f, \t, \n, \r, \v, 160) to + spaces (ASCII 32) and then compresses multiple consecutive space + characters into one.

cssDecode

Decodes CSS-encoded characters, as specified at http://www.w3.org/TR/REC-CSS2/syndata.html. + This function uses only up to two bytes in the decoding process, meaning + it is useful to uncover ASCII characters (that wouldn't normally be + encoded) encoded using CSS encoding, or to counter evasion which is a + combination of a backslash and non-hexadecimal characters (e.g. + ja\vascript is equivalent to + javascript).

escapeSeqDecode

This function decode ANSI C escape sequences: \a, \b, + \f, \n, \r, + \t, \v, \\, + \?, \', \", + \xHH (hexadecimal), \0OOO (octal). Invalid encodings are left in + the output.

hexDecode

This function decodes a hex-encoded string.

hexEncode

This function encodes input as hex-encoded string.

htmlEntityDecode

This function decodes HTML entities present in input. The + following variants are supported:

  • &#xHH and &#xHH; (where H is any hexadecimal + number)

  • &#DDD and &#DDD; (where D is any decimal + number)

  • &quot and &quot;

  • &nbsp and &nbsp;

  • &lt and &lt;

  • &gt and &gt;

This function will convert any entity into a single byte only, + possibly resulting in a loss of information. It is thus useful to + uncover bytes that would otherwise not need to be encoded, but it cannot + do anything with the characters from the range above 255.

jsDecode

Decodes JavaScript escape sequences. If a + \uHHHH code is in the range of + FF01-FF5E (the full width ASCII + codes), then the higher byte is used to detect and adjust the lower + byte. Otherwise, only the lower byte will be used and the higher byte + zeroed.

length

This function converts the input to its numeric length (count of + bytes).

lowercase

This function converts all characters to lowercase using the + current C locale.

md5

This function calculates an MD5 hash from input. Note that the + computed hash is in a raw binary form and may need encoded into text to + be usable (for example: t:md5,t:hexEncode).

none

Not an actual transformation function, but an instruction to + ModSecurity to remove all transformation functions associated with the + current rule.

normalisePath

This function will remove multiple slashes, self-references and + directory back-references (except when they are at the beginning of the + input).

normalisePathWin

Same as normalisePath, but will first convert + backslash characters to forward slashes.

parityEven7bit

This function calculates even parity of 7-bit data replacing the + 8th bit of each target byte with the calculated parity bit.

parityOdd7bit

This function calculates odd parity of 7-bit data replacing the + 8th bit of each target byte with the calculated parity bit.

parityZero7bit

This function calculates zero parity of 7-bit data replacing the + 8th bit of each target byte with a zero parity bit which allows + inspection of even/odd parity 7bit data as ASCII7 data.

removeNulls

This function removes NULL bytes from input.

removeWhitespace

This function removes all whitespace characters from input.

replaceComments

This function replaces each occurrence of a C-style comments + (/* ... */) with a single space + (multiple consecutive occurrences of a space will not be compressed). + Unterminated comments will too be replaced with a space (ASCII 32). + However, a standalone termination of a comment (*/) will not be acted upon.

replaceNulls

This function is enabled by default. It replaces NULL bytes in + input with spaces (ASCII 32).

urlDecode

This function decodes an URL-encoded input string. Invalid + encodings (i.e. the ones that use non-hexadecimal characters, or the + ones that are at the end of string and have one or two characters + missing) will not be converted. If you want to detect invalid encodings + use the @validateUrlEncoding + operator. The transformation function should not be used against + variables that have already been URL-decoded unless it is your intention + to perform URL decoding twice!

urlDecodeUni

In addition to decoding %xx like urlDecode, urlDecodeUni also decodes %uXXXX encoding. If the code is in the range + of FF01-FF5E (the full width ASCII + codes), then the higher byte is used to detect and adjust the lower + byte. Otherwise, only the lower byte will be used and the higher byte + zeroed.

urlEncode

This function encodes input using URL encoding.

sha1

This function calculates a SHA1 hash from input. Note that the + computed hash is in a raw binary form and may need encoded to be usable + (for example: t:sha1,t:hexEncode).

trimLeft

This function removes whitespace from the left side of + input.

trimRight

This function removes whitespace from the right side of + input.

trim

This function removes whitespace from both the left and right + sides of input.

\ No newline at end of file diff --git a/doc/html-multipage/variables.html b/doc/html-multipage/variables.html new file mode 100644 index 0000000..e19a854 --- /dev/null +++ b/doc/html-multipage/variables.html @@ -0,0 +1,360 @@ +Variables
ModSecurity

Variables

The following variables are supported in ModSecurity 2.x:

ARGS

ARGS is a collection and can be used on its own + (means all arguments including the POST Payload), with a static + parameter (matches arguments with that name), or with a regular + expression (matches all arguments with name that matches the regular + expression). To look at only the query string or body arguments, see the + ARGS_GET and ARGS_POST + collections.

Some variables are actually collections, which are expanded into + more variables at runtime. The following example will examine all + request arguments:

SecRule ARGS dirty
+ Sometimes, however, you will want to look only at parts of a collection. + This can be achieved with the help of the selection + operator(colon). The following example will only look at the + arguments named p (do note that, in + general, requests can contain multiple arguments with the same name): +
SecRule ARGS:p dirty
+ It is also possible to specify exclusions. The following will examine + all request arguments for the word dirty, except + the ones named z (again, there can be + zero or more arguments named z): +
SecRule ARGS|!ARGS:z dirty
+ There is a special operator that allows you to count how many variables + there are in a collection. The following rule will trigger if there is + more than zero arguments in the request (ignore the second parameter for + the time being):
SecRule &ARGS !^0$
+ And sometimes you need to look at an array of parameters, each with a + slightly different name. In this case you can specify a regular + expression in the selection operator itself. The following rule will + look into all arguments whose names begin with id_:
SecRule ARGS:/^id_/ dirty

Note

Using ARGS:p will not result in any + invocations against the operator if argument p does not exist.

In ModSecurity 1.X, the ARGS variable stood + for QUERY_STRING + POST_PAYLOAD, + whereas now it expands to individual variables.

ARGS_COMBINED_SIZE

This variable allows you to set more targeted evaluations on the + total size of the Arguments as compared with normal Apache LimitRequest + directives. For example, you could create a rule to ensure that the + total size of the argument data is below a certain threshold (to help + prevent buffer overflow issues). Example: Block request if the size of + the arguments is above 25 characters.

SecRule REQUEST_FILENAME "^/cgi-bin/login\.php" \
+    "chain,log,deny,phase:2,t:none,t:lowercase,t:normalisePath"
+SecRule ARGS_COMBINED_SIZE "@gt 25"

ARGS_NAMES

Is a collection of the argument names. You can search for specific + argument names that you want to block. In a positive policy scenario, + you can also whitelist (using an inverted rule with the ! character) + only authorized argument names. Example: This example rule will only + allow 2 argument names - p and a. If any other argument names are + injected, it will be blocked.

SecRule REQUEST_FILENAME "/index.php" \
+    "chain,log,deny,status:403,phase:2,t:none,t:lowercase,t:normalisePath"
+SecRule ARGS_NAMES "!^(p|a)$" "t:none,t:lowercase"

ARGS_GET

ARGS_GET is similar to ARGS, + but only contains arguments from the query string.

ARGS_GET_NAMES

ARGS_GET_NAMES is similar to + ARGS_NAMES, but only contains argument names from the + query string.

ARGS_POST

ARGS_POST is similar to + ARGS, but only contains arguments from the POST + body.

ARGS_POST_NAMES

ARGS_POST_NAMES is similar to + ARGS_NAMES, but only contains argument names from the + POST body.

AUTH_TYPE

This variable holds the authentication method used to validate a + user. Example:

SecRule AUTH_TYPE "basic" log,deny,status:403,phase:1,t:lowercase

Note

This data will not be available in a proxy-mode deployment as the + authentication is not local. In a proxy-mode deployment, you would need + to inspect the REQUEST_HEADERS:Authorization + header.

ENV

Collection, requires a single parameter (after colon). The + ENV variable is set with setenv and does not give + access to the CGI environment variables. Example:

SecRule REQUEST_FILENAME "printenv" pass,setenv:tag=suspicious
+SecRule ENV:tag "suspicious"

FILES

Collection. Contains a collection of original file names (as they + were called on the remote user's file system). Note: only available if + files were extracted from the request body. Example:

SecRule FILES "\.conf$" log,deny,status:403,phase:2

FILES_COMBINED_SIZE

Single value. Total size of the uploaded files. Note: only + available if files were extracted from the request body. Example:

SecRule FILES_COMBINED_SIZE "@gt 1000" log,deny,status:403,phase:2

FILES_NAMES

Collection w/o parameter. Contains a list of form fields that were + used for file upload. Note: only available if files were extracted from + the request body. Example:

SecRule FILES_NAMES "^upfile$" log,deny,status:403,phase:2

FILES_SIZES

Collection. Contains a list of file sizes. Useful for implementing + a size limitation on individual uploaded files. Note: only available if + files were extracted from the request body. Example:

SecRule FILES_SIZES "@gt 100" log,deny,status:403,phase:2

FILES_TMPNAMES

Collection. Contains a collection of temporary files' names on the + disk. Useful when used together with @inspectFile. Note: only available if files + were extracted from the request body. Example:

SecRule FILES_TMPNAMES "@inspectFile /path/to/inspect_script.pl"

GEO

GEO is a collection populated by the results of + the last @geoLookup operator. The + collection can be used to match geographical fields looked from an IP + address or hostname.

Available since ModSecurity 2.5.0.

Fields:

  • COUNTRY_CODE: Two character country code. + EX: US, GB, etc.

  • COUNTRY_CODE3: Up to three character + country code.

  • COUNTRY_NAME: The full country + name.

  • COUNTRY_CONTINENT: The two character + continent that the country is located. EX: EU

  • REGION: The two character region. For US, + this is state. For Canada, providence, etc.

  • CITY: The city name if supported by the + database.

  • POSTAL_CODE: The postal code if supported + by the database.

  • LATITUDE: The latitude if supported by + the database.

  • LONGITUDE: The longitude if supported by + the database.

  • DMA_CODE: The metropolitan area code if + supported by the database. (US only)

  • AREA_CODE: The phone system area code. + (US only)

Example:

SecGeoLookupDb /usr/local/geo/data/GeoLiteCity.dat
+...
+SecRule REMOTE_ADDR "@geoLookup" "chain,drop,msg:'Non-GB IP address'"
+SecRule GEO:COUNTRY_CODE "!@streq GB"

HIGHEST_SEVERITY

This variable holds the highest severity of any rules that have + matched so far. Severities are numeric values and thus can be used with + comparison operators such as @lt, + etc.

Note

Higher severities have a lower numeric value.

A value of 255 indicates no severity has been set.

SecRule HIGHEST_SEVERITY "@le 2" "phase:2,deny,status:500,msg:'severity %{HIGHEST_SEVERITY}'"

MATCHED_VAR

This variable holds the value of the variable that was matched + against. It is similar to the TX:0, except it can be used for all + operators and does not require that the capture action be specified.

SecRule ARGS pattern chain,deny
+...
+SecRule MATCHED_VAR "further scrutiny"

MATCHED_VAR_NAME

This variable holds the full name of the variable that was matched + against.

SecRule ARGS pattern setvar:tx.mymatch=%{MATCHED_VAR_NAME}
+...
+SecRule TX:MYMATCH "@eq ARGS:param" deny

MODSEC_BUILD

This variable holds the ModSecurity build number. This variable is + intended to be used to check the build number prior to using a feature + that is available only in a certain build. Example:

SecRule MODSEC_BUILD "!@ge 02050102" skipAfter:12345
+SecRule ARGS "@pm some key words" id:12345,deny,status:500

MULTIPART_CRLF_LF_LINES

This flag variable will be set to 1 whenever a + multi-part request uses mixed line terminators. The + multipart/form-data RFC requires + CRLF sequence to be used to terminate lines. Since + some client implementations use only LF to terminate + lines you might want to allow them to proceed under certain + circumstances (if you want to do this you will need to stop using + MULTIPART_STRICT_ERROR and check each multi-part flag + variable individually, avoiding MULTIPART_LF_LINE). + However, mixing CRLF and LF line + terminators is dangerous as it can allow for evasion. Therefore, in such + cases, you will have to add a check for + MULTIPART_CRLF_LF_LINES.

MULTIPART_STRICT_ERROR

MULTIPART_STRICT_ERROR will be set to + 1 when any of the following variables is also set to + 1: REQBODY_PROCESSOR_ERROR, + MULTIPART_BOUNDARY_QUOTED, + MULTIPART_BOUNDARY_WHITESPACE, + MULTIPART_DATA_BEFORE, + MULTIPART_DATA_AFTER, + MULTIPART_HEADER_FOLDING, + MULTIPART_LF_LINE, + MULTIPART_SEMICOLON_MISSING + MULTIPART_INVALID_QUOTING. Each of these variables + covers one unusual (although sometimes legal) aspect of the request body + in multipart/form-data format. Your policies should + always contain a rule to check either this variable + (easier) or one or more individual variables (if you know exactly what + you want to accomplish). Depending on the rate of false positives and + your default policy you should decide whether to block or just warn when + the rule is triggered.

The best way to use this variable is as in the example + below:

SecRule MULTIPART_STRICT_ERROR "!@eq 0" \
+"phase:2,t:none,log,deny,msg:'Multipart request body \
+failed strict validation: \
+PE %{REQBODY_PROCESSOR_ERROR}, \
+BQ %{MULTIPART_BOUNDARY_QUOTED}, \
+BW %{MULTIPART_BOUNDARY_WHITESPACE}, \
+DB %{MULTIPART_DATA_BEFORE}, \
+DA %{MULTIPART_DATA_AFTER}, \
+HF %{MULTIPART_HEADER_FOLDING}, \
+LF %{MULTIPART_LF_LINE}, \
+SM %{MULTIPART_SEMICOLON_MISSING}, \
+IQ %{MULTIPART_INVALID_QUOTING}'"

The multipart/form-data parser was upgraded in + ModSecurity v2.1.3 to actively look for signs of evasion. Many variables + (as listed above) were added to expose various facts discovered during + the parsing process. The MULTIPART_STRICT_ERROR + variable is handy to check on all abnormalities at once. The individual + variables allow detection to be fine-tuned according to your + circumstances in order to reduce the number of false positives. Detailed + analysis of various evasion techniques covered will be released as a + separated document at a later date.

MULTIPART_UNMATCHED_BOUNDARY

Set to 1 when, during the parsing phase of a + multipart/request-body, ModSecurity encounters what + feels like a boundary but it is not. Such an event may occur when + evasion of ModSecurity is attempted.

The best way to use this variable is as in the example + below:

SecRule MULTIPART_UNMATCHED_BOUNDARY "!@eq 0" \
+"phase:2,t:none,log,deny,msg:'Multipart parser detected a possible unmatched boundary.'"

Change the rule from blocking to logging-only if many false + positives are encountered.

PATH_INFO

Besides passing query information to a script/handler, you can + also pass additional data, known as extra path information, as part of + the URL. Example:

SecRule PATH_INFO "^/(bin|etc|sbin|opt|usr)"

QUERY_STRING

This variable holds form data passed to the script/handler by + appending data after a question mark. Warning: Not URL-decoded. + Example:

SecRule QUERY_STRING "attack"

REMOTE_ADDR

This variable holds the IP address of the remote client. + Example:

SecRule REMOTE_ADDR "^192\.168\.1\.101$"

REMOTE_HOST

If HostnameLookUps are set to On, then this variable will hold the + DNS resolved remote host name. If it is set to Off, then it will hold + the remote IP address. Possible uses for this variable would be to deny + known bad client hosts or network blocks, or conversely, to allow in + authorized hosts. Example:

SecRule REMOTE_HOST "\.evil\.network\org$"

REMOTE_PORT

This variable holds information on the source port that the client + used when initiating the connection to our web server. Example: in this + example, we are evaluating to see if the REMOTE_PORT + is less than 1024, which would indicate that the user is a privileged + user (root).

SecRule REMOTE_PORT "@lt 1024" phase:1,log,pass,setenv:remote_port=privileged

REMOTE_USER

This variable holds the username of the authenticated user. If + there are no password (basic|digest) access controls in place, then this + variable will be empty. Example:

SecRule REMOTE_USER "admin"

Note

This data will not be available in a proxy-mode deployment as the + authentication is not local.

REQBODY_PROCESSOR

Built-in processors are URLENCODED, + MULTIPART, and XML. + Example:

SecRule REQBODY_PROCESSOR "^XML$ chain
+SecRule XML "@validateDTD /opt/apache-frontend/conf/xml.dtd"

REQBODY_PROCESSOR_ERROR

Possible values are 0 (no error) or 1 (error). This variable will + be set by request body processors (typically the + multipart/request-data parser or the XML parser) + when they fail to properly parse a request payload.

Example:

SecRule REQBODY_PROCESSOR_ERROR "@eq 1" deny,phase:2

Note

Your policies must have a rule to check + REQBODY_PROCESSOR_ERROR at the beginning of phase 2. Failure to do so + will leave the door open for impedance mismatch attacks. It is + possible, for example, that a payload that cannot be parsed by + ModSecurity can be successfully parsed by more tolerant parser + operating in the application. If your policy dictates blocking then + you should reject the request if error is detected. When operating in + detection-only mode your rule should alert with high severity when + request body processing fails.

REQBODY_PROCESSOR_ERROR_MSG

Empty, or contains the error message from the processor. + Example:

SecRule REQBODY_PROCESSOR_ERROR_MSG "failed to parse" t:lowercase

REQUEST_BASENAME

This variable holds just the filename part of + REQUEST_FILENAME (e.g. index.php).

Example:

SecRule REQUEST_BASENAME "^login\.php$" phase:2,t:none,t:lowercase

Note

Please note that anti-evasion transformations are not applied to + this variable by default. REQUEST_BASENAME will + recognise both / and \ as path + separators.

REQUEST_BODY

This variable holds the data in the request body (including + POST_PAYLOAD data). REQUEST_BODY + should be used if the original order of the arguments is important + (ARGS should be used in all other cases). + Example:

SecRule REQUEST_BODY "^username=\w{25,}\&password=\w{25,}\&Submit\=login$"

Note

This variable is only available if the + URLENCODED request body processor parsed a request + body. This will occur by default when an + application/x-www-form-urlencoded is detected, or + the URLENCODED request body parser is forced. As of + 2.5.7 it is possible to force the presence of the + REQUEST_BODY variable, but only when there is no + request body processor defined, using the + ctl:forceRequestBodyVariable option in the + REQUEST_HEADERS phase.

REQUEST_COOKIES

This variable is a collection of all of the cookie data. Example: + the following example is using the Ampersand special operator to count + how many variables are in the collection. In this rule, it would trigger + if the request does not include any Cookie headers.

SecRule &REQUEST_COOKIES "@eq 0"

REQUEST_COOKIES_NAMES

This variable is a collection of the cookie names in the request + headers. Example: the following rule will trigger if the JSESSIONID + cookie is not present.

SecRule &REQUEST_COOKIES_NAMES:JSESSIONID "@eq 0"

REQUEST_FILENAME

This variable holds the relative REQUEST_URI + minus the QUERY_STRING part (e.g. /index.php). + Example:

SecRule REQUEST_FILENAME "^/cgi-bin/login\.php$" phase:2,t:none,t:normalisePath

Note

Please note that anti-evasion transformations are not used on + REQUEST_FILENAME by default.

REQUEST_HEADERS

This variable can be used as either a collection of all of the + request headers or can be used to specify individual headers (by using + REQUEST_HEADERS:Header-Name). Example: the first + example uses REQUEST_HEADERS as a collection and is + applying the validateUrlEncoding operator against all + headers.

SecRule REQUEST_HEADERS "@validateUrlEncoding"

Example: the second example is targeting only the + Host header.

SecRule REQUEST_HEADERS:Host "^[\d\.]+$" \
+    "deny,log,status:400,msg:'Host header is a numeric IP address'"

REQUEST_HEADERS_NAMES

This variable is a collection of the names of all of the request + headers. Example:

SecRule REQUEST_HEADERS_NAMES "^x-forwarded-for" \
+    "log,deny,status:403,t:lowercase,msg:'Proxy Server Used'"

REQUEST_LINE

This variable holds the complete request line sent to the server + (including the REQUEST_METHOD and HTTP version data). Example: this + example rule will trigger if the request method is something other than + GET, HEAD, POST or if the HTTP is something other than HTTP/0.9, 1.0 or + 1.1.

SecRule REQUEST_LINE "!(^((?:(?:pos|ge)t|head))|http/(0\.9|1\.0|1\.1)$)" t:none,t:lowercase

REQUEST_METHOD

This variable holds the request method used by the client.

The following example will trigger if the request method is either + CONNECT or TRACE.

SecRule REQUEST_METHOD "^((?:connect|trace))$" t:none,t:lowercase

REQUEST_PROTOCOL

This variable holds the request protocol version information. + Example:

SecRule REQUEST_PROTOCOL "!^http/(0\.9|1\.0|1\.1)$" t:none,t:lowercase

REQUEST_URI

This variable holds the full URL including the + QUERY_STRING data (e.g. /index.php?p=X), however it + will never contain a domain name, even if it was provided on the request + line. It also does not include either the + REQUEST_METHOD or the HTTP version info.

Example:

SecRule REQUEST_URI "attack" phase:1,t:none,t:urlDecode,t:lowercase,t:normalisePath

Note

Please note that anti-evasion transformations are not used on + REQUEST_URI by default.

REQUEST_URI_RAW

Same as REQUEST_URI but will contain the domain + name if it was provided on the request line (e.g. + http://www.example.com/index.php?p=X).

Example:

SecRule REQUEST_URI_RAW "http:/" phase:1,t:none,t:urlDecode,t:lowercase,t:normalisePath

Note

Please note that anti-evasion transformations are not used on + REQUEST_URI_RAW by default.

RESPONSE_BODY

This variable holds the data for the response payload.

Example:

SecRule RESPONSE_BODY "ODBC Error Code"

RESPONSE_CONTENT_LENGTH

Response body length in bytes. Can be available starting with + phase 3 but it does not have to be (as the length of response body is + not always known in advance.) If the size is not known this variable + will contain a zero. If RESPONSE_CONTENT_LENGTH + contains a zero in phase 5 that means the actual size of the response + body was 0.

The value of this variable can change between phases if the body + is modified. For example, in embedded mode + mod_deflate can compress the response body between + phases 4 and 5.

RESPONSE_CONTENT_TYPE

Response content type. Only available starting with phase + 3.

RESPONSE_HEADERS

This variable is similar to the REQUEST_HEADERS variable and can + be used in the same manner. Example:

SecRule RESPONSE_HEADERS:X-Cache "MISS"

Note

This variable may not have access to some headers when running in + embedded-mode. Headers such as Server, Date, Connection and Content-Type + are added during a later Apache hook just prior to sending the data to + the client. This data should be available, however, either during + ModSecurity phase:5 (logging) or when running in proxy-mode.

RESPONSE_HEADERS_NAMES

This variable is a collection of the response header names. + Example:

SecRule RESPONSE_HEADERS_NAMES "Set-Cookie"

Note

Same limitations as RESPONSE_HEADERS with regards to access to + some headers in embedded-mode.

RESPONSE_PROTOCOL

This variable holds the HTTP response protocol information. + Example:

SecRule RESPONSE_PROTOCOL "^HTTP\/0\.9"

RESPONSE_STATUS

This variable holds the HTTP response status code as generated by + Apache. Example:

SecRule RESPONSE_STATUS "^[45]"

Note

This directive may not work as expected in embedded-mode as Apache + handles many of the stock response codes (404, 401, etc...) earlier in + Phase 2. This variable should work as expected in a proxy-mode + deployment.

RULE

This variable provides access to the id, rev, + severity, logdata, and msg fields of the rule that triggered the + action. Only available for expansion in action strings (e.g.setvar:tx.varname=%{rule.id}). Example:

SecRule &REQUEST_HEADERS:Host "@eq 0" "log,deny,setvar:tx.varname=%{rule.id}"

SCRIPT_BASENAME

This variable holds just the local filename part of + SCRIPT_FILENAME. Example:

SecRule SCRIPT_BASENAME "^login\.php$"

Note

This variable is not available in proxy mode.

SCRIPT_FILENAME

This variable holds the full path on the server to the requested + script. (e.g. SCRIPT_NAME plus the server path). Example:

SecRule SCRIPT_FILENAME "^/usr/local/apache/cgi-bin/login\.php$"

Note

This variable is not available in proxy mode.

SCRIPT_GID

This variable holds the group id (numerical value) of the group + owner of the script. Example:

SecRule SCRIPT_GID "!^46$"

Note

This variable is not available in proxy mode.

SCRIPT_GROUPNAME

This variable holds the group name of the group owner of the + script. Example:

SecRule SCRIPT_GROUPNAME "!^apache$"

Note

This variable is not available in proxy mode.

SCRIPT_MODE

This variable holds the script's permissions mode data (numerical + - 1=execute, 2=write, 4=read and 7=read/write/execute). Example: will + trigger if the script has the WRITE permissions set.

SecRule SCRIPT_MODE "^(2|3|6|7)$"

Note

This variable is not available in proxy mode.

SCRIPT_UID

This variable holds the user id (numerical value) of the owner of + the script. Example: the example rule below will trigger if the UID is + not 46 (the Apache user).

SecRule SCRIPT_UID "!^46$"

Note

This variable is not available in proxy mode.

SCRIPT_USERNAME

This variable holds the username of the owner of the script. + Example:

SecRule SCRIPT_USERNAME "!^apache$"

Note

This variable is not available in proxy mode.

SERVER_ADDR

This variable contains the IP address of the server. + Example:

SecRule SERVER_ADDR "^192\.168\.1\.100$"

SERVER_NAME

This variable contains the server's hostname or IP address. + Example:

SecRule SERVER_NAME "hostname\.com$"

Note

This data is taken from the Host header submitted in the client + request.

SERVER_PORT

This variable contains the local port that the web server is + listening on. Example:

SecRule SERVER_PORT "^80$"

SESSION

This variable is a collection, available only after setsid is executed. Example: the following + example shows how to initialize a SESSION collection with setsid, how to + use setvar to increase the session.score values, how to set the + session.blocked variable and finally how to deny the connection based on + the session:blocked value.

SecRule REQUEST_COOKIES:PHPSESSID !^$ chain,nolog,pass
+SecAction setsid:%{REQUEST_COOKIES.PHPSESSID}
+SecRule REQUEST_URI "^/cgi-bin/finger$" \
+    "phase:2,t:none,t:lowercase,t:normalisePath,pass,log,setvar:session.score=+10"
+SecRule SESSION:SCORE "@gt 50" "pass,log,setvar:session.blocked=1"
+SecRule SESSION:BLOCKED "@eq 1" "log,deny,status:403"

SESSIONID

This variable is the value set with setsid. Example:

SecRule SESSIONID !^$ chain,nolog,pass
+SecRule REQUEST_COOKIES:PHPSESSID !^$
+SecAction setsid:%{REQUEST_COOKIES.PHPSESSID}

TIME

This variable holds a formatted string representing the time + (hour:minute:second). Example:

SecRule TIME "^(([1](8|9))|([2](0|1|2|3))):\d{2}:\d{2}$"

TIME_DAY

This variable holds the current date (1-31). Example: this rule + would trigger anytime between the 10th and 20th days of the + month.

SecRule TIME_DAY "^(([1](0|1|2|3|4|5|6|7|8|9))|20)$"

TIME_EPOCH

This variable holds the time in seconds since 1970. + Example:

SecRule TIME_EPOCH "@gt 1000"

TIME_HOUR

This variable holds the current hour (0-23). Example: this rule + would trigger during "off hours".

SecRule TIME_HOUR "^(0|1|2|3|4|5|6|[1](8|9)|[2](0|1|2|3))$"

TIME_MIN

This variable holds the current minute (0-59). Example: this rule + would trigger during the last half hour of every hour.

SecRule TIME_MIN "^(3|4|5)"

TIME_MON

This variable holds the current month (0-11). Example: this rule + would match if the month was either November (10) or December + (11).

SecRule TIME_MON "^1"

TIME_SEC

This variable holds the current second count (0-59). + Example:

SecRule TIME_SEC "@gt 30"

TIME_WDAY

This variable holds the current weekday (0-6). Example: this rule + would trigger only on week-ends (Saturday and Sunday).

SecRule TIME_WDAY "^(0|6)$"

TIME_YEAR

This variable holds the current four-digit year data. + Example:

SecRule TIME_YEAR "^2006$"

TX

Transaction Collection. This is used to store pieces of data, + create a transaction anomaly score, and so on. Transaction variables are + set for 1 request/response cycle. The scoring and evaluation will not + last past the current request/response process. Example: In this + example, we are using setvar to increase the tx.score value by 5 points. + We then have a follow-up run that will evaluate the transactional score + this request and then it will decided whether or not to allow/deny the + request through.

The following is a list of reserved names in the TX + collection:

  • TX:0 - The matching value + when using the @rx or @pm operator with the capture action.

  • TX:1-TX:9 - The captured + subexpression value when using the @rx operator with capturing parens and the + capture action.

SecRule WEBSERVER_ERROR_LOG "does not exist" "phase:5,pass,setvar:tx.score=+5"
+SecRule TX:SCORE "@gt 20" deny,log

USERID

This variable is the value set with setuid. Example:

SecAction setuid:%{REMOTE_USER},nolog
+SecRule USERID "Admin"

WEBAPPID

This variable is the value set with SecWebAppId. Example:

SecWebAppId "WebApp1"
+SecRule WEBAPPID "WebApp1" "chain,log,deny,status:403"
+SecRule REQUEST_HEADERS:Transfer-Encoding "!^$"

WEBSERVER_ERROR_LOG

Contains zero or more error messages produced by the web server. + Access to this variable is in phase:5 (logging). Example:

SecRule WEBSERVER_ERROR_LOG "File does not exist" "phase:5,setvar:tx.score=+5"

XML

Can be used standalone (as a target for + validateDTD and validateSchema) or + with an XPath expression parameter (which makes it a valid target for + any function that accepts plain text). Example using XPath:

SecDefaultAction log,deny,status:403,phase:2
+SecRule REQUEST_HEADERS:Content-Type ^text/xml$ \
+    phase:1,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML
+SecRule REQBODY_PROCESSOR "!^XML$" skipAfter:12345
+SecRule XML:/employees/employee/name/text() Fred
+SecRule XML:/xq:employees/employee/name/text() Fred \
+    id:12345,xmlns:xq=http://www.example.com/employees

The first XPath expression does not use namespaces. It would match + against payload such as this one:

<employees>
+    <employee>
+        <name>Fred Jones</name>
+        <address location="home">
+            <street>900 Aurora Ave.</street>
+            <city>Seattle</city>
+            <state>WA</state>
+            <zip>98115</zip>
+        </address>
+        <address location="work">
+            <street>2011 152nd Avenue NE</street>
+            <city>Redmond</city>
+            <state>WA</state>
+            <zip>98052</zip>
+        </address>
+        <phone location="work">(425)555-5665</phone>
+        <phone location="home">(206)555-5555</phone>
+        <phone location="mobile">(206)555-4321</phone>
+    </employee>
+</employees>

The second XPath expression does use namespaces. It would match + the following payload:

<xq:employees xmlns:xq="http://www.example.com/employees">
+    <employee>
+        <name>Fred Jones</name>
+        <address location="home">
+            <street>900 Aurora Ave.</street>
+            <city>Seattle</city>
+            <state>WA</state>
+            <zip>98115</zip>
+        </address>
+        <address location="work">
+            <street>2011 152nd Avenue NE</street>
+            <city>Redmond</city>
+            <state>WA</state>
+            <zip>98052</zip>
+        </address>
+        <phone location="work">(425)555-5665</phone>
+        <phone location="home">(206)555-5555</phone>
+        <phone location="mobile">(206)555-4321</phone>
+    </employee>
+</xq:employees>

Note the different namespace used in the second example.

To learn more about XPath we suggest the following + resources:

\ No newline at end of file diff --git a/doc/index.html b/doc/index.html new file mode 100644 index 0000000..2ba4b12 --- /dev/null +++ b/doc/index.html @@ -0,0 +1,35 @@ + + + + ModSecurity for Apache Reference + + + + +
+
ModSecurity
+
+ +
+ +
+ +

ModSecurity for Apache Documentation

+ +

Version 2.5.11 (Nov 4, 2009)

+ + + +
+ + + + + diff --git a/doc/migration-matrix.html b/doc/migration-matrix.html new file mode 100644 index 0000000..70d908a --- /dev/null +++ b/doc/migration-matrix.html @@ -0,0 +1,74 @@ + + + ModSecurity Migration Matrix

ModSecurity Migration Matrix

Version 1.0 / (April 10, 2007)


Migration from 1.x to 2.x

If you are already using an older version of ModSecurity and want to upgrade/migrate your existing custom rules, you will need to ensure that you properly translate all of your Directives to their corresponding 2.0 counterparts. Some directives have simply changed names, however some directives actually behave differently so it is important that you also review the entire 2.0 Reference Manual. +The migration matrix show below should help you to translate ModSecurity 1.X directives to the 2.0 values. There are also some notes that provide additional information is a directive significantly changed how it operates. +

Feature/CapabilityModSecurity 1.xModSecurity 2.xNotesHow To Upgrade
Apache Version SupportedApache 1.x/2.xApache 2.x OnlyModSecurity 2.0 will only work with Apache 2.x and not the older 1.3 version.If you are mainly an Apache 1.3 shop and/or you have other web servers that you want to protect (such as IIS) an alternative solution is to deploy an Apache 2.x reverse proxy server and implement ModSecurity 2.x on it.
InstallationCan be installed as either a DSO module or as a statically compiled module.Can currently only be installed as a DSO module.In 1.x, you could use apxs directly, while in 2.x you must use the provided Makefile.If you can not use DSOs in your current Apache configs, you may look at implementing a front-end Apache reverse proxy server.
Configuration - IfModuleApache 1.x - <IfModule mod_security.c> + +Apache 2.x - <IfModule security_module><IfModule security2_module>The syntax of using IfModule has changed between Apache 1.x and 2.xMake sure that any existing <IfModule> directives uses the correct syntax.
Processing Phases Supported25ModSecurity 1.x supports:
  • Inbound - which corresponds to current Mod 2.x Request Body phase and the Apache “fixups” phase.

  • Outbound - which corresponds to current Mod 2.x Response Body phase and just after the Apache “response” processing phase.

ModSecurity 2.x supports:
  • Request Headers – which corresponds with the Apache “post-read-request” phase.

  • Request Body – which corresponds with the Apache “fixups” phase.

  • Response Headers – which corresponds to the Apache “response” phase.

  • Response Body – which corresponds to just after the Apache “response” phase.

  • Logging - which is the Apache logging phase.

If you are translating existing 1.x rules (SecFilter/SecFilterSelective) then you should use phase:2 in the new rule syntax. Translate existing OUTPUT rules to run in phase:4.
Directive to turn On/Off the Rule EngineSecFilterEngineSecRuleEngine +ctl:ruleEngine=
  • 1.x – values were On, Off and DynamicOnly and was a Global directive.

  • 2.x - values are On, Off or DetectionOnly.

  • 2.x – the “ctl” action can control the RuleEngine dynamically for individual requests.

Replace SecFilterEngine with SecRuleEngine. The DynamicOnly mode is not supported in ModSecurity 2.x because it was sometimes difficult for ModSecurity to determine if a particular request was dynamic in nature or not. Use of AddType vs. AddHandler would cause problems. Since this logic relies on the internal (and not entirely documented) workings of Apache and on the chosen configuration it also makes it somewhat unpredictable.
Directive to handle the Audit EngineSecAuditEngine On, Off, RelevantOnly, DynamicOrRelevantSecAuditEngine On, Off, RelevantOnlyIn 2.x, the DynamicOrRelevant option was discontinued.If you are using DynamicOrRelevant then switch it to RelevantOnly.
Default Rule ActionSecFilterDefaultActionSecDefaultAction
  • 1.x – SecFilterDefaultAction could be used anywhere in the config and it would be picked up by all rules.

  • 2.x – SecDefaultAction must come before rules and be specified in each context. The default setting for this directive (if it is not specified otherwise) is – +SecDefaultAction phase:2,log,deny,status:403,\

    t:lowercase,t:replaceNulls,\

    t:compressWhitespace

Replace SecFilterDefaultAction with SecDefaultAction. Optionally, you can group rules together where you would like to use the same action and then specify a SecDefaultAction line before each group. + +Also keep in mind that while most actions specified on individual rules will supersede those specified in SecDefaultAction, transformation functions are additive. So, if you specify a “t:base64Decode” transformation function to a rule, it will be added after the lowercase, replaceNulls and compressWhitespace transformation functions.
Debug LoggingSecFilterDebugLog +SecFilterDebugLogLevelSecDebugLog +SecDebugLogLevelName change only.Change the names of these directives to their 2.x counterparts.
Rule Directive(s)SecFilter +SecFilterSelectiveSecRule
  • In Mod 1.x, SecFilter and SecFilterSelective were case insensitive.

  • In Mod 2.x, the case of data is not altered unless the lowercase transformation funce is used. +SecRule has essentially the same rule syntax as SecFilterSelective.

Replace SecFilterSelective with SecRule and make sure to translate the variable tested according to this list. +Replace any SecFilter with a new SecRule directive. You will need to specify a new Variable location and a phase. You can optionally specify a disruptive action, otherwise it will be inherited from a previous SecDefaultAction. +
Rule ExceptionsWhitelist approach – use pass, allow actions +False Positive Approach – use SecFilterRemoveWhitelist approach – use pass, allow and ctl actions. +False Positive Approach – use SecRuleRemoveById and Apache Scope contextIn Mod 2.x, using the “allow” action may not be enough to truly let a request through as “allow” only applies to the current processing phase. This means that rules in subsequent phases may act on the request. This is why you need to also use the “ctl:ruleEngine=Off” action if you really want to let a request through.See Blog post on handling false positives and creating custom rules - http://www.modsecurity.org/blog/archives/2007/02/handling_false.html
Directive to control rule inheritance to Apache Scope locations (Virtual Hosts, Location, Directory)SecFilterInheritanceSecRuleInheritanceThe best use of this directive is when you want to start with a “clean slate” so you can use SecRuleInheritance Off and then specify your new rule sets. +Note – Rule Inheritance does not work across Apache Scope directives (such as Vhosts, Location and Directory directives). This means that you can not use SecRuleInheritance On to inherit a SecDefaultAction directive within these new contexts. This is an issue with the way that Apache inherits contexts. It is for this reason that we recommend that you specify new SecDefaultAction directives within each Apache scope location that you create.Translate any existing “SecFilterInheritance Off” rules directly to “SecRuleInheritance Off”. +Then replace any “SecFilterInheritance On” directives inside Apache Scope context locations with a new SecDefaultAction directive and then import the rules that you want with standard Apache Include directives.
Ability to manage rules in Apache Scope locationsSecFilterImport +SecFilterRemoveSecRuleRemoveById +SecRuleRemoveByMsgSecFilterRemove is now SecRuleRemoveById or SecRuleRemoveByMsg. SecFilterImport is no longer supported.Change all of your existing SecFilterRemove rules to SecRuleRemoveById. For any existing SecFilterImport rules, you will need to either copy the rule into the context or use an Apache Include Directive to include entire files (such as including the Core Rules files).
Ability to verify URL/UTF8 EncodingsSecFilterCheckURLEncoding +SecFilterCheckUnicodeEncoding @validateUrlEncoding +@validateUtf8Encoding In Mod 1.x, these were Global Directives and in Mod 2.x they are Operators that can be applied selectively to each rule.Add the rules that will do exactly the same as the directives
Ability to enforce a Byte Range (allowed character set)SecFilterForceByteRange@validateByteRangeIn Mod 1.x, this was a Global Directive and in Mod 2.x it is an Operator that can be applied selectively to each rule. +In Mod 1.x, this directive did not check POST payloads when multipart/form-data encoding was used.You can now add @validateByteRange operators to individual rules. This helps if you have differences in allowed character sets for different portions of the web application.
Ability to Normalize/Transform Request DataModSecurity 1.x automatically applied the following transformations:
  • On Windows only, convert \ to /

  • Reduce /./ to /

  • Reduce // to /

  • Decode URL-encoded characters

  • Converts Null Bytes to Space character

  • base64Decode

  • base64Encode

  • compressWhitespace

  • escapeSeqDecode

  • hexDecode

  • hexEncode

  • htmlEntityDecode

  • lowercase

  • md5

  • none

  • normalisePath

  • normalisePathWin

  • removeNulls

  • removeWhitespace

  • replaceComments

  • replaceNulls

  • urlDecode

  • urlDecodeUni

  • urlEncode

  • sha1

In Mod 1.x, the normalization functions were implicit and you could not control them. In Mod 2.x, not normalization is done by default. There are now “Transformation Functions” that allow you to selectively apply normalizations and other features.You should add the appropriate transformation functions to either SecDefaultAction directive or each individual rule. See the Core Rules files for examples. +Keep in mind that transformation functions are inherited from parent SecDefaultAction directives. Care should be taken to ensure that RegEx patterns match the data after transformation functions are applied. In order to avoid possible unwanted inherited transformation functions, use “t:none” to either not apply any transformation functions or you can then specify specific transformation functions after “t:none”.
Ability to specify an arbitrary Request Header in a ruleHEADER_headername +HTTP_headernameREQUEST_HEADERS REQUEST_HEADERS:headername +REQUEST_HEADERS:/RegEx/The HTTP_headername syntax has been superseded by the new REQUEST_HEADERS:headername syntax and will not be supported in future releases. The advantage to using the new syntax is that you can also use RegEx in the headername portion.Translate any existing HTTP_headername directives to REQUEST_HEADERS:headername. Also consider consolidating header checks by using Regular Expressions in the header name portion of the Variable.
Variable/Location for the entire URL Request LineTHE_REQUESTREQUEST_LINEFunctions the same. The variable includes the Request Method, URI and HTTP version data.Translate any existing THE_REQUEST directives to REQUEST_LINE directives.
Variable/Location for ArgumentsARG_nameARGS:name +ARGS:/RegEx/Similar to the HTTP_headername situation, the advantage of the new syntax is the ability to use RegEx in the argument name.Translate any existing ARG_name directives to ARGS:name directives.
Accessing Request BodiesSecFilterScanPOST +POST_PAYLOADSecRequestBodyAccess +Phase:2 +REQUEST_BODYIn 2.x, the directive is now called SecRequestBodyAccess and it is more flexible than SecFilterScanPOST as it is able to inspect all request bodies (such as PUT and XML, etc…) and not just POST payloads.Replace the existing SecFilterScanPOST directive with SecRequestBodyAccess. +For individual rules where you want to inspect the request bodies, you must specify REQUEST_BODY as the variable and you also must ensure that it is running in phase:2 (by either an inherited SecDefaultAction setting or by explicitly specifying the phase within the rule action).
Ability to disable POST/Request buffering dynamicallyMODSEC_NOPOSTBUFFERINGctl:requestBodyAccess=OffIn 2.x, you can use the ctl action to turn on/off request body access on a per rule basis.Take any existing entries in the httpd.conf file that set the MODSEC_NOPOSTBUFFERING Env variable and translate them to Mod 2.x rules.
Accessing CookiesCOOKIES +COOKIES_COUNT +COOKIES_NAMES +COOKIES_VALUES +COOKIE_nameREQUEST_HEADERS:Cookie +REQUEST_COOKIES_NAMES REQUEST_COOKIES_NAMES:name +REQUEST_COOKIES_NAMES:/RegEx/ +REQUEST_COOKIES +REQUEST_COOKIES:name REQUEST_COOKIES:/RegEx/ In 2.x, you can use the “&” character to “count” the number of variables. +While there are different ways to access request cookies, the main difference between them are that REQUEST_HEADERS:Cookie will include all of the “raw” Cookie data while any of the REQUEST_COOKIES variable values are parsed.Translate rules as follows – +Mod 1.x -> Mod 2.x +COOKIES -> REQUEST_COOKIES +COOKIES_COUNT -> &REQUEST_COOKIES +COOKIES_NAMES -> REQUEST_COOKIES_NAMES COOKIES_VALUES -> REQUEST_COOKIES +COOKIE_name -> REQUEST_COOKIES:name
Counting VariablesARGS_COUNT +COOKIES_COUNT +HEADERS_COUNT +FILES_COUNT&ARGS +&REQUEST_COOKIES &REQUEST_HEADERS +&FILESIn 2.x, prepending the “&” character will count the number of variables. Example – +1.x – HEADERS_COUNT +2.x - &REQUEST_HEADERSTranslate existing 1.x rules as listed.
Accessing HTTP Status CodeOUTPUT_STATUSRESPONSE_STATUS +Phase:3In 2.x, you need to specify both the RESPONSE_STATUS variable and phase:3 with the rule.Translate any existing 1.x OUTPUT STATUS rules to use RESPONSE_STATUS and phase:3.
Accessing Response Bodies/Post PayloadsSecFilterScanOutput +SecFilterOutputMimeTypes +OUTPUTSecResponseBodyAccess +SecResponseBodyMimeTypes +RESPONSE_BODY +Phase:4In 1.x, neither skipnext nor chain could be used on the OUTPUT location. +In 2.x, both actions can be used on RESPONSE_BODYTranslate directives/rules as follows – +Mod 1.x -> Mod 2.x +SecFilterScanOutput -> SecResponseBodyAccess +SecFilterOutputMimeTypes -> SecResponseBodyMimeTypes +OUTPUT -> RESPONSE_BODY/Phase:4
Cookie NormalizationSecFilterCookieFormat +SecFilterNormalizeCookiesSecCookieFormatSecFilterNormalizeCookies is no longer supported as Mod 2.x transformation functions can now be used to normalize all Variables including Cookie data.Change SecFilterCookieFormat to SecCookieFormat. +When specifying Cookie variables, then apply the applicable transformation functions in the action field of the rule.
Ability to skip rulesskipnextskipIn Mod 2.x – skip takes into account chained rulesets and treats them as 1 rule. +In Mod 1.x – skipnext treated each rule directive as an individual rule regardless of whether or not they were tied together as a chained ruleset.Translate all skipnext rules to skip, however make sure to factor in any chained rulesets that may follow and adjust the skip number accordingly.
Adding/Removing Audit Log Data on a per rule basislogpartsclt:auditLogParts=The rules function the same.Translate any existing logparts actions to the ctl:auditLogParts equivalent.
Inspecting uploaded filesSecUploadApproveScript@inspectFile +FILES_TMPNAMESThe main difference here is that now @inspectFile is an Operator vs. a global Directive. This means that you can apply @inspectFile to individual rules and use different scripts as appropriate. +Also, the return codes are now reversed – +In 1.x, a return code of “1” means that the file would be allowed. +In 2.x, a return code of “1” means that the file would be denied. In order to scan/inspect uploaded files in 2.x, you need to create specific rules that use the FILES_TMPNAMES variable (as these are the names of the files that are temporarily stored on disk) and then use the @inspectFile Operator on each rule. +Also, make sure to swap your return codes in existing scripts as mentioned in the notes column.
Memory limits for uploaded filesSecUploadInMemoryLimitSecRequestBodyInMemoryLimitThese two directives function the same.Change the SecUploadInMemoryLimit directive to SecRequestBodyInMemoryLimit.
diff --git a/doc/migration-matrix.xml b/doc/migration-matrix.xml new file mode 100644 index 0000000..04dd83a --- /dev/null +++ b/doc/migration-matrix.xml @@ -0,0 +1,814 @@ + +
+ ModSecurity Migration Matrix + + + Version 1.0 / (April 10, 2007) + + + 2004-2009 + + Breach Security, Inc. (http://www.breach.com) + + + +
+ Migration from 1.x to 2.x + +
+ If you are already using an older version of ModSecurity and want + to upgrade/migrate your existing custom rules, you will need to ensure + that you properly translate all of your Directives to their + corresponding 2.0 counterparts. Some directives have simply changed + names, however some directives actually behave differently so it is + important that you also review the entire 2.0 Reference Manual. The + migration matrix show below should help you to translate ModSecurity 1.X + directives to the 2.0 values. There are also some notes that provide + additional information is a directive significantly changed how it + operates. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Feature/Capability + + ModSecurity 1.x + + ModSecurity 2.x + + Notes + + How To Upgrade +
+ Apache Version Supported + Apache 1.x/2.xApache 2.x OnlyModSecurity 2.0 will only work with Apache 2.x and not the older + 1.3 version.If you are mainly an Apache 1.3 shop and/or you have other web + servers that you want to protect (such as IIS) an alternative + solution is to deploy an Apache 2.x reverse proxy server and + implement ModSecurity 2.x on it.
+ Installation + Can be installed as either a DSO module or as a statically + compiled module.Can currently only be installed as a DSO module.In 1.x, you could use apxs directly, while in 2.x you must use + the provided Makefile.If you can not use DSOs in your current Apache configs, you may + look at implementing a front-end Apache reverse proxy server.
+ Configuration - IfModule + Apache 1.x - <IfModule mod_security.c> Apache 2.x - + <IfModule security_module><IfModule security2_module>The syntax of using IfModule has changed between Apache 1.x and + 2.xMake sure that any existing <IfModule> directives uses the + correct syntax.
+ Processing Phases Supported + 25ModSecurity 1.x supports: + + Inbound - which corresponds to current Mod 2.x Request + Body phase and the Apache “fixups” phase. + + + + Outbound - which corresponds to current Mod 2.x Response + Body phase and just after the Apache “response” processing + phase. + + ModSecurity 2.x supports: + + Request Headers – which corresponds with the Apache + “post-read-request” phase. + + + + Request Body – which corresponds with the Apache + “fixups” phase. + + + + Response Headers – which corresponds to the Apache + “response” phase. + + + + Response Body – which corresponds to just after the + Apache “response” phase. + + + + Logging - which is the Apache logging phase. + + If you are translating existing 1.x rules + (SecFilter/SecFilterSelective) then you should use phase:2 in the + new rule syntax. Translate existing OUTPUT rules to run in + phase:4.
+ Directive to turn On/Off the Rule + Engine + SecFilterEngineSecRuleEngine ctl:ruleEngine= + + + 1.x – values were On, Off and DynamicOnly and was a + Global directive. + + + + 2.x - values are On, Off or DetectionOnly. + + + + 2.x – the “ctl” action can control the RuleEngine + dynamically for individual requests. + + + + + Replace SecFilterEngine with SecRuleEngine. The DynamicOnly mode + is not supported in ModSecurity 2.x because it was sometimes + difficult for ModSecurity to determine if a particular request was + dynamic in nature or not. Use of AddType vs. AddHandler would cause + problems. Since this logic relies on the internal (and not entirely + documented) workings of Apache and on the chosen configuration it + also makes it somewhat unpredictable.
+ Directive to handle the Audit + Engine + SecAuditEngine On, Off, RelevantOnly, DynamicOrRelevantSecAuditEngine On, Off, RelevantOnlyIn 2.x, the DynamicOrRelevant option was discontinued.If you are using DynamicOrRelevant then switch it to + RelevantOnly.
+ Default Rule Action + SecFilterDefaultActionSecDefaultAction + + + 1.x – SecFilterDefaultAction could be used anywhere in + the config and it would be picked up by all rules. + + + + 2.x – SecDefaultAction must come before rules and be + specified in each context. The default setting for this + directive (if it is not specified otherwise) is – + SecDefaultAction + phase:2,log,deny,status:403,\ + + + t:lowercase,t:replaceNulls,\ + + + + t:compressWhitespace + + + + + + Replace SecFilterDefaultAction with SecDefaultAction. + Optionally, you can group rules together where you would like to use + the same action and then specify a SecDefaultAction line before each + group. Also keep in mind that while most actions specified on + individual rules will supersede those specified in SecDefaultAction, + transformation functions are additive. So, if you specify a + “t:base64Decode” transformation function to a rule, it will be added + after the lowercase, replaceNulls and compressWhitespace + transformation functions.
+ Debug Logging + SecFilterDebugLog SecFilterDebugLogLevelSecDebugLog SecDebugLogLevelName change only.Change the names of these directives to their 2.x + counterparts.
+ Rule Directive(s) + SecFilter SecFilterSelectiveSecRule + + + In Mod 1.x, SecFilter and SecFilterSelective were case + insensitive. + + + + In Mod 2.x, the case of data is not altered unless the + lowercase transformation funce is used. SecRule has + essentially the same rule syntax as SecFilterSelective. + + + Replace SecFilterSelective with SecRule and make sure to + translate the variable tested according to this list. Replace any + SecFilter with a new SecRule directive. You will need to specify a + new Variable location and a phase. You can optionally specify a + disruptive action, otherwise it will be inherited from a previous + SecDefaultAction.
+ Rule Exceptions + Whitelist approach – use pass, allow actions False Positive + Approach – use SecFilterRemoveWhitelist approach – use pass, allow and ctl actions. False + Positive Approach – use SecRuleRemoveById and Apache Scope + contextIn Mod 2.x, using the “allow” action may not be enough to truly + let a request through as “allow” only applies to the current + processing phase. This means that rules in subsequent phases may act + on the request. This is why you need to also use the + “ctl:ruleEngine=Off” action if you really want to let a request + through.See Blog post on handling false positives and creating custom + rules - + http://www.modsecurity.org/blog/archives/2007/02/handling_false.html
+ Directive to control rule inheritance to + Apache Scope locations (Virtual Hosts, Location, + Directory) + SecFilterInheritanceSecRuleInheritanceThe best use of this directive is when you want to start with a + “clean slate” so you can use SecRuleInheritance Off and then specify + your new rule sets. Note – Rule Inheritance does not work across + Apache Scope directives (such as Vhosts, Location and Directory + directives). This means that you can not use SecRuleInheritance On + to inherit a SecDefaultAction directive within these new contexts. + This is an issue with the way that Apache inherits contexts. It is + for this reason that we recommend that you specify new + SecDefaultAction directives within each Apache scope location that + you create.Translate any existing “SecFilterInheritance Off” rules directly + to “SecRuleInheritance Off”. Then replace any “SecFilterInheritance + On” directives inside Apache Scope context locations with a new + SecDefaultAction directive and then import the rules that you want + with standard Apache Include directives.
+ Ability to manage rules in Apache Scope + locations + SecFilterImport SecFilterRemoveSecRuleRemoveById SecRuleRemoveByMsgSecFilterRemove is now SecRuleRemoveById or SecRuleRemoveByMsg. + SecFilterImport is no longer supported.Change all of your existing SecFilterRemove rules to + SecRuleRemoveById. For any existing SecFilterImport rules, you will + need to either copy the rule into the context or use an Apache + Include Directive to include entire files (such as including the + Core Rules files).
+ Ability to verify URL/UTF8 + Encodings + SecFilterCheckURLEncoding SecFilterCheckUnicodeEncoding @validateUrlEncoding @validateUtf8Encoding In Mod 1.x, these were Global Directives and in Mod 2.x they are + Operators that can be applied selectively to each rule.Add the rules that will do exactly the same as the + directives
+ Ability to enforce a Byte Range (allowed + character set) + SecFilterForceByteRange@validateByteRangeIn Mod 1.x, this was a Global Directive and in Mod 2.x it is an + Operator that can be applied selectively to each rule. In Mod 1.x, + this directive did not check POST payloads when multipart/form-data + encoding was used.You can now add @validateByteRange operators to individual + rules. This helps if you have differences in allowed character sets + for different portions of the web application.
+ Ability to Normalize/Transform Request + Data + ModSecurity 1.x automatically applied the following + transformations: + + On Windows only, convert \ to / + + + + Reduce /./ to / + + + + Reduce // to / + + + + Decode URL-encoded characters + + + + Converts Null Bytes to Space character + + + + + base64Decode + + + + base64Encode + + + + compressWhitespace + + + + escapeSeqDecode + + + + hexDecode + + + + hexEncode + + + + htmlEntityDecode + + + + lowercase + + + + md5 + + + + none + + + + normalisePath + + + + normalisePathWin + + + + removeNulls + + + + removeWhitespace + + + + replaceComments + + + + replaceNulls + + + + urlDecode + + + + urlDecodeUni + + + + urlEncode + + + + sha1 + + + + + In Mod 1.x, the normalization functions were implicit and you + could not control them. In Mod 2.x, not normalization is done by + default. There are now “Transformation Functions” that allow you to + selectively apply normalizations and other features.You should add the appropriate transformation functions to + either SecDefaultAction directive or each individual rule. See the + Core Rules files for examples. Keep in mind that transformation + functions are inherited from parent SecDefaultAction directives. + Care should be taken to ensure that RegEx patterns match the data + after transformation functions are applied. In order to avoid + possible unwanted inherited transformation functions, use “t:none” + to either not apply any transformation functions or you can then + specify specific transformation functions after “t:none”.
+ Ability to specify an arbitrary Request + Header in a rule + HEADER_headername HTTP_headernameREQUEST_HEADERS REQUEST_HEADERS:headername + REQUEST_HEADERS:/RegEx/The HTTP_headername syntax has been superseded by the new + REQUEST_HEADERS:headername syntax and will not be supported in + future releases. The advantage to using the new syntax is that you + can also use RegEx in the headername portion.Translate any existing HTTP_headername directives to + REQUEST_HEADERS:headername. Also consider consolidating header + checks by using Regular Expressions in the header name portion of + the Variable.
+ Variable/Location for the entire URL Request + Line + THE_REQUESTREQUEST_LINEFunctions the same. The variable includes the Request Method, + URI and HTTP version data.Translate any existing THE_REQUEST directives to REQUEST_LINE + directives.
+ Variable/Location for Arguments + ARG_nameARGS:name ARGS:/RegEx/Similar to the HTTP_headername situation, the advantage of the + new syntax is the ability to use RegEx in the argument name.Translate any existing ARG_name directives to ARGS:name + directives.
+ Accessing Request Bodies + SecFilterScanPOST POST_PAYLOADSecRequestBodyAccess Phase:2 REQUEST_BODYIn 2.x, the directive is now called SecRequestBodyAccess and it + is more flexible than SecFilterScanPOST as it is able to inspect all + request bodies (such as PUT and XML, etc…) and not just POST + payloads.Replace the existing SecFilterScanPOST directive with + SecRequestBodyAccess. For individual rules where you want to inspect + the request bodies, you must specify REQUEST_BODY as the variable + and you also must ensure that it is running in phase:2 (by either an + inherited SecDefaultAction setting or by explicitly specifying the + phase within the rule action).
+ Ability to disable POST/Request buffering + dynamically + MODSEC_NOPOSTBUFFERINGctl:requestBodyAccess=OffIn 2.x, you can use the ctl action to turn on/off request body + access on a per rule basis.Take any existing entries in the httpd.conf file that set the + MODSEC_NOPOSTBUFFERING Env variable and translate them to Mod 2.x + rules.
+ Accessing Cookies + COOKIES COOKIES_COUNT COOKIES_NAMES COOKIES_VALUES + COOKIE_nameREQUEST_HEADERS:Cookie REQUEST_COOKIES_NAMES + REQUEST_COOKIES_NAMES:name REQUEST_COOKIES_NAMES:/RegEx/ + REQUEST_COOKIES REQUEST_COOKIES:name REQUEST_COOKIES:/RegEx/ In 2.x, you can use the “&” character to “count” the number + of variables. While there are different ways to access request + cookies, the main difference between them are that + REQUEST_HEADERS:Cookie will include all of the “raw” Cookie data + while any of the REQUEST_COOKIES variable values are parsed.Translate rules as follows – Mod 1.x -> Mod 2.x COOKIES -> + REQUEST_COOKIES COOKIES_COUNT -> &REQUEST_COOKIES + COOKIES_NAMES -> REQUEST_COOKIES_NAMES COOKIES_VALUES -> + REQUEST_COOKIES COOKIE_name -> REQUEST_COOKIES:name
+ Counting Variables + ARGS_COUNT COOKIES_COUNT HEADERS_COUNT FILES_COUNT&ARGS &REQUEST_COOKIES &REQUEST_HEADERS + &FILESIn 2.x, prepending the “&” character will count the number + of variables. Example – 1.x – HEADERS_COUNT 2.x - + &REQUEST_HEADERSTranslate existing 1.x rules as listed.
+ Accessing HTTP Status Code + OUTPUT_STATUSRESPONSE_STATUS Phase:3In 2.x, you need to specify both the RESPONSE_STATUS variable + and phase:3 with the rule.Translate any existing 1.x OUTPUT STATUS rules to use + RESPONSE_STATUS and phase:3.
+ Accessing Response Bodies/Post + Payloads + SecFilterScanOutput SecFilterOutputMimeTypes OUTPUTSecResponseBodyAccess SecResponseBodyMimeTypes RESPONSE_BODY + Phase:4In 1.x, neither skipnext nor chain could be used on the OUTPUT + location. In 2.x, both actions can be used on RESPONSE_BODYTranslate directives/rules as follows – Mod 1.x -> Mod 2.x + SecFilterScanOutput -> SecResponseBodyAccess + SecFilterOutputMimeTypes -> SecResponseBodyMimeTypes OUTPUT -> + RESPONSE_BODY/Phase:4
+ Cookie Normalization + SecFilterCookieFormat SecFilterNormalizeCookiesSecCookieFormatSecFilterNormalizeCookies is no longer supported as Mod 2.x + transformation functions can now be used to normalize all Variables + including Cookie data.Change SecFilterCookieFormat to SecCookieFormat. When specifying + Cookie variables, then apply the applicable transformation functions + in the action field of the rule.
+ Ability to skip rules + skipnextskipIn Mod 2.x – skip takes into account chained rulesets and treats + them as 1 rule. In Mod 1.x – skipnext treated each rule directive as + an individual rule regardless of whether or not they were tied + together as a chained ruleset.Translate all skipnext rules to skip, however make sure to + factor in any chained rulesets that may follow and adjust the skip + number accordingly.
+ Adding/Removing Audit Log Data on a per rule + basis + logpartsclt:auditLogParts=The rules function the same.Translate any existing logparts actions to the ctl:auditLogParts + equivalent.
+ Inspecting uploaded files + SecUploadApproveScript@inspectFile FILES_TMPNAMESThe main difference here is that now @inspectFile is an Operator + vs. a global Directive. This means that you can apply @inspectFile + to individual rules and use different scripts as appropriate. Also, + the return codes are now reversed – In 1.x, a return code of “1” + means that the file would be allowed. In 2.x, a return code of “1” + means that the file would be denied. In order to scan/inspect uploaded files in 2.x, you need to + create specific rules that use the FILES_TMPNAMES variable (as these + are the names of the files that are temporarily stored on disk) and + then use the @inspectFile Operator on each rule. Also, make sure to + swap your return codes in existing scripts as mentioned in the notes + column.
+ Memory limits for uploaded files + SecUploadInMemoryLimitSecRequestBodyInMemoryLimitThese two directives function the same.Change the SecUploadInMemoryLimit directive to + SecRequestBodyInMemoryLimit.
+
+
+
diff --git a/doc/modsecurity-reference.css b/doc/modsecurity-reference.css new file mode 100644 index 0000000..1c89c88 --- /dev/null +++ b/doc/modsecurity-reference.css @@ -0,0 +1,102 @@ + +body { + font: 13px/20px Arial, Helvetica; + background-color: white; + width: 800px; +} + +/* TEXT */ + +PRE { + font-size: 100%; + padding: 5px; + border-style: solid; + border-width: 1px; + border-color: #CCCCCC; + background-color: #F5F8FA; +} + +p, td, tr, li, ol, ul { + /*font-family: Trebuchet MS, Verdana, Tahoma, Arial, Helvetica, Geneva;*/ + /*font-family: Arial, Helvetica; + font-size: 14px; + line-height: 24px;*/ +} + +.copyright { + font-size: 10px; +} + +h1 { + padding-top: 40px; + font: 24px/30px Arial, Helvetica; + font-weight: bold; +} + +h2 { + font: 20px/30px Arial, Helvetica; + font-weight: bold; +} + +h3 { + padding-top: 15px; + font: 16px/10px Arial, Helvetica; + font-weight: bold; +} + +h4 { + padding-top: 15px; + font: 14px/10px Arial, Helvetica; + font-weight: bold; +} + + + + +.header { + background-color: #00448B; + border-top: 6px solid #002B6E; + height: 84px; + vertical-align: top; + padding-left: 20px; + padding-top: 10px; +} + +.topNavigation { + background-color: #EEEEEE; + background: url('g/topnav-background.gif'); + height: 23px; + line-height: 12px; + vertical-align: top; + padding-left: 12px; + padding-top: 5px; +} + +.topLink, A.topLink:link, A.topLink:active, A.topLink:visited { + font-weight: bold; + color: black; + text-decoration: none; + padding-left: 8px; + padding-right: 8px; +} + +A.topLink:hover { + color: #BB0000; +} + +#navheader td { + font-size: 12px; +} + +#navfooter td { + font-size: 12px; +} + +h3.title { + margin-top: 0px; +} + +.note { + border-top: 1px solid #CCCCCC; + border-bottom: 1px solid #CCCCCC; +} diff --git a/doc/modsecurity.gif b/doc/modsecurity.gif new file mode 100644 index 0000000000000000000000000000000000000000..76f5ca1632677cb890e0a5ad57cf47cb8a4a6c8d GIT binary patch literal 2585 zcmV+!3g-1kNk%w1VR!%}0OkMyMS8T;+UNWG{a1IVdy~1WyVD0Zeqx@~4m^P!N{eWu z+9FMj7(|8^LWB}Nfh<&!G+UL8qQhB|$|qKpQi;NvtjcVu-t+bNJ#npVhq6Rxo$c`T zLUys-;_OO*x;kyDV4KktK!Rze+>)imRgK2z?DH^Tp62TExy0F|w9hJ9nIlkm!FW4o`jp2nVgKB zq^Y5Xm8+(xjgO_8v$Kh)u)Ds!qmsX!s<67EtCPvKoXpL&uf)R3$-S!6vX{oYmAI#* z&bZvK!l91m;Mvx|+RCY{*wxL%^V;^HuJyjove%iC0NcSUc8j1fWRs8y)Fn?|EL+tW z4ntRt*D!AL^tB3x1c66$qb#ngn5&qk227Z6`E*ekvt!2^vTS&z$%qjI^!bBn5Z|;- z45V=2aAe9Elk4cUqIK?8J5w7SAt=zN&z?V1o<4e6GS|$dhZ?l7V1WXcK~oxJZF-L& zz@7g8;{HOAqG|xF0zF+z2ba^)jDH$7HbWKmr3Zf}n#4JaCv9CkUjWWd{Wapd}0_XnBVLwf5n}4pdZyf&l|)nZplS_OJpA zI)DLy76+7}02FG(p@0}lz%fG^B4FSE8ZU$a1_cy=A%+fJ*l++CWI*8n6k&Lp2OK)Q z0Kym|P(a5QUwF`k9tU`;M;tGRF@qOOupx%PUX+-PDXmsD1Ox_9)rS>+AmC;HA3H#x z>5;^42r&j22l&9i1Uv|_0tO0@K|u%(*zkfG2joEk z8473-0uvb6@d5=CoQw3jOE(Qh3@SkGLDeC6k#!g*gh0U;I(&ct2Sb0r#80fcsVGyWC~JF93lH*jZiK_?N@~v0)BBTL7|1@P{*m1QZHn;M*W5K`T}80diQL207?K zophCkSl2@Zgt4oe3w9|BQ-L&VzA zcz_r^d_fN;c!2`o&<2orBZ|RuAQk6U1iNAJ0T-ys04h)wEYL>(O~&y<0unFGMj7EqvKT2Me3D6oa@MZpgakbxKu z0D={?U<^6{0OUB(Ckdcomoh*A6v)6seEm?E`zvO;LePdII4uTdh=C1oV34LrbBe^P z$_^Hg$vzNa3Y^px7b@9@Av^&BRX7m5J4Ht0D>@#Aq+fdT@)0sh8V;k3cFgC5GDNExmM8iPPU21-zZ008d> zti?hD`$hj>cRl zsK&T_h{3^PKmiqS0S7YB!@)@KfpX3OjUWI49L~Z80Hn7DHS|IYK;YOFgaBURLj!c4 z0S)N7;JRz*v#P0yOXh4J-fwC6dGc1D>#iEck)IeozAgR-ghlCUw1InS3@}1?F@-E- zfub`svUP5QgDhC*5I8^rZYj!%Ea3JGMaIDa?bsa>se*=F0HP$m)14(V0?bE24wJBq z97M3WL;)rhauOh39e6-hjmZZBF~SR|xMLX<`3GR=F%f9``67Pc!UQ~}0Nsg1BogUM zL}t>HL1!c&0oeyMD9wpBe82+goWM$uLLWW@de621OEd_*7nZDg9GGznBN%W500003 zo6g5V9s-PhoI=pO21j1d5 zX!p4s=Gcr&{EX?<{6jK)dC0c6{f>>eWHOItb-0yM>~3GD-K-|aUm!y4K6{%X--tCx voModSecurity® Reference + Manual
ModSecurity

ModSecurity® Reference + Manual

Version 2.5.11 (Nov 4, 2009)


Table of Contents

Introduction
HTTP Traffic Logging
Real-Time Monitoring and Attack Detection
Attack Prevention and Just-in-time Patching
Flexible Rule Engine
Embedded-mode Deployment
Network-based Deployment
Portability
Licensing
ModSecurity Core Rules
Overview
Core Rules Content
Installation
Configuration Directives
SecAction
SecArgumentSeparator
SecAuditEngine
SecAuditLog
SecAuditLog2
SecAuditLogDirMode
SecAuditLogFileMode
SecAuditLogParts
SecAuditLogRelevantStatus
SecAuditLogStorageDir
SecAuditLogType
SecCacheTransformations + (Deprecated/Experimental)
SecChrootDir
SecComponentSignature
SecContentInjection
SecCookieFormat
SecDataDir
SecDebugLog
SecDebugLogLevel
SecDefaultAction
SecGeoLookupDb
SecGuardianLog
SecMarker
SecPdfProtect
SecPdfProtectMethod
SecPdfProtectSecret
SecPdfProtectTimeout
SecPdfProtectTokenName
SecRequestBodyAccess
SecRequestBodyLimit
SecRequestBodyNoFilesLimit
SecRequestBodyInMemoryLimit
SecResponseBodyLimit
SecResponseBodyLimitAction
SecResponseBodyMimeType
SecResponseBodyMimeTypesClear
SecResponseBodyAccess
SecRule
SecRuleInheritance
SecRuleEngine
SecRuleRemoveById
SecRuleRemoveByMsg
SecRuleScript (Experimental)
SecRuleUpdateActionById
SecServerSignature
SecTmpDir
SecUploadDir
SecUploadFileMode
SecUploadKeepFiles
SecWebAppId
Processing Phases
Phase Request Headers
Phase Request Body
Phase Response Headers
Phase Response Body
Phase Logging
Variables
ARGS
ARGS_COMBINED_SIZE
ARGS_NAMES
ARGS_GET
ARGS_GET_NAMES
ARGS_POST
ARGS_POST_NAMES
AUTH_TYPE
ENV
FILES
FILES_COMBINED_SIZE
FILES_NAMES
FILES_SIZES
FILES_TMPNAMES
GEO
HIGHEST_SEVERITY
MATCHED_VAR
MATCHED_VAR_NAME
MODSEC_BUILD
MULTIPART_CRLF_LF_LINES
MULTIPART_STRICT_ERROR
MULTIPART_UNMATCHED_BOUNDARY
PATH_INFO
QUERY_STRING
REMOTE_ADDR
REMOTE_HOST
REMOTE_PORT
REMOTE_USER
REQBODY_PROCESSOR
REQBODY_PROCESSOR_ERROR
REQBODY_PROCESSOR_ERROR_MSG
REQUEST_BASENAME
REQUEST_BODY
REQUEST_COOKIES
REQUEST_COOKIES_NAMES
REQUEST_FILENAME
REQUEST_HEADERS
REQUEST_HEADERS_NAMES
REQUEST_LINE
REQUEST_METHOD
REQUEST_PROTOCOL
REQUEST_URI
REQUEST_URI_RAW
RESPONSE_BODY
RESPONSE_CONTENT_LENGTH
RESPONSE_CONTENT_TYPE
RESPONSE_HEADERS
RESPONSE_HEADERS_NAMES
RESPONSE_PROTOCOL
RESPONSE_STATUS
RULE
SCRIPT_BASENAME
SCRIPT_FILENAME
SCRIPT_GID
SCRIPT_GROUPNAME
SCRIPT_MODE
SCRIPT_UID
SCRIPT_USERNAME
SERVER_ADDR
SERVER_NAME
SERVER_PORT
SESSION
SESSIONID
TIME
TIME_DAY
TIME_EPOCH
TIME_HOUR
TIME_MIN
TIME_MON
TIME_SEC
TIME_WDAY
TIME_YEAR
TX
USERID
WEBAPPID
WEBSERVER_ERROR_LOG
XML
Transformation functions
base64Decode
base64Encode
compressWhitespace
cssDecode
escapeSeqDecode
hexDecode
hexEncode
htmlEntityDecode
jsDecode
length
lowercase
md5
none
normalisePath
normalisePathWin
parityEven7bit
parityOdd7bit
parityZero7bit
removeNulls
removeWhitespace
replaceComments
replaceNulls
urlDecode
urlDecodeUni
urlEncode
sha1
trimLeft
trimRight
trim
Actions
allow
append
auditlog
block
capture
chain
ctl
deny
deprecatevar
drop
exec
expirevar
id
initcol
log
logdata
msg
multiMatch
noauditlog
nolog
pass
pause
phase
prepend
proxy
redirect
rev
sanitiseArg
sanitiseMatched
sanitiseRequestHeader
sanitiseResponseHeader
severity
setuid
setsid
setenv
setvar
skip
skipAfter
status
t
tag
xmlns
Operators
beginsWith
contains
endsWith
eq
ge
geoLookup
gt
inspectFile
le
lt
pm
pmFromFile
rbl
rx
streq
validateByteRange
validateDTD
validateSchema
validateUrlEncoding
validateUtf8Encoding
verifyCC
within
Macro Expansion
Persistant Storage
Miscellaneous Topics
Impedance Mismatch

Introduction

ModSecurity is a web application firewall (WAF). With over 70% of + attacks now carried out over the web application level, organisations need + all the help they can get in making their systems secure. WAFs are + deployed to establish an increased external security layer to detect + and/or prevent attacks before they reach web applications. ModSecurity + provides protection from a range of attacks against web applications and + allows for HTTP traffic monitoring and real-time analysis with little or + no changes to existing infrastructure.

HTTP Traffic Logging

Web servers are typically well-equipped to log traffic in a form + useful for marketing analyses, but fall short logging traffic to web + applications. In particular, most are not capable of logging the request + bodies. Your adversaries know this, and that is why most attacks are now + carried out via POST requests, rendering your systems blind. ModSecurity + makes full HTTP transaction logging possible, allowing complete requests + and responses to be logged. Its logging facilities also allow + fine-grained decisions to be made about exactly what is logged and when, + ensuring only the relevant data is recorded. As some of the request + and/or response may contain sensitive data in certain fields, + ModSecurity can be configured to mask these fields before they are + written to the audit log.

Real-Time Monitoring and Attack Detection

In addition to providing logging facilities, ModSecurity can + monitor the HTTP traffic in real time in order to detect attacks. In + this case, ModSecurity operates as a web intrusion detection tool, + allowing you to react to suspicious events that take place at your web + systems.

Attack Prevention and Just-in-time Patching

ModSecurity can also act immediately to prevent attacks from + reaching your web applications. There are three commonly used + approaches:

  1. Negative security model. A negative security model monitors + requests for anomalies, unusual behaviour, and common web + application attacks. It keeps anomaly scores for each request, IP + addresses, application sessions, and user accounts. Requests with + high anomaly scores are either logged or rejected altogether.

  2. Positive security model. When a positive security model is + deployed, only requests that are known to be valid are accepted, + with everything else rejected. This model requires knownledge of the + web applications you are protecting. Therefore a positive security + model works best with applications that are heavily used but rarely + updated so that maintenance of the model is minimized.

  3. Known weaknesses and vulnerabilities. Its rule language makes + ModSecurity an ideal external patching tool. External patching + (sometimes referred to as Virtual Patching) is about reducing the + window of opportunity. Time needed to patch application + vulnerabilities often runs to weeks in many organisations. With + ModSecurity, applications can be patched from the outside, without + touching the application source code (and even without any access to + it), making your systems secure until a proper patch is applied to + the application.

Flexible Rule Engine

A flexible rule engine sits in the heart of ModSecurity. It + implements the ModSecurity Rule Language, which is a specialised + programming language designed to work with HTTP transaction data. The + ModSecurity Rule Language is designed to be easy to use, yet flexible: + common operations are simple while complex operations are possible. + Certified ModSecurity Rules, included with ModSecurity, contain a + comprehensive set of rules that implement general-purpose hardening, + protocol validation and detection of common web application security + issues. Heavily commented, these rules can be used as a learning + tool.

Embedded-mode Deployment

ModSecurity is an embeddable web application firewall, which means + it can be deployed as part of your existing web server infrastructure + provided your web servers are Apache-based. This deployment method has + certain advantages:

  1. No changes to existing network. It only takes a few minutes to + add ModSecurity to your existing web servers. And because it was + designed to be completely passive by default, you are free to deploy + it incrementally and only use the features you need. It is equally + easy to remove or deactivate it if required.

  2. No single point of failure. Unlike with network-based + deployments, you will not be introducing a new point of failure to + your system.

  3. Implicit load balancing and scaling. Because it works embedded + in web servers, ModSecurity will automatically take advantage of the + additional load balancing and scalability features. You will not + need to think of load balancing and scaling unless your existing + system needs them.

  4. Minimal overhead. Because it works from inside the web server + process there is no overhead for network communication and minimal + overhead in parsing and data exchange.

  5. No problem with encrypted or compressed content. Many IDS + systems have difficulties analysing SSL traffic. This is not a + problem for ModSecurity because it is positioned to work when the + traffic is decrypted and decompressed.

Network-based Deployment

ModSecurity works equally well when deployed as part of an + Apache-based reverse proxy server, and many of our customers choose to + do so. In this scenario, one installation of ModSecurity can protect any + number of web servers (even the non-Apache ones).

Portability

ModSecurity is known to work well on a wide range of operating + systems. Our customers are successfully running it on Linux, Windows, + Solaris, FreeBSD, OpenBSD, NetBSD, AIX, Mac OS X, and HP-UX.

Licensing

ModSecurity is available under two licenses. Users can choose to + use the software under the terms of the GNU General Public License + version 2 (licence text is included with the distribution), as an Open + Source / Free Software product. A range of commercial licenses is also + available, together with a range of commercial support contracts. For + more information on commercial licensing please contact Breach + Security.

Note

ModSecurity, mod_security, ModSecurity Pro, and ModSecurity Core + Rules are trademarks or registered trademarks of Breach Security, + Inc.

ModSecurity Core Rules

Overview

ModSecurity is a web application firewall engine that provides + very little protection on its own. In order to become useful, + ModSecurity must be configured with rules. In order to enable users to + take full advantage of ModSecurity out of the box, Breach Security, Inc. + is providing a free certified rule set for ModSecurity 2.x. Unlike + intrusion detection and prevention systems, which rely on signatures + specific to known vulnerabilities, the Core Rules provide generic + protection from unknown vulnerabilities often found in web applications, + which are in most cases custom coded. The Core Rules are heavily + commented to allow it to be used as a step-by-step deployment guide for + ModSecurity. The latest Core Rules can be found at the ModSecurity + website - http://www.modsecurity.org/projects/rules/.

Core Rules Content

In order to provide generic web applications protection, the Core + Rules use the following techniques:

  • HTTP protection - detecting violations of the HTTP protocol + and a locally defined usage policy.

  • Common Web Attacks Protection - detecting common web + application security attack.

  • Automation detection - Detecting bots, crawlers, scanners and + other surface malicious activity.

  • Trojan Protection - Detecting access to Trojans horses.

  • Error Hiding - Disguising error messages sent by the + server.

Installation

ModSecurity installation requirements:

  1. ModSecurity 2.x works only with Apache 2.0.x or higher. Version + 2.2.x is highly recommended.

  2. Make sure you have mod_unique_id installed.

    mod_unique_id is packaged with Apache httpd.

  3. libapr and libapr-util

    http://apr.apache.org/

  4. libpcre

    http://www.pcre.org/

  5. libxml2

    http://xmlsoft.org/downloads.html

  6. liblua v5.1.x

    This library is optional and only needed if you will be using + the new Lua engine.

    http://www.lua.org/download.html

    Note that ModSecurity requires the dynamic libraries. These are + not built by default in the source distribution, so the binary + distribution is recommended.

  7. libcurl v7.15.1 or higher

    If you will be using the ModSecurity Log Collector (mlogc) to + send audit logs to a central repository, then you will also need the + curl library.

    http://curl.haxx.se/libcurl/

    Note

    Many have had issues with libcurl linked with the GnuTLS + library for SSL/TLS support. It is recommended that the + openssl library be used for SSL/TLS support in libcurl.

ModSecurity installation consists of the following steps:

  1. Stop Apache httpd

  2. Unpack the ModSecurity archive

  3. Building differs for UNIX (or UNIX-like) operating systems and + Windows.

    • UNIX

      1. Run the configure script to generate a Makefile. + Typically no options are needed.

        ./configure

        Options are available for more customization (use + ./configure --help for a full list), but + typically you will only need to specify the location of the + apxs command installed by Apache httpd with + the --with-apxs option.

        ./configure + --with-apxs=/path/to/httpd-2.x.y/bin/apxs

        Note

        There are certain configure options that are meant for + debugging an other development use. If enabled, these + options can substantially impact performance. These options + include all --debug-* options as well as + the --enable-performance-measurements + options.

      2. Compile with: make

      3. Optionally test with: make + test

        Note

        This is step is still a bit experimental. If you have + problems, please send the full output and error from the + build to the support list. Most common issues are related to + not finding the required headers and/or libraries.

      4. Optionally build the ModSecurity Log Collector with: + make mlogc

      5. Optionally install mlogc: Review the + INSTALL file included in the + apache2/mlogc-src directory in the distribution.

      6. Install the ModSecurity module with: make + install

    • Windows (MS VC++ 8)

      1. Edit Makefile.win to configure the + Apache base and library paths.

      2. Compile with: nmake -f + Makefile.win

      3. Install the ModSecurity module with: nmake -f + Makefile.win install

      4. Copy the libxml2.dll and + lua5.1.dll to the Apache + bin directory. Alternatively you can follow + the step below for using LoadFile to load these + libraries.

  4. Edit the main Apache httpd config file (usually + httpd.conf)

    On UNIX (and Windows if you did not copy the DLLs as stated + above) you must load libxml2 and lua5.1 before ModSecurity with + something like this:

    LoadFile /usr/lib/libxml2.so
    +LoadFile /usr/lib/liblua5.1.so

    Load the ModSecurity module with:

    LoadModule security2_module modules/mod_security2.so

  5. Configure ModSecurity

  6. Start Apache httpd

  7. You should now have ModSecurity 2.x up and running.

Note

If you have compiled Apache yourself you might experience problems + compiling ModSecurity against PCRE. This is because Apache bundles PCRE + but this library is also typically provided by the operating system. I + would expect most (all) vendor-packaged Apache distributions to be + configured to use an external PCRE library (so this should not be a + problem).

You want to avoid Apache using the bundled PCRE library and + ModSecurity linking against the one provided by the operating system. + The easiest way to do this is to compile Apache against the PCRE library + provided by the operating system (or you can compile it against the + latest PCRE version you downloaded from the main PCRE distribution + site). You can do this at configure time using the --with-pcre switch. If you are not in a + position to recompile Apache, then, to compile ModSecurity successfully, + you'd still need to have access to the bundled PCRE headers (they are + available only in the Apache source code) and change the include path + for ModSecurity (as you did in step 7 above) to point to them (via the + --with-pcre ModSecurity configure option).

Do note that if your Apache is using an external PCRE library you + can compile ModSecurity with WITH_PCRE_STUDY defined,which would possibly + give you a slight performance edge in regular expression + processing.

Non-gcc compilers may have problems running out-of-the-box as the + current build system was designed around the gcc compiler and some + compiler/linker flags may differ. To use a non-gcc compiler you may need + some manual Makefile tweaks if issues cannot be solved by exporting + custom CFLAGS and CPPFLAGS environment variables.

If you are upgrading from ModSecurity 1.x, please refer to the + migration matrix at http://www.modsecurity.org/documentation/ModSecurity-Migration-Matrix.pdf

Configuration Directives

The following section outlines all of the ModSecurity directives. + Most of the ModSecurity directives can be used inside the various Apache + Scope Directives such as VirtualHost, + Location, LocationMatch, + Directory, etc... There are others, however, that can + only be used once in the main configuration file. This information is + specified in the Scope sections below. The first version to use a given + directive is given in the Version sections below.

These rules, along with the Core rules files, should be contained is + files outside of the httpd.conf file and called up with Apache "Include" + directives. This allows for easier updating/migration of the rules. If you + create your own custom rules that you would like to use with the Core + rules, you should create a file called - + modsecurity_crs_15_customrules.conf and place it in + the same directory as the Core rules files. By using this file name, your + custom rules will be called up after the standard ModSecurity Core rules + configuration file but before the other Core rules. This allows your rules + to be evaluated first which can be useful if you need to implement + specific "allow" rules or to correct any false positives in the Core rules + as they are applied to your site.

Note

It is highly encouraged that you do not edit the Core rules files + themselves but rather place all changes (such as + SecRuleRemoveByID, etc...) in your custom rules file. + This will allow for easier upgrading as newer Core rules are released by + Breach Security on the ModSecurity website.

SecAction

Description: Unconditionally processes the + action list it receives as the first and only parameter. It accepts one + parameter, the syntax of which is identical to the third parameter + of SecRule.

Syntax: SecAction + action1,action2,action3

Example Usage: SecAction + nolog,phase:1,initcol:RESOURCE=%{REQUEST_FILENAME}

Processing Phase: Any

Scope: Any

Version: 2.0.0

Dependencies/Notes: None

SecAction is best used when you unconditionally execute an action. + This is explicit triggering whereas the normal Actions are conditional + based on data inspection of the request/response. This is a useful + directive when you want to run certain actions such as + initcol to initialize collections.

SecArgumentSeparator

Description: Specifies which character to use + as separator for + application/x-www-form-urlencoded content. Defaults to + &. Applications are sometimes + (very rarely) written to use a semicolon (;).

Syntax: SecArgumentSeparator character

Example Usage: SecArgumentSeparator ;

Processing Phase: Any

Scope: Main

Version: 2.0.0

Dependencies/Notes: None

This directive is needed if a backend web application is using a + non-standard argument separator. If this directive is not set properly + for each web application, then ModSecurity will not be able to parse the + arguments appropriately and the effectiveness of the rule matching will + be significantly decreased.

SecAuditEngine

Description: Configures the audit logging + engine.

Syntax: SecAuditEngine On|Off|RelevantOnly

Example Usage: SecAuditEngine On

Processing Phase: N/A

Scope: Any

Version: 2.0.0

Dependencies/Notes: Can be set/changed with + the "ctl" action for the current transaction.

Example: The following example shows the various audit directives + used together.

SecAuditEngine RelevantOnly 
+SecAuditLog logs/audit/audit.log
+SecAuditLogParts ABCFHZ
+SecAuditLogType concurrent
+SecAuditLogStorageDir logs/audit
+SecAuditLogRelevantStatus ^(?:5|4\d[^4])

Possible values are:

  • On - log all transactions + by default.

  • Off - do not log + transactions by default.

  • RelevantOnly - by default + only log transactions that have triggered a warning or an error, or + have a status code that is considered to be relevant (see SecAuditLogRelevantStatus).

SecAuditLog

Description: Defines the path to the main + audit log file.

Syntax: SecAuditLog + /path/to/auditlog

Example Usage: SecAuditLog + /usr/local/apache/logs/audit.log

Processing Phase: N/A

Scope: Any

Version: 2.0.0

Dependencies/Notes: This file is open on + startup when the server typically still runs as + root. You should not allow non-root users to have write + privileges for this file or for the directory it is stored in..

This file will be used to store the audit log entries if serial + audit logging format is used. If concurrent audit logging format is used + this file will be used as an index, and contain a record of all audit + log files created. If you are planning to use Concurrent audit logging + and sending your audit log data off to a remote Console host or + commercial ModSecurity Management Appliance, then you will need to + configure and use the ModSecurity Log Collector (mlogc) and use the + following format for the audit log:

SecAuditLog "|/path/to/mlogc /path/to/mlogc.conf"

SecAuditLog2

Description: Defines the path to the + secondary audit log index file when concurrent logging is enabled. See + SecAuditLog2 for more details.

Syntax: SecAuditLog2 + /path/to/auditlog2

Example Usage: SecAuditLog2 + /usr/local/apache/logs/audit2.log

Processing Phase: N/A

Scope: Any

Version: 2.1.2

Dependencies/Notes: A main audit log must be + defined via SecAuditLog before this + directive may be used. Additionally, this log is only used for + replicating the main audit log index file when concurrent audit logging + is used. It will not be used for non-concurrent + audit logging.

SecAuditLogDirMode

Description: Configures the mode + (permissions) of any directories created for concurrent audit logs using + an octal mode (as used in chmod). See SecAuditLogFileMode for controlling the mode + of audit log files.

Syntax: SecAuditLogDirMode octal_mode|"default"

Example Usage: SecAuditLogDirMode 02750

Processing Phase: N/A

Scope: Any

Version: 2.5.10

Dependencies/Notes: This feature is not + available on operating systems not supporting octal file modes. The + default mode (0600) only grants read/write access to the account writing + the file. If access from another account is needed (using mpm-itk is a + good example), then this directive may be required. However, use this + directive with caution to avoid exposing potentially sensitive data to + unauthorized users. Using the value "default" will revert back to the + default setting.

Note

The process umask may still limit the mode if it is being more + restrictive than the mode set using this directive.

SecAuditLogFileMode

Description: Configures the mode + (permissions) of any files created for concurrent audit logs using an + octal mode (as used in chmod). See SecAuditLogDirMode for controlling the mode of + created audit log directories.

Syntax: SecAuditLogFileMode + octal_mode|"default"

Example Usage: SecAuditLogFileMode 00640

Processing Phase: N/A

Scope: Any

Version: 2.5.10

Dependencies/Notes: This feature is not + available on operating systems not supporting octal file modes. The + default mode (0600) only grants read/write access to the account writing + the file. If access from another account is needed (using mpm-itk is a + good example), then this directive may be required. However, use this + directive with caution to avoid exposing potentially sensitive data to + unauthorized users. Using the value "default" will revert back to the + default setting.

Note

The process umask may still limit the mode if it is being more + restrictive than the mode set using this directive.

SecAuditLogParts

Description: Defines which part of each + transaction are going to be recorded in audit log. Each part is assigned + a single letter. If a letter appears in the list then the equivalent + part of each transactions will be recorded. See below for the list of + all parts.

Syntax: SecAuditLogParts PARTS

Example Usage: SecAuditLogParts ABCFHZ

Processing Phase: N/A

Scope: Any

Version: 2.0.0

Dependencies/Notes: At this time ModSecurity + does not log response bodies of stock Apache responses (e.g. 404), or the Server and Date response headers.

Default: ABCFHZ.

Note

Please refer to the ModSecurity Data Formats document for a + detailed description of every available part.

Available audit log parts:

  • A - audit log header + (mandatory)

  • B - request headers

  • C - request body (present + only if the request body exists and ModSecurity is configured to + intercept it)

  • D - RESERVED for + intermediary response headers, not implemented yet.

  • E - intermediary response + body (present only if ModSecurity is configured to intercept + response bodies, and if the audit log engine is configured to record + it). Intermediary response body is the same as the actual response + body unless ModSecurity intercepts the intermediary response body, + in which case the actual response body will contain the error + message (either the Apache default error message, or the + ErrorDocument page).

  • F - final response headers + (excluding the Date and Server headers, which are always added by + Apache in the late stage of content delivery).

  • G - RESERVED for the actual + response body, not implemented yet.

  • H - audit log + trailer

  • I - This part is a + replacement for part C. It will log the same data as C in all cases + except when multipart/form-data + encoding in used. In this case it will log a fake application/x-www-form-urlencoded body + that contains the information about parameters but not about the + files. This is handy if you don't want to have (often large) files + stored in your audit logs.

  • J - RESERVED. This part, + when implemented, will contain information about the files uploaded + using multipart/form-data encoding.

  • K - This part contains a + full list of every rule that matched (one per line) in the order + they were matched. The rules are fully qualified and will thus show + inherited actions and default operators. Supported as of + v2.5.0

  • Z - final boundary, + signifies the end of the entry (mandatory)

SecAuditLogRelevantStatus

Description: Configures which response status + code is to be considered relevant for the purpose of audit + logging.

Syntax: SecAuditLogRelevantStatus REGEX

Example Usage: SecAuditLogRelevantStatus + ^(?:5|4\d[^4])

Processing Phase: N/A

Scope: Any

Version: 2.0.0

Dependencies/Notes: Must have the + SecAuditEngine set to + RelevantOnly. The parameter is a regular + expression.

The main purpose of this directive is to allow you to configure + audit logging for only transactions that generate the specified HTTP + Response Status Code. This directive is often used to the decrease the + total size of the audit log file. Keep in mind that if this parameter is + used, then successful attacks that result in a 200 OK status code will + not be logged.

SecAuditLogStorageDir

Description: Configures the storage directory + where concurrent audit log entries are to be stored.

Syntax: SecAuditLogStorageDir + /path/to/storage/dir

Example Usage: SecAuditLogStorageDir + /usr/local/apache/logs/audit

Processing Phase: N/A

Scope: Any

Version: 2.0.0

Dependencies/Notes: SecAuditLogType must be + set to Concurrent. The directory must already be created before starting + Apache and it must be writable by the web server user as new files are + generated at runtime.

As with all logging mechanisms, ensure that you specify a file + system location that has adequate disk space and is not on the root + partition.

SecAuditLogType

Description: Configures the type of audit + logging mechanism to be used.

Syntax: SecAuditLogType Serial|Concurrent

Example Usage: SecAuditLogType Serial

Processing Phase: N/A

Scope: Any

Version: 2.0.0

Dependencies/Notes: Must specify + SecAuditLogStorageDir if you use concurrent + logging.

Possible values are:

  1. Serial - all audit log + entries will be stored in the main audit logging file. This is more + convenient for casual use but it is slower as only one audit log + entry can be written to the file at any one file.

  2. Concurrent - audit log + entries will be stored in separate files, one for each transaction. + Concurrent logging is the mode to use if you are going to send the + audit log data off to a remote ModSecurity Console host.

SecCacheTransformations + (Deprecated/Experimental)

Description: Controls caching of + transformations. Caching is off by default starting with 2.5.6, when it + was deprecated and downgraded back to experimental.

Syntax: SecCacheTransformations On|Off + [options]

Example Usage: SecCacheTransformations On + "minlen:64,maxlen:0"

Processing Phase: N/A

Scope: Any

Version: 2.5.0

Dependencies/Notes: N/A

First parameter:

  • On - cache transformations + (per transaction, per phase) allowing identical transformations to + be performed only once. (default)

  • Off - do not cache any + transformations, forcing all transformations to be performed for + each rule executed.

The following options are allowed (comma separated):

  • incremental:on|off - + enabling this option will cache every transformation instead of just + the final transformation. (default: off)

  • maxitems:N - do not allow + more than N transformations to be cached. The cache will then be + disabled. A zero value is interpreted as "unlimited". This option + may be useful to limit caching for a form with a large number of + ARGS. (default: 512)

  • minlen:N - do not cache the + transformation if the value's length is less than N bytes. (default: + 32)

  • maxlen:N - do not cache the + transformation if the value's length is more than N bytes. A zero + value is interpreted as "unlimited". (default: 1024)

SecChrootDir

Description: Configures the directory path + that will be used to jail the web server process.

Syntax: SecChrootDir + /path/to/chroot/dir

Example Usage: SecChrootDir /chroot

Processing Phase: N/A

Scope: Main

Version: 2.0.0

Dependencies/Notes: This feature is not + available on Windows builds. The internal chroot functionality provided + by ModSecurity works great for simple setups. One example of a simple + setup is Apache serving static files only, or running scripts using + modules.builds. Some problems you might encounter with more complex + setups:

  1. DNS lookups do not work (this is because this feature requires + a shared library that is loaded on demand, after chroot takes + place).

  2. You cannot send email from PHP because it uses sendmail and + sendmail is outside the jail.

  3. In some cases Apache graceful (reload) no longer works.

You should be aware that the internal chroot feature might not be + 100% reliable. Due to the large number of default and third-party + modules available for the Apache web server, it is not possible to + verify the internal chroot works reliably with all of them. A module, + working from within Apache, can do things that make it easy to break out + of the jail. In particular, if you are using any of the modules that + fork in the module initialisation phase (e.g. + mod_fastcgi, mod_fcgid, + mod_cgid), you are advised to examine each Apache + process and observe its current working directory, process root, and the + list of open files. Consider what your options are and make your own + decision.

SecComponentSignature

Description: Appends component signature to + the ModSecurity signature.

Syntax: SecComponentSignature + "COMPONENT_NAME/X.Y.Z (COMMENT)"

Example usage: SecComponentSignature + "Core Rules/1.2.3"

Processing Phase: N/A

Scope: Main

Version: 2.5.0

Dependencies/Notes: This directive should be + used to make the presence of significant ModSecurity components known. + The entire signature will be recorded in transaction audit log. It + should be used by ModSecurity module and rule set writers to make + debugging easier.

SecContentInjection

Description: Enables content injection using + actions append and prepend.

Syntax: SecContentInjection + (On|Off)

Example Usage: SecContentInjection + On

Processing Phase: N/A

Scope: Any

Version: 2.5.0

Dependencies/Notes: N/A

SecCookieFormat

Description: Selects the cookie format that + will be used in the current configuration context.

Syntax: SecCookieFormat 0|1

Example Usage: SecCookieFormat 0

Processing Phase: N/A

Scope: Any

Version: 2.0.0

Dependencies/Notes: None

Possible values are:

  • 0 - use version 0 + (Netscape) cookies. This is what most applications use. It is the + default value.

  • 1 - use version 1 + cookies.

SecDataDir

Description: Path where persistent data (e.g. + IP address data, session data, etc) is to be stored.

Syntax: SecDataDir + /path/to/dir

Example Usage: SecDataDir /usr/local/apache/logs/data

Processing Phase: N/A

Scope: Main

Dependencies/Notes: This directive is needed + when initcol, setsid an setuid are used. Must be writable by the web + server user.

SecDebugLog

Description: Path to the ModSecurity debug + log file.

Syntax: SecDebugLog + /path/to/modsec-debug.log

Example Usage: SecDebugLog + /usr/local/apache/logs/modsec-debug.log

Processing Phase: N/A

Scope: Any

Version: 2.0.0

Dependencies/Notes: None

SecDebugLogLevel

Description: Configures the verboseness of + the debug log data.

Syntax: SecDebugLogLevel 0|1|2|3|4|5|6|7|8|9

Example Usage: SecDebugLogLevel 4

Processing Phase: N/A

Scope: Any

Version: 2.0.0

Dependencies/Notes: Levels 1 - 3 are always sent to the Apache error log. + Therefore you can always use level 0 + as the default logging level in production. Level 5 is useful when debugging. It is not + advisable to use higher logging levels in production as excessive + logging can slow down server significantly.

Possible values are:

  • 0 - no logging.

  • 1 - errors (intercepted + requests) only.

  • 2 - warnings.

  • 3 - notices.

  • 4 - details of how + transactions are handled.

  • 5 - as above, but including + information about each piece of information handled.

  • 9 - log everything, + including very detailed debugging information.

SecDefaultAction

Description: Defines the default action to + take on a rule match.

Syntax: SecDefaultAction + action1,action2,action3

Example Usage: SecDefaultAction + log,auditlog,deny,status:403,phase:2

Processing Phase: Any

Scope: Any

Version: 2.0.0

Dependencies/Notes: Rules following a + SecDefaultAction directive will inherit this setting + unless a specific action is specified for an individual rule or until + another SecDefaultAction is specified. Take special + note that in the logging disruptive actions are not allowed, but this + can inadvertently be inherited using a disruptive action in + SecDefaultAction.

The default value is minimal (differing from previous + versions):

SecDefaultAction phase:2,log,auditlog,pass

Note

SecDefaultAction must specify a disruptive + action and a processing phase and cannot contain metadata + actions.

Warning

SecDefaultAction is not + inherited across configuration contexts. (For an example of why this + may be a problem for you, read the following ModSecurity Blog entry + http://blog.modsecurity.org/2008/07/modsecurity-tri.html).

SecGeoLookupDb

Description: Defines the path to the + geographical database file.

Syntax: SecGeoLookupDb /path/to/db

Example Usage: SecGeoLookupDb + /usr/local/geo/data/GeoLiteCity.dat

Processing Phase: N/A

Scope: Any

Version: 2.5.0

Dependencies/Notes: Check out + maxmind.com for free database files.

SecGuardianLog

Description: Configuration directive to use + the httpd-guardian script to monitor for Denial of Service (DoS) + attacks.

Syntax: SecGuardianLog |/path/to/httpd-guardian

Example Usage: SecGuardianLog + |/usr/local/apache/bin/httpd-guardian

Processing Phase: N/A

Scope: Main

Version: 2.0.0

Dependencies/Notes: By default httpd-guardian + will defend against clients that send more than 120 requests in a + minute, or more than 360 requests in five minutes.

Since 1.9, ModSecurity supports a new directive, SecGuardianLog, + that is designed to send all access data to another program using the + piped logging feature. Since Apache is typically deployed in a + multi-process fashion, making information sharing difficult, the idea is + to deploy a single external process to observe all requests in a + stateful manner, providing additional protection.

Development of a state of the art external protection tool will be + a focus of subsequent ModSecurity releases. However, a fully functional + tool is already available as part of the Apache httpd tools + project. The tool is called httpd-guardian and can be used to + defend against Denial of Service attacks. It uses the blacklist tool + (from the same project) to interact with an iptables-based (Linux) or + pf-based (*BSD) firewall, dynamically blacklisting the offending IP + addresses. It can also interact with SnortSam (http://www.snortsam.net). + Assuming httpd-guardian is already configured (look into the source code + for the detailed instructions) you only need to add one line to your + Apache configuration to deploy it:

SecGuardianLog |/path/to/httpd-guardian

SecMarker

Description: Adds a fixed rule marker in the + ruleset to be used as a target in a skipAfter action. + A SecMarker directive essentially creates a rule that + does nothing and whose only purpose it to carry the given ID.

Syntax: SecMarker + ID

Example Usage: SecMarker 9999

Processing Phase: Any

Scope: Any

Version: 2.5.0

Dependencies/Notes: None

SecRule REQUEST_URI "^/$" \
+    "chain,t:none,t:urlDecode,t:lowercase,t:normalisePath,skipAfter:99"
+SecRule REMOTE_ADDR "^127\.0\.0\.1$" "chain"
+SecRule REQUEST_HEADERS:User-Agent \
+    "^Apache \(internal dummy connection\)$" "t:none"  
+SecRule &REQUEST_HEADERS:Host "@eq 0" \
+    "deny,log,status:400,id:08,severity:4,msg:'Missing a Host Header'"
+SecRule &REQUEST_HEADERS:Accept "@eq 0" \
+    "log,deny,log,status:400,id:15,msg:'Request Missing an Accept Header'"
+
+SecMarker 99

SecPdfProtect

Description: Enables the PDF XSS protection + functionality. Once enabled access to PDF files is tracked. Direct + access attempts are redirected to links that contain one-time tokens. + Requests with valid tokens are allowed through unmodified. Requests with + invalid tokens are also allowed through but with forced download of the + PDF files. This implementation uses response headers to detect PDF files + and thus can be used with dynamically generated PDF files that do not + have the .pdf extension in the request URI.

Syntax: SecPdfProtect On|Off

Example Usage: SecPdfProtect On

Processing Phase: N/A

Scope: Any

Version: 2.5.0

Dependencies/Notes: None

SecPdfProtectMethod

Description: Configure desired protection + method to be used when requests for PDF files are detected. Possible + values are TokenRedirection and + ForcedDownload. The token redirection approach will + attempt to redirect with tokens where possible. This allows PDF files to + continue to be opened inline but only works for GET requests. Forced + download always causes PDF files to be delivered as opaque binaries and + attachments. The latter will always be used for non-GET requests. Forced + download is considered to be more secure but may cause usability + problems for users ("This PDF won't open anymore!").

Syntax: SecPdfProtectMethod method

Example Usage: SecPdfProtectMethod TokenRedirection

Processing Phase: N/A

Scope: Any

Version: 2.5.0

Dependencies/Notes: None

Default: + TokenRedirection

SecPdfProtectSecret

Description: Defines the secret that will be + used to construct one-time tokens. You should use a reasonably long + value for the secret (e.g. 16 characters is good). Once selected the + secret should not be changed as it will break the tokens that were sent + prior to change. But it's not a big deal even if you change it. It will + just force download of PDF files with tokens that were issued in the + last few seconds.

Syntax: SecPdfProtectSecret secret

Example Usage: SecPdfProtectSecret + MyRandomSecretString

Processing Phase: N/A

Scope: Any

Version: 2.5.0

Dependencies/Notes: None

SecPdfProtectTimeout

Description: Defines the token timeout. After + token expires it can no longer be used to allow access to PDF file. + Request will be allowed through but the PDF will be delivered as + attachment.

Syntax: SecPdfProtectTimeout timeout

Example Usage: SecPdfProtectTimeout 10

Processing Phase: N/A

Scope: Any

Version: 2.5.0

Dependencies/Notes: None

Default: 10

SecPdfProtectTokenName

Description: Defines the name of the token. + The only reason you would want to change the name of the token is if you + wanted to hide the fact you are running ModSecurity. It's a good reason + but it won't really help as the adversary can look into the algorithm + used for PDF protection and figure it out anyway. It does raise the bar + slightly so go ahead if you want to.

Syntax: SecPdfProtectTokenName name

Example Usage: SecPdfProtectTokenName PDFTOKEN

Processing Phase: N/A

Scope: Any

Version: 2.5.0

Dependencies/Notes: None

Default: PDFTOKEN

SecRequestBodyAccess

Description: Configures whether request + bodies will be buffered and processed by ModSecurity by default.

Syntax: SecRequestBodyAccess On|Off

Example Usage: SecRequestBodyAccess On

Processing Phase: N/A

Scope: Any

Version: 2.0.0

Dependencies/Notes: This directive is + required if you plan to inspect POST_PAYLOAD. This + directive must be used along with the "phase:2" processing phase action + and REQUEST_BODY variable/location. If any of these 3 + parts are not configured, you will not be able to inspect the request + bodies.

Possible values are:

  • On - access request + bodies.

  • Off - do not attempt to + access request bodies.

SecRequestBodyLimit

Description: Configures the maximum request + body size ModSecurity will accept for buffering.

Syntax: SecRequestBodyLimit NUMBER_IN_BYTES

Example Usage: SecRequestBodyLimit 134217728

Scope: Any

Version: 2.0.0

Dependencies/Notes: 131072 KB (134217728 + bytes) is the default setting. Anything over this limit will be rejected + with status code 413 Request Entity Too Large. There is a hard limit of + 1 GB.

SecRequestBodyNoFilesLimit

Description: Configures the maximum request + body size ModSecurity will accept for buffering, excluding the size of + files being transported in the request. This directive comes handy to + further reduce susceptibility to DoS attacks when someone is sending + request bodies of very large sizes. Web applications that require file + uploads must configure SecRequestBodyLimit to a high + value. Since large files are streamed to disk file uploads will not + increase memory consumption. However, it's still possible for someone to + take advantage of a large request body limit and send non-upload + requests with large body sizes. This directive eliminates that + loophole.

Syntax: SecRequestBodyNoFilesLimit + NUMBER_IN_BYTES

Example Usage: SecRequestBodyLimit 131072

Scope: Any

Version: 2.5.0

Dependencies/Notes: 1 MB (1048576 bytes) is + the default setting. This value is very conservative. For most + applications you should be able to reduce it down to 128 KB or lower. + Anything over the limit will be rejected with status code 413 + Request Entity Too Large. There is a hard limit of 1 + GB.

SecRequestBodyInMemoryLimit

Description: Configures the maximum request + body size ModSecurity will store in memory.

Syntax: SecRequestBodyInMemoryLimit + NUMBER_IN_BYTES

Example Usage: SecRequestBodyInMemoryLimit 131072

Processing Phase: N/A

Scope: Any

Version: 2.0.0

Dependencies/Notes: None

By default the limit is 128 KB:

# Store up to 128 KB in memory
+SecRequestBodyInMemoryLimit 131072

SecResponseBodyLimit

Description: Configures the maximum response + body size that will be accepted for buffering.

Syntax: SecResponseBodyLimit NUMBER_IN_BYTES

Example Usage: SecResponseBodyLimit 524228

Processing Phase: N/A

Scope: Any

Version: 2.0.0

Dependencies/Notes: Anything over this limit + will be rejected with status code 500 Internal Server Error. This + setting will not affect the responses with MIME types that are not + marked for buffering. There is a hard limit of 1 GB.

By default this limit is configured to 512 KB:

# Buffer response bodies of up to 512 KB in length 
+SecResponseBodyLimit 524288

SecResponseBodyLimitAction

Description: Controls what happens once a + response body limit, configured with + SecResponseBodyLimit, is encountered. By default + ModSecurity will reject a response body that is longer than specified. + Some web sites, however, will produce very long responses making it + difficult to come up with a reasonable limit. Such sites would have to + raise the limit significantly to function properly defying the purpose + of having the limit in the first place (to control memory consumption). + With the ability to choose what happens once a limit is reached site + administrators can choose to inspect only the first part of the + response, the part that can fit into the desired limit, and let the rest + through. Some could argue that allowing parts of responses to go + uninspected is a weakness. This is true in theory but only applies to + cases where the attacker controls the output (e.g. can make it arbitrary + long). In such cases, however, it is not possible to prevent leakage + anyway. The attacker could compress, obfuscate, or even encrypt data + before it is sent back, and therefore bypass any monitoring + device.

Syntax: SecResponseBodyLimitAction + Reject|ProcessPartial

Example Usage: + SecResponseBodyLimitAction ProcessPartial

Processing Phase: N/A

Scope: Any

Version: 2.5.0

Dependencies/Notes: None

SecResponseBodyMimeType

Description: Configures which MIME types are to be considered for response + body buffering.

Syntax: SecResponseBodyMimeType mime/type

Example Usage: SecResponseBodyMimeType text/plain + text/html

Processing Phase: N/A

Scope: Any

Version: 2.0.0

Dependencies/Notes: Multiple SecResponseBodyMimeType directives can be + used to add MIME types.

The default value is text/plaintext/html:

SecResponseBodyMimeType text/plain text/html

SecResponseBodyMimeTypesClear

Description: Clears the list of MIME types considered for response body + buffering, allowing you to start populating the list from + scratch.

Syntax: SecResponseBodyMimeTypesClear

Example Usage: SecResponseBodyMimeTypesClear

Processing Phase: N/A

Scope: Any

Version: 2.0.0

Dependencies/Notes: None

SecResponseBodyAccess

Description: Configures whether response + bodies are to be buffer and analysed or not.

Syntax: SecResponseBodyAccess On|Off

Example Usage: SecResponseBodyAccess On

Processing Phase: N/A

Scope: Any

Version: 2.0.0

Dependencies/Notes: This directive is + required if you plan to inspect HTML responses. This directive must be + used along with the "phase:4" processing phase action and RESPONSE_BODY + variable/location. If any of these 3 parts are not configured, you will + not be able to inspect the response bodies.

Possible values are:

  • On - access response bodies + (but only if the MIME type matches, see above).

  • Off - do not attempt to + access response bodies.

SecRule

Description: SecRule is the main ModSecurity directive. It + is used to analyse data and perform actions based on the results.

Syntax: SecRule + VARIABLES OPERATOR [ACTIONS]

Example Usage: SecRule REQUEST_URI "attack" \

+ "phase:1,t:none,t:urlDecode,t:lowercase,t:normalisePath"

Processing Phase: Any

Scope: Any

Version: 2.0.0

Dependencies/Notes: None

In general, the format of this rule is as follows:

SecRule VARIABLES OPERATOR [ACTIONS]

The second part, OPERATOR, + specifies how they are going to be checked. The third (optional) part, + ACTIONS, specifies what to do + whenever the operator used performs a successful match against a + variable.

Variables in rules

The first part, VARIABLES, + specifies which variables are to be checked. For example, the + following rule will reject a transaction that has the word + dirty in the URI:

SecRule ARGS dirty

Each rule can specify one or more variables:

SecRule ARGS|REQUEST_HEADERS:User-Agent dirty

There is a third format supported by the selection operator - + XPath expression. XPath expressions can only used against the special + variable XML, which is available only of the request body was + processed as XML.

SecRule XML:/xPath/Expression dirty

Note

Not all collections support all selection operator format + types. You should refer to the documentation of each collection to + determine what is and isn't supported.

Collections

A variable can contain one or many pieces of data, depending on + the nature of the variable and the way it is used. We've seen examples + of both approaches in the previous section. When a variable can + contain more than one value we refer to it as a + collection.

Collections are always expanded before a rule is run. For + example, the following rule:

SecRule ARGS dirty

will be expanded to:

SecRule ARGS:p dirty
+SecRule ARGS:q dirty

in a requests that has only two parameters, named + p and q.

Collections come in several flavours:

Read-only

Created at runtime using transaction data. For example: + ARGS (contains a list of all request + parameter values) and REQUEST_HEADERS + (contains a list of all request header values).

Transient Read/Write

The TX collection is created (empty) + for every transaction. Rules can read from it and write to it + (using the setvar action, for example), but + the information stored in this collection will not survive the + end of transaction.

Persistent Read/Write

There are several collections that can be written to, but + which are persisted to the storage backend. These collections + are used to track clients across transactions. Examples of + collections that fall into this type are IP, + SESSION and USER.

Operators in rules

In the simplest possible case you will use a regular expression + pattern as the second rule parameter. This is what we've done in the + examples above. If you do this ModSecurity assumes you want to use the + rx (regular expression) operator. + You can also explicitly specify the operator you want to use by using + @, followed by the name of an + operator, at the beginning of the second SecRule + parameter:

SecRule ARGS "@rx dirty"

Note how we had to use double quotes to delimit the second rule + parameter. This is because the second parameter now has whitespace in + it. Any number of whitespace characters can follow the name of the + operator. If there are any non-whitespace characters there, they will + all be treated as a special parameter to the operator. In the case of + the regular expression operator the special parameter is the pattern + that will be used for comparison.

The @ can be the second character if you are using negation to + negate the result returned by the operator:

SecRule &ARGS "!@rx ^0$"

Operator negation

Operator results can be negated by using an exclamation mark at + the beginning of the second parameter. The following rule matches if + the word dirty does not appear + in the User-Agent request header:

SecRule REQUEST_HEADERS:User-Agent !dirty

You can use the exclamation mark in combination with any + parameter. If you do, the exclamation mark needs to go first, followed + by the explicit operator reference. The following rule has the same + effect as the previous example:

SecRule REQUEST_HEADERS:User-Agent "!@rx dirty"

If you need to use negation in a rule that is going to be + applied to several variables then it may not be immediately clear what + will happen. Consider the following example:

SecRule ARGS:p|ARGS:q !dirty

The above rule is identical to:

SecRule ARGS:p !dirty
+SecRule ARGS:q !dirty

Warning

Negation is applied to operations against individual + operations, not agains the entire variable list.

Actions in rules

The third parameter, ACTIONS, + can be omitted only because there is a helper feature that specifies + the default action list. If the parameter isn't omitted the actions + specified in the parameter will be merged with the default action list + to create the actual list of actions that will be processed on a rule + match.

SecRuleInheritance

Description: Configures whether the current + context will inherit rules from the parent context (configuration + options are inherited in most cases - you should look up the + documentation for every directive to determine if it is inherited or + not).

Syntax: SecRuleInheritance On|Off

Example Usage: SecRuleInheritance Off

Processing Phase: Any

Scope: Any

Version: 2.0.0

Dependencies/Notes: Resource-specific + contexts (e.g. Location, Directory, etc) cannot override + phase1 rules configured in the main server or in + the virtual server. This is because phase 1 is run early in the request + processing process, before Apache maps request to resource. Virtual host + context can override phase 1 rules configured in the main server.

Example: The following example shows where ModSecurity may be + enabled in the main Apache configuration scope, however you might want + to configure your VirtualHosts differently. In the first example, the + first VirtualHost is not inheriting the ModSecurity main config + directives and in the second one it is.

SecRuleEngine On
+SecDefaultAction log,pass,phase:2
+...  
+
+<VirtualHost *:80>
+ServerName app1.com 
+ServerAlias www.app1.com
+SecRuleInheritance Off
+SecDefaultAction log,deny,phase:1,redirect:http://www.site2.com 
+... 
+</VirtualHost>  
+
+<VirtualHost *:80> 
+ServerName app2.com 
+ServerAlias www.app2.com
+SecRuleInheritance On SecRule ARGS "attack" 
+... 
+</VirtualHost>

Possible values are:

  • On - inherit rules from the + parent context.

  • Off - do not inherit rules + from the parent context.

    Note

    Configuration contexts are an Apache concept. Directives + <Directory>, + <Files>, + <Location> and + <VirtualHost> are all used to create + configuration contexts. For more information please go to the + Apache documentation section Configuration + Sections.

SecRuleEngine

Description: Configures the rules + engine.

Syntax: SecRuleEngine On|Off|DetectionOnly

Example Usage: SecRuleEngine On

Processing Phase: Any

Scope: Any

Version: 2.0.0

Dependencies/Notes: This directive can also + be controlled by the ctl action (ctl:ruleEngine=off) for per rule + processing.

Possible values are:

  • On - process rules.

  • Off - do not process + rules.

  • DetectionOnly - process + rules but never intercept transactions, even when rules are + configured to do so.

SecRuleRemoveById

Description: Removes matching rules from the + parent contexts.

Syntax: SecRuleUpdateActionById RULEID + ACTIONLIST

Example Usage: SecRuleRemoveByID 1 2 "9000-9010"

Processing Phase: Any

Scope: Any

Version: 2.0.0

Dependencies/Notes: This directive supports + multiple parameters, where each parameter can either be a rule ID, or a + range. Parameters that contain spaces must be delimited using double + quotes.

SecRuleRemoveById 1 2 5 10-20 "400-556" 673

SecRuleRemoveByMsg

Description: Removes matching rules from the + parent contexts.

Syntax: SecRuleRemoveByMsg REGEX

Example Usage: SecRuleRemoveByMsg "FAIL"

Processing Phase: Any

Scope: Any

Version: 2.0.0

Dependencies/Notes: This directive supports + multiple parameters. Each parameter is a regular expression that will be + applied to the message (specified using the msg action).

SecRuleScript (Experimental)

Description: This directive creates a special + rule that executes a Lua script to decide whether to match or not. The + main difference from SecRule is that there are no + targets nor operators. The script can fetch any variable from the + ModSecurity context and use any (Lua) operator to test them. The second + optional parameter is the list of actions whose meaning is identical to + that of SecRule.

Syntax: SecRuleScript + /path/to/script.lua [ACTIONS]

Example Usage: SecRuleScript "/path/to/file.lua" + "block"

Processing Phase: Any

Scope: Any

Version: 2.5.0

Dependencies/Notes: None

Note

All Lua scripts are compiled at configuration time and cached in + memory. To reload scripts you must reload the entire ModSecurity + configuration by restarting Apache.

Example script:

-- Your script must define the main entry
+-- point, as below.
+function main()
+    -- Log something at level 1. Normally you shouldn't be
+    -- logging anything, especially not at level 1, but this is
+    -- just to show you can. Useful for debugging.
+    m.log(1, "Hello world!");
+
+    -- Retrieve one variable.
+    local var1 = m.getvar("REMOTE_ADDR");
+
+    -- Retrieve one variable, applying one transformation function.
+    -- The second parameter is a string.
+    local var2 = m.getvar("ARGS", "lowercase");
+
+    -- Retrieve one variable, applying several transformation functions.
+    -- The second parameter is now a list. You should note that m.getvar()
+    -- requires the use of comma to separate collection names from
+    -- variable names. This is because only one variable is returned.
+    local var3 = m.getvar("ARGS.p", { "lowercase", "compressWhitespace" } );
+
+    -- If you want this rule to match return a string
+    -- containing the error message. The message must contain the name
+    -- of the variable where the problem is located.
+    -- return "Variable ARGS:p looks suspicious!"
+
+    -- Otherwise, simply return nil.
+    return nil;
+end

In this first example we were only retrieving one variable at the + time. In this case the name of the variable is known to you. In many + cases, however, you will want to examine variables whose names you won't + know in advance, for example script parameters.

Example showing use of m.getvars() to retrieve + many variables at once:

function main()
+    -- Retrieve script parameters.
+    local d = m.getvars("ARGS", { "lowercase", "htmlEntityDecode" } );
+
+    -- Loop through the paramters.
+    for i = 1, #d do
+        -- Examine parameter value.
+        if (string.find(d[i].value, "<script")) then
+            -- Always specify the name of the variable where the
+            -- problem is located in the error message.
+            return ("Suspected XSS in variable " .. d[i].name .. ".");
+        end
+    end
+
+    -- Nothing wrong found.
+    return nil;
+end

Note

Go to http://www.lua.org/ to find more + about the Lua programming language. The reference manual too is + available online, at http://www.lua.org/manual/5.1/.

Note

Lua support is marked as experimental as + the way the progamming interface may continue to evolve while we are + working for the best implementation style. Any user input into the + programming interface is appreciated.

SecRuleUpdateActionById

Description: Updates the action list of the + specified rule.

Syntax: SecRuleRemoveById RULEID ACTIONLIST

Example Usage: SecRuleUpdateActionById 12345 + deny,status:403

Processing Phase: Any

Scope: Any

Version: 2.5.0

Dependencies/Notes: This directive merges the + specified action list with the rule's action list. There are two + limitations. The rule ID cannot be changed, nor can the phase. Further + note that actions that may be specified multiple times are appended to + the original.

SecAction \
+  "t:lowercase,phase:2,id:12345,pass,msg:'The Message',log,auditlog"
+SecRuleUpdateActionById 12345 "t:compressWhitespace,deny,status:403,msg:'A new message'

The example above will cause the rule to be executed as if it was + specified as follows:

SecAction \
+  "t:lowercase,phase:2,id:12345,log,auditlog,t:compressWhitespace,deny,status:403,msg:'A new message'"

SecServerSignature

Description: Instructs ModSecurity to change + the data presented in the "Server:" response header token.

Syntax: SecServerSignature "WEB SERVER + SOFTWARE"

Example Usage: SecServerSignature + "Netscape-Enterprise/6.0"

Processing Phase: N/A

Scope: Main

Version: 2.0.0

Dependencies/Notes: In order for this + directive to work, you must set the Apache ServerTokens directive to + Full. ModSecurity will overwrite the server signature data held in this + memory space with the data set in this directive. If ServerTokens is not + set to Full, then the memory space is most likely not large enough to + hold the new data we are looking to insert.

SecTmpDir

Description: Configures the directory where + temporary files will be created.

Syntax: SecTmpDir + /path/to/dir

Example Usage: SecTmpDir /tmp

Processing Phase: N/A

Scope: Any

Version: 2.0.0

Dependencies/Notes: Needs to be writable by + the Apache user process. This is the directory location where Apache + will swap data to disk if it runs out of memory (more data than what was + specified in the SecRequestBodyInMemoryLimit directive) during + inspection.

SecUploadDir

Description: Configures the directory where + intercepted files will be stored.

Syntax: SecUploadDir + /path/to/dir

Example Usage: SecUploadDir /tmp

Processing Phase: N/A

Scope: Any

Version: 2.0.0

Dependencies/Notes: This directory must be on + the same filesystem as the temporary directory defined with SecTmpDir. This directive is used with + SecUploadKeepFiles.

SecUploadFileMode

Description: Configures the mode + (permissions) of any uploaded files using an octal mode (as used in + chmod).

Syntax: SecUploadFileMode octal_mode|"default"

Example Usage: SecUploadFileMode 0640

Processing Phase: N/A

Scope: Any

Version: 2.1.6

Dependencies/Notes: This feature is not + available on operating systems not supporting octal file modes. The + default mode (0600) only grants read/write access to the account writing + the file. If access from another account is needed (using clamd is a + good example), then this directive may be required. However, use this + directive with caution to avoid exposing potentially sensitive data to + unauthorized users. Using the value "default" will revert back to the + default setting.

Note

The process umask may still limit the mode if it is being more + restrictive than the mode set using this directive.

SecUploadKeepFiles

Description: Configures whether or not the + intercepted files will be kept after transaction is processed.

Syntax: SecUploadKeepFiles On|Off|RelevantOnly

Example Usage: SecUploadKeepFiles On

Processing Phase: N/A

Scope: Any

Version: 2.0.0

Dependencies/Notes: This directive requires + the storage directory to be defined (using SecUploadDir).

Possible values are:

  • On - Keep uploaded + files.

  • Off - Do not keep uploaded + files.

  • RelevantOnly - This will + keep only those files that belong to requests that are deemed + relevant.

SecWebAppId

Description: Creates a partition on the + server that belongs to one web application.

Syntax: SecWebAppId + "NAME"

Example Usage: SecWebAppId "WebApp1"

Processing Phase: N/A

Scope: Any

Version: 2.0.0

Dependencies/Notes: Partitions are used to + avoid collisions between session IDs and user IDs. This directive must + be used if there are multiple applications deployed on the same server. + If it isn't used, a collision between session IDs might occur. The + default value is default. + Example:

<VirtualHost *:80> 
+ServerName app1.com 
+ServerAlias www.app1.com
+SecWebAppId "App1"
+SecRule REQUEST_COOKIES:PHPSESSID !^$ chain,nolog,pass 
+SecAction setsid:%{REQUEST_COOKIES.PHPSESSID} 
+... 
+</VirtualHost>  
+
+<VirtualHost *:80> 
+ServerName app2.com 
+ServerAlias www.app2.com
+SecWebAppId "App2"
+SecRule REQUEST_COOKIES:PHPSESSID !^$ chain,nolog,pass 
+SecAction setsid:%{REQUEST_COOKIES.PHPSESSID} 
+... 
+</VirtualHost>

In the two examples configurations shown, SecWebAppId is being + used in conjunction with the Apache VirtualHost directives. What this + achieves is to create more unique collection names when being hosted on + one server. Normally, when setsid is used, ModSecurity will create a + collection with the name "SESSION" and it will hold the value specified. + With using SecWebAppId as shown in the examples, however, the name of + the collection would become "App1_SESSION" and "App2_SESSION".

SecWebAppId is relevant in two cases:

  1. You are logging transactions/alerts to the ModSecurity Console + and you want to use the web application ID to search only the + transactions belonging to that application.

  2. You are using the data persistence facility (collections + SESSION and USER) and you need to avoid collisions between sessions + and users belonging to different applications.

Processing Phases

ModSecurity 2.x allows rules to be placed in one of the following + five phases:

  1. Request headers (REQUEST_HEADERS)

  2. Request body (REQUEST_BODY)

  3. Response headers (RESPONSE_HEADERS)

  4. Response body (RESPONSE_BODY)

  5. Logging (LOGGING)

Below is a diagram of the standard Apache Request Cycle. In the + diagram, the 5 ModSecurity processing phases are shown.

In order to select the phase a rule executes during, use the phase + action either directly in the rule or in using the + SecDefaultAction directive:

SecDefaultAction "log,pass,phase:2"
+SecRule REQUEST_HEADERS:Host "!^$" "deny,phase:1"

Note

Keep in mind that rules are executed according to phases, so even + if two rules are adjacent in a configuration file, but are set to + execute in different phases, they would not happen one after the other. + The order of rules in the configuration file is important only within + the rules of each phase. This is especially important when using the + skip and skipAfter actions.

Note

The LOGGING phase is special. It is executed at + the end of each transaction no matter what happened in the previous + phases. This means it will be processed even if the request was + intercepted or the allow action was used to pass the + transaction through.

Phase Request Headers

Rules in this phase are processed immediately after Apache + completes reading the request headers (post-read-request phase). At this + point the request body has not been read yet, meaning not all request + arguments are available. Rules should be placed in this phase if you + need to have them run early (before Apache does something with the + request), to do something before the request body has been read, + determine whether or not the request body should be buffered, or decide + how you want the request body to be processed (e.g. whether to parse it + as XML or not).

Note

Rules in this phase can not leverage Apache scope directives + (Directory, Location, LocationMatch, etc...) as the post-read-request + hook does not have this information yet. The exception here is the + VirtualHost directive. If you want to use ModSecurity rules inside + Apache locations, then they should run in Phase 2. Refer to the Apache + Request Cycle/ModSecurity Processing Phases diagram.

Phase Request Body

This is the general-purpose input analysis phase. Most of the + application-oriented rules should go here. In this phase you are + guaranteed to have received the request arguments (provided the request + body has been read). ModSecurity supports three encoding types for the + request body phase:

  • application/x-www-form-urlencoded - used to + transfer form data

  • multipart/form-data - used for file + transfers

  • text/xml - used for passing XML data

Other encodings are not used by most web applications.

Phase Response Headers

This phase takes place just before response headers are sent back + to the client. Run here if you want to observe the response before that + happens, and if you want to use the response headers to determine if you + want to buffer the response body. Note that some response status codes + (such as 404) are handled earlier in the request cycle by Apache and my + not be able to be triggered as expected. Additionally, there are some + response headers that are added by Apache at a later hook (such as Date, + Server and Connection) that we would not be able to trigger on or + sanitize. This should work appropriately in a proxy setup or within + phase:5 (logging).

Phase Response Body

This is the general-purpose output analysis phase. At this point + you can run rules against the response body (provided it was buffered, + of course). This is the phase where you would want to inspect the + outbound HTML for information disclosure, error messages or failed + authentication text.

Phase Logging

This phase is run just before logging takes place. The rules + placed into this phase can only affect how the logging is performed. + This phase can be used to inspect the error messages logged by Apache. + You cannot deny/block connections in this phase as it is too late. This + phase also allows for inspection of other response headers that weren't + available during phase:3 or phase:4. Note that you must be careful not + to inherit a disruptive action into a rule in this phase as this is a + configuration error in ModSecurity 2.5.0 and later versions.

Variables

The following variables are supported in ModSecurity 2.x:

ARGS

ARGS is a collection and can be used on its own + (means all arguments including the POST Payload), with a static + parameter (matches arguments with that name), or with a regular + expression (matches all arguments with name that matches the regular + expression). To look at only the query string or body arguments, see the + ARGS_GET and ARGS_POST + collections.

Some variables are actually collections, which are expanded into + more variables at runtime. The following example will examine all + request arguments:

SecRule ARGS dirty
+ Sometimes, however, you will want to look only at parts of a collection. + This can be achieved with the help of the selection + operator(colon). The following example will only look at the + arguments named p (do note that, in + general, requests can contain multiple arguments with the same name): +
SecRule ARGS:p dirty
+ It is also possible to specify exclusions. The following will examine + all request arguments for the word dirty, except + the ones named z (again, there can be + zero or more arguments named z): +
SecRule ARGS|!ARGS:z dirty
+ There is a special operator that allows you to count how many variables + there are in a collection. The following rule will trigger if there is + more than zero arguments in the request (ignore the second parameter for + the time being):
SecRule &ARGS !^0$
+ And sometimes you need to look at an array of parameters, each with a + slightly different name. In this case you can specify a regular + expression in the selection operator itself. The following rule will + look into all arguments whose names begin with id_:
SecRule ARGS:/^id_/ dirty

Note

Using ARGS:p will not result in any + invocations against the operator if argument p does not exist.

In ModSecurity 1.X, the ARGS variable stood + for QUERY_STRING + POST_PAYLOAD, + whereas now it expands to individual variables.

ARGS_COMBINED_SIZE

This variable allows you to set more targeted evaluations on the + total size of the Arguments as compared with normal Apache LimitRequest + directives. For example, you could create a rule to ensure that the + total size of the argument data is below a certain threshold (to help + prevent buffer overflow issues). Example: Block request if the size of + the arguments is above 25 characters.

SecRule REQUEST_FILENAME "^/cgi-bin/login\.php" \
+    "chain,log,deny,phase:2,t:none,t:lowercase,t:normalisePath"
+SecRule ARGS_COMBINED_SIZE "@gt 25"

ARGS_NAMES

Is a collection of the argument names. You can search for specific + argument names that you want to block. In a positive policy scenario, + you can also whitelist (using an inverted rule with the ! character) + only authorized argument names. Example: This example rule will only + allow 2 argument names - p and a. If any other argument names are + injected, it will be blocked.

SecRule REQUEST_FILENAME "/index.php" \
+    "chain,log,deny,status:403,phase:2,t:none,t:lowercase,t:normalisePath"
+SecRule ARGS_NAMES "!^(p|a)$" "t:none,t:lowercase"

ARGS_GET

ARGS_GET is similar to ARGS, + but only contains arguments from the query string.

ARGS_GET_NAMES

ARGS_GET_NAMES is similar to + ARGS_NAMES, but only contains argument names from the + query string.

ARGS_POST

ARGS_POST is similar to + ARGS, but only contains arguments from the POST + body.

ARGS_POST_NAMES

ARGS_POST_NAMES is similar to + ARGS_NAMES, but only contains argument names from the + POST body.

AUTH_TYPE

This variable holds the authentication method used to validate a + user. Example:

SecRule AUTH_TYPE "basic" log,deny,status:403,phase:1,t:lowercase

Note

This data will not be available in a proxy-mode deployment as the + authentication is not local. In a proxy-mode deployment, you would need + to inspect the REQUEST_HEADERS:Authorization + header.

ENV

Collection, requires a single parameter (after colon). The + ENV variable is set with setenv and does not give + access to the CGI environment variables. Example:

SecRule REQUEST_FILENAME "printenv" pass,setenv:tag=suspicious
+SecRule ENV:tag "suspicious"

FILES

Collection. Contains a collection of original file names (as they + were called on the remote user's file system). Note: only available if + files were extracted from the request body. Example:

SecRule FILES "\.conf$" log,deny,status:403,phase:2

FILES_COMBINED_SIZE

Single value. Total size of the uploaded files. Note: only + available if files were extracted from the request body. Example:

SecRule FILES_COMBINED_SIZE "@gt 1000" log,deny,status:403,phase:2

FILES_NAMES

Collection w/o parameter. Contains a list of form fields that were + used for file upload. Note: only available if files were extracted from + the request body. Example:

SecRule FILES_NAMES "^upfile$" log,deny,status:403,phase:2

FILES_SIZES

Collection. Contains a list of file sizes. Useful for implementing + a size limitation on individual uploaded files. Note: only available if + files were extracted from the request body. Example:

SecRule FILES_SIZES "@gt 100" log,deny,status:403,phase:2

FILES_TMPNAMES

Collection. Contains a collection of temporary files' names on the + disk. Useful when used together with @inspectFile. Note: only available if files + were extracted from the request body. Example:

SecRule FILES_TMPNAMES "@inspectFile /path/to/inspect_script.pl"

GEO

GEO is a collection populated by the results of + the last @geoLookup operator. The + collection can be used to match geographical fields looked from an IP + address or hostname.

Available since ModSecurity 2.5.0.

Fields:

  • COUNTRY_CODE: Two character country code. + EX: US, GB, etc.

  • COUNTRY_CODE3: Up to three character + country code.

  • COUNTRY_NAME: The full country + name.

  • COUNTRY_CONTINENT: The two character + continent that the country is located. EX: EU

  • REGION: The two character region. For US, + this is state. For Canada, providence, etc.

  • CITY: The city name if supported by the + database.

  • POSTAL_CODE: The postal code if supported + by the database.

  • LATITUDE: The latitude if supported by + the database.

  • LONGITUDE: The longitude if supported by + the database.

  • DMA_CODE: The metropolitan area code if + supported by the database. (US only)

  • AREA_CODE: The phone system area code. + (US only)

Example:

SecGeoLookupDb /usr/local/geo/data/GeoLiteCity.dat
+...
+SecRule REMOTE_ADDR "@geoLookup" "chain,drop,msg:'Non-GB IP address'"
+SecRule GEO:COUNTRY_CODE "!@streq GB"

HIGHEST_SEVERITY

This variable holds the highest severity of any rules that have + matched so far. Severities are numeric values and thus can be used with + comparison operators such as @lt, + etc.

Note

Higher severities have a lower numeric value.

A value of 255 indicates no severity has been set.

SecRule HIGHEST_SEVERITY "@le 2" "phase:2,deny,status:500,msg:'severity %{HIGHEST_SEVERITY}'"

MATCHED_VAR

This variable holds the value of the variable that was matched + against. It is similar to the TX:0, except it can be used for all + operators and does not require that the capture action be specified.

SecRule ARGS pattern chain,deny
+...
+SecRule MATCHED_VAR "further scrutiny"

MATCHED_VAR_NAME

This variable holds the full name of the variable that was matched + against.

SecRule ARGS pattern setvar:tx.mymatch=%{MATCHED_VAR_NAME}
+...
+SecRule TX:MYMATCH "@eq ARGS:param" deny

MODSEC_BUILD

This variable holds the ModSecurity build number. This variable is + intended to be used to check the build number prior to using a feature + that is available only in a certain build. Example:

SecRule MODSEC_BUILD "!@ge 02050102" skipAfter:12345
+SecRule ARGS "@pm some key words" id:12345,deny,status:500

MULTIPART_CRLF_LF_LINES

This flag variable will be set to 1 whenever a + multi-part request uses mixed line terminators. The + multipart/form-data RFC requires + CRLF sequence to be used to terminate lines. Since + some client implementations use only LF to terminate + lines you might want to allow them to proceed under certain + circumstances (if you want to do this you will need to stop using + MULTIPART_STRICT_ERROR and check each multi-part flag + variable individually, avoiding MULTIPART_LF_LINE). + However, mixing CRLF and LF line + terminators is dangerous as it can allow for evasion. Therefore, in such + cases, you will have to add a check for + MULTIPART_CRLF_LF_LINES.

MULTIPART_STRICT_ERROR

MULTIPART_STRICT_ERROR will be set to + 1 when any of the following variables is also set to + 1: REQBODY_PROCESSOR_ERROR, + MULTIPART_BOUNDARY_QUOTED, + MULTIPART_BOUNDARY_WHITESPACE, + MULTIPART_DATA_BEFORE, + MULTIPART_DATA_AFTER, + MULTIPART_HEADER_FOLDING, + MULTIPART_LF_LINE, + MULTIPART_SEMICOLON_MISSING + MULTIPART_INVALID_QUOTING. Each of these variables + covers one unusual (although sometimes legal) aspect of the request body + in multipart/form-data format. Your policies should + always contain a rule to check either this variable + (easier) or one or more individual variables (if you know exactly what + you want to accomplish). Depending on the rate of false positives and + your default policy you should decide whether to block or just warn when + the rule is triggered.

The best way to use this variable is as in the example + below:

SecRule MULTIPART_STRICT_ERROR "!@eq 0" \
+"phase:2,t:none,log,deny,msg:'Multipart request body \
+failed strict validation: \
+PE %{REQBODY_PROCESSOR_ERROR}, \
+BQ %{MULTIPART_BOUNDARY_QUOTED}, \
+BW %{MULTIPART_BOUNDARY_WHITESPACE}, \
+DB %{MULTIPART_DATA_BEFORE}, \
+DA %{MULTIPART_DATA_AFTER}, \
+HF %{MULTIPART_HEADER_FOLDING}, \
+LF %{MULTIPART_LF_LINE}, \
+SM %{MULTIPART_SEMICOLON_MISSING}, \
+IQ %{MULTIPART_INVALID_QUOTING}'"

The multipart/form-data parser was upgraded in + ModSecurity v2.1.3 to actively look for signs of evasion. Many variables + (as listed above) were added to expose various facts discovered during + the parsing process. The MULTIPART_STRICT_ERROR + variable is handy to check on all abnormalities at once. The individual + variables allow detection to be fine-tuned according to your + circumstances in order to reduce the number of false positives. Detailed + analysis of various evasion techniques covered will be released as a + separated document at a later date.

MULTIPART_UNMATCHED_BOUNDARY

Set to 1 when, during the parsing phase of a + multipart/request-body, ModSecurity encounters what + feels like a boundary but it is not. Such an event may occur when + evasion of ModSecurity is attempted.

The best way to use this variable is as in the example + below:

SecRule MULTIPART_UNMATCHED_BOUNDARY "!@eq 0" \
+"phase:2,t:none,log,deny,msg:'Multipart parser detected a possible unmatched boundary.'"

Change the rule from blocking to logging-only if many false + positives are encountered.

PATH_INFO

Besides passing query information to a script/handler, you can + also pass additional data, known as extra path information, as part of + the URL. Example:

SecRule PATH_INFO "^/(bin|etc|sbin|opt|usr)"

QUERY_STRING

This variable holds form data passed to the script/handler by + appending data after a question mark. Warning: Not URL-decoded. + Example:

SecRule QUERY_STRING "attack"

REMOTE_ADDR

This variable holds the IP address of the remote client. + Example:

SecRule REMOTE_ADDR "^192\.168\.1\.101$"

REMOTE_HOST

If HostnameLookUps are set to On, then this variable will hold the + DNS resolved remote host name. If it is set to Off, then it will hold + the remote IP address. Possible uses for this variable would be to deny + known bad client hosts or network blocks, or conversely, to allow in + authorized hosts. Example:

SecRule REMOTE_HOST "\.evil\.network\org$"

REMOTE_PORT

This variable holds information on the source port that the client + used when initiating the connection to our web server. Example: in this + example, we are evaluating to see if the REMOTE_PORT + is less than 1024, which would indicate that the user is a privileged + user (root).

SecRule REMOTE_PORT "@lt 1024" phase:1,log,pass,setenv:remote_port=privileged

REMOTE_USER

This variable holds the username of the authenticated user. If + there are no password (basic|digest) access controls in place, then this + variable will be empty. Example:

SecRule REMOTE_USER "admin"

Note

This data will not be available in a proxy-mode deployment as the + authentication is not local.

REQBODY_PROCESSOR

Built-in processors are URLENCODED, + MULTIPART, and XML. + Example:

SecRule REQBODY_PROCESSOR "^XML$ chain
+SecRule XML "@validateDTD /opt/apache-frontend/conf/xml.dtd"

REQBODY_PROCESSOR_ERROR

Possible values are 0 (no error) or 1 (error). This variable will + be set by request body processors (typically the + multipart/request-data parser or the XML parser) + when they fail to properly parse a request payload.

Example:

SecRule REQBODY_PROCESSOR_ERROR "@eq 1" deny,phase:2

Note

Your policies must have a rule to check + REQBODY_PROCESSOR_ERROR at the beginning of phase 2. Failure to do so + will leave the door open for impedance mismatch attacks. It is + possible, for example, that a payload that cannot be parsed by + ModSecurity can be successfully parsed by more tolerant parser + operating in the application. If your policy dictates blocking then + you should reject the request if error is detected. When operating in + detection-only mode your rule should alert with high severity when + request body processing fails.

REQBODY_PROCESSOR_ERROR_MSG

Empty, or contains the error message from the processor. + Example:

SecRule REQBODY_PROCESSOR_ERROR_MSG "failed to parse" t:lowercase

REQUEST_BASENAME

This variable holds just the filename part of + REQUEST_FILENAME (e.g. index.php).

Example:

SecRule REQUEST_BASENAME "^login\.php$" phase:2,t:none,t:lowercase

Note

Please note that anti-evasion transformations are not applied to + this variable by default. REQUEST_BASENAME will + recognise both / and \ as path + separators.

REQUEST_BODY

This variable holds the data in the request body (including + POST_PAYLOAD data). REQUEST_BODY + should be used if the original order of the arguments is important + (ARGS should be used in all other cases). + Example:

SecRule REQUEST_BODY "^username=\w{25,}\&password=\w{25,}\&Submit\=login$"

Note

This variable is only available if the + URLENCODED request body processor parsed a request + body. This will occur by default when an + application/x-www-form-urlencoded is detected, or + the URLENCODED request body parser is forced. As of + 2.5.7 it is possible to force the presence of the + REQUEST_BODY variable, but only when there is no + request body processor defined, using the + ctl:forceRequestBodyVariable option in the + REQUEST_HEADERS phase.

REQUEST_COOKIES

This variable is a collection of all of the cookie data. Example: + the following example is using the Ampersand special operator to count + how many variables are in the collection. In this rule, it would trigger + if the request does not include any Cookie headers.

SecRule &REQUEST_COOKIES "@eq 0"

REQUEST_COOKIES_NAMES

This variable is a collection of the cookie names in the request + headers. Example: the following rule will trigger if the JSESSIONID + cookie is not present.

SecRule &REQUEST_COOKIES_NAMES:JSESSIONID "@eq 0"

REQUEST_FILENAME

This variable holds the relative REQUEST_URI + minus the QUERY_STRING part (e.g. /index.php). + Example:

SecRule REQUEST_FILENAME "^/cgi-bin/login\.php$" phase:2,t:none,t:normalisePath

Note

Please note that anti-evasion transformations are not used on + REQUEST_FILENAME by default.

REQUEST_HEADERS

This variable can be used as either a collection of all of the + request headers or can be used to specify individual headers (by using + REQUEST_HEADERS:Header-Name). Example: the first + example uses REQUEST_HEADERS as a collection and is + applying the validateUrlEncoding operator against all + headers.

SecRule REQUEST_HEADERS "@validateUrlEncoding"

Example: the second example is targeting only the + Host header.

SecRule REQUEST_HEADERS:Host "^[\d\.]+$" \
+    "deny,log,status:400,msg:'Host header is a numeric IP address'"

REQUEST_HEADERS_NAMES

This variable is a collection of the names of all of the request + headers. Example:

SecRule REQUEST_HEADERS_NAMES "^x-forwarded-for" \
+    "log,deny,status:403,t:lowercase,msg:'Proxy Server Used'"

REQUEST_LINE

This variable holds the complete request line sent to the server + (including the REQUEST_METHOD and HTTP version data). Example: this + example rule will trigger if the request method is something other than + GET, HEAD, POST or if the HTTP is something other than HTTP/0.9, 1.0 or + 1.1.

SecRule REQUEST_LINE "!(^((?:(?:pos|ge)t|head))|http/(0\.9|1\.0|1\.1)$)" t:none,t:lowercase

REQUEST_METHOD

This variable holds the request method used by the client.

The following example will trigger if the request method is either + CONNECT or TRACE.

SecRule REQUEST_METHOD "^((?:connect|trace))$" t:none,t:lowercase

REQUEST_PROTOCOL

This variable holds the request protocol version information. + Example:

SecRule REQUEST_PROTOCOL "!^http/(0\.9|1\.0|1\.1)$" t:none,t:lowercase

REQUEST_URI

This variable holds the full URL including the + QUERY_STRING data (e.g. /index.php?p=X), however it + will never contain a domain name, even if it was provided on the request + line. It also does not include either the + REQUEST_METHOD or the HTTP version info.

Example:

SecRule REQUEST_URI "attack" phase:1,t:none,t:urlDecode,t:lowercase,t:normalisePath

Note

Please note that anti-evasion transformations are not used on + REQUEST_URI by default.

REQUEST_URI_RAW

Same as REQUEST_URI but will contain the domain + name if it was provided on the request line (e.g. + http://www.example.com/index.php?p=X).

Example:

SecRule REQUEST_URI_RAW "http:/" phase:1,t:none,t:urlDecode,t:lowercase,t:normalisePath

Note

Please note that anti-evasion transformations are not used on + REQUEST_URI_RAW by default.

RESPONSE_BODY

This variable holds the data for the response payload.

Example:

SecRule RESPONSE_BODY "ODBC Error Code"

RESPONSE_CONTENT_LENGTH

Response body length in bytes. Can be available starting with + phase 3 but it does not have to be (as the length of response body is + not always known in advance.) If the size is not known this variable + will contain a zero. If RESPONSE_CONTENT_LENGTH + contains a zero in phase 5 that means the actual size of the response + body was 0.

The value of this variable can change between phases if the body + is modified. For example, in embedded mode + mod_deflate can compress the response body between + phases 4 and 5.

RESPONSE_CONTENT_TYPE

Response content type. Only available starting with phase + 3.

RESPONSE_HEADERS

This variable is similar to the REQUEST_HEADERS variable and can + be used in the same manner. Example:

SecRule RESPONSE_HEADERS:X-Cache "MISS"

Note

This variable may not have access to some headers when running in + embedded-mode. Headers such as Server, Date, Connection and Content-Type + are added during a later Apache hook just prior to sending the data to + the client. This data should be available, however, either during + ModSecurity phase:5 (logging) or when running in proxy-mode.

RESPONSE_HEADERS_NAMES

This variable is a collection of the response header names. + Example:

SecRule RESPONSE_HEADERS_NAMES "Set-Cookie"

Note

Same limitations as RESPONSE_HEADERS with regards to access to + some headers in embedded-mode.

RESPONSE_PROTOCOL

This variable holds the HTTP response protocol information. + Example:

SecRule RESPONSE_PROTOCOL "^HTTP\/0\.9"

RESPONSE_STATUS

This variable holds the HTTP response status code as generated by + Apache. Example:

SecRule RESPONSE_STATUS "^[45]"

Note

This directive may not work as expected in embedded-mode as Apache + handles many of the stock response codes (404, 401, etc...) earlier in + Phase 2. This variable should work as expected in a proxy-mode + deployment.

RULE

This variable provides access to the id, rev, + severity, logdata, and msg fields of the rule that triggered the + action. Only available for expansion in action strings (e.g.setvar:tx.varname=%{rule.id}). Example:

SecRule &REQUEST_HEADERS:Host "@eq 0" "log,deny,setvar:tx.varname=%{rule.id}"

SCRIPT_BASENAME

This variable holds just the local filename part of + SCRIPT_FILENAME. Example:

SecRule SCRIPT_BASENAME "^login\.php$"

Note

This variable is not available in proxy mode.

SCRIPT_FILENAME

This variable holds the full path on the server to the requested + script. (e.g. SCRIPT_NAME plus the server path). Example:

SecRule SCRIPT_FILENAME "^/usr/local/apache/cgi-bin/login\.php$"

Note

This variable is not available in proxy mode.

SCRIPT_GID

This variable holds the group id (numerical value) of the group + owner of the script. Example:

SecRule SCRIPT_GID "!^46$"

Note

This variable is not available in proxy mode.

SCRIPT_GROUPNAME

This variable holds the group name of the group owner of the + script. Example:

SecRule SCRIPT_GROUPNAME "!^apache$"

Note

This variable is not available in proxy mode.

SCRIPT_MODE

This variable holds the script's permissions mode data (numerical + - 1=execute, 2=write, 4=read and 7=read/write/execute). Example: will + trigger if the script has the WRITE permissions set.

SecRule SCRIPT_MODE "^(2|3|6|7)$"

Note

This variable is not available in proxy mode.

SCRIPT_UID

This variable holds the user id (numerical value) of the owner of + the script. Example: the example rule below will trigger if the UID is + not 46 (the Apache user).

SecRule SCRIPT_UID "!^46$"

Note

This variable is not available in proxy mode.

SCRIPT_USERNAME

This variable holds the username of the owner of the script. + Example:

SecRule SCRIPT_USERNAME "!^apache$"

Note

This variable is not available in proxy mode.

SERVER_ADDR

This variable contains the IP address of the server. + Example:

SecRule SERVER_ADDR "^192\.168\.1\.100$"

SERVER_NAME

This variable contains the server's hostname or IP address. + Example:

SecRule SERVER_NAME "hostname\.com$"

Note

This data is taken from the Host header submitted in the client + request.

SERVER_PORT

This variable contains the local port that the web server is + listening on. Example:

SecRule SERVER_PORT "^80$"

SESSION

This variable is a collection, available only after setsid is executed. Example: the following + example shows how to initialize a SESSION collection with setsid, how to + use setvar to increase the session.score values, how to set the + session.blocked variable and finally how to deny the connection based on + the session:blocked value.

SecRule REQUEST_COOKIES:PHPSESSID !^$ chain,nolog,pass
+SecAction setsid:%{REQUEST_COOKIES.PHPSESSID}
+SecRule REQUEST_URI "^/cgi-bin/finger$" \
+    "phase:2,t:none,t:lowercase,t:normalisePath,pass,log,setvar:session.score=+10"
+SecRule SESSION:SCORE "@gt 50" "pass,log,setvar:session.blocked=1"
+SecRule SESSION:BLOCKED "@eq 1" "log,deny,status:403"

SESSIONID

This variable is the value set with setsid. Example:

SecRule SESSIONID !^$ chain,nolog,pass
+SecRule REQUEST_COOKIES:PHPSESSID !^$
+SecAction setsid:%{REQUEST_COOKIES.PHPSESSID}

TIME

This variable holds a formatted string representing the time + (hour:minute:second). Example:

SecRule TIME "^(([1](8|9))|([2](0|1|2|3))):\d{2}:\d{2}$"

TIME_DAY

This variable holds the current date (1-31). Example: this rule + would trigger anytime between the 10th and 20th days of the + month.

SecRule TIME_DAY "^(([1](0|1|2|3|4|5|6|7|8|9))|20)$"

TIME_EPOCH

This variable holds the time in seconds since 1970. + Example:

SecRule TIME_EPOCH "@gt 1000"

TIME_HOUR

This variable holds the current hour (0-23). Example: this rule + would trigger during "off hours".

SecRule TIME_HOUR "^(0|1|2|3|4|5|6|[1](8|9)|[2](0|1|2|3))$"

TIME_MIN

This variable holds the current minute (0-59). Example: this rule + would trigger during the last half hour of every hour.

SecRule TIME_MIN "^(3|4|5)"

TIME_MON

This variable holds the current month (0-11). Example: this rule + would match if the month was either November (10) or December + (11).

SecRule TIME_MON "^1"

TIME_SEC

This variable holds the current second count (0-59). + Example:

SecRule TIME_SEC "@gt 30"

TIME_WDAY

This variable holds the current weekday (0-6). Example: this rule + would trigger only on week-ends (Saturday and Sunday).

SecRule TIME_WDAY "^(0|6)$"

TIME_YEAR

This variable holds the current four-digit year data. + Example:

SecRule TIME_YEAR "^2006$"

TX

Transaction Collection. This is used to store pieces of data, + create a transaction anomaly score, and so on. Transaction variables are + set for 1 request/response cycle. The scoring and evaluation will not + last past the current request/response process. Example: In this + example, we are using setvar to increase the tx.score value by 5 points. + We then have a follow-up run that will evaluate the transactional score + this request and then it will decided whether or not to allow/deny the + request through.

The following is a list of reserved names in the TX + collection:

  • TX:0 - The matching value + when using the @rx or @pm operator with the capture action.

  • TX:1-TX:9 - The captured + subexpression value when using the @rx operator with capturing parens and the + capture action.

SecRule WEBSERVER_ERROR_LOG "does not exist" "phase:5,pass,setvar:tx.score=+5"
+SecRule TX:SCORE "@gt 20" deny,log

USERID

This variable is the value set with setuid. Example:

SecAction setuid:%{REMOTE_USER},nolog
+SecRule USERID "Admin"

WEBAPPID

This variable is the value set with SecWebAppId. Example:

SecWebAppId "WebApp1"
+SecRule WEBAPPID "WebApp1" "chain,log,deny,status:403"
+SecRule REQUEST_HEADERS:Transfer-Encoding "!^$"

WEBSERVER_ERROR_LOG

Contains zero or more error messages produced by the web server. + Access to this variable is in phase:5 (logging). Example:

SecRule WEBSERVER_ERROR_LOG "File does not exist" "phase:5,setvar:tx.score=+5"

XML

Can be used standalone (as a target for + validateDTD and validateSchema) or + with an XPath expression parameter (which makes it a valid target for + any function that accepts plain text). Example using XPath:

SecDefaultAction log,deny,status:403,phase:2
+SecRule REQUEST_HEADERS:Content-Type ^text/xml$ \
+    phase:1,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML
+SecRule REQBODY_PROCESSOR "!^XML$" skipAfter:12345
+SecRule XML:/employees/employee/name/text() Fred
+SecRule XML:/xq:employees/employee/name/text() Fred \
+    id:12345,xmlns:xq=http://www.example.com/employees

The first XPath expression does not use namespaces. It would match + against payload such as this one:

<employees>
+    <employee>
+        <name>Fred Jones</name>
+        <address location="home">
+            <street>900 Aurora Ave.</street>
+            <city>Seattle</city>
+            <state>WA</state>
+            <zip>98115</zip>
+        </address>
+        <address location="work">
+            <street>2011 152nd Avenue NE</street>
+            <city>Redmond</city>
+            <state>WA</state>
+            <zip>98052</zip>
+        </address>
+        <phone location="work">(425)555-5665</phone>
+        <phone location="home">(206)555-5555</phone>
+        <phone location="mobile">(206)555-4321</phone>
+    </employee>
+</employees>

The second XPath expression does use namespaces. It would match + the following payload:

<xq:employees xmlns:xq="http://www.example.com/employees">
+    <employee>
+        <name>Fred Jones</name>
+        <address location="home">
+            <street>900 Aurora Ave.</street>
+            <city>Seattle</city>
+            <state>WA</state>
+            <zip>98115</zip>
+        </address>
+        <address location="work">
+            <street>2011 152nd Avenue NE</street>
+            <city>Redmond</city>
+            <state>WA</state>
+            <zip>98052</zip>
+        </address>
+        <phone location="work">(425)555-5665</phone>
+        <phone location="home">(206)555-5555</phone>
+        <phone location="mobile">(206)555-4321</phone>
+    </employee>
+</xq:employees>

Note the different namespace used in the second example.

To learn more about XPath we suggest the following + resources:

Transformation functions

When ModSecurity receives request or response information, it makes + a copy of this data and places it into memory. It is on this data in + memory that transformation functions are applied. The raw request/response + data is never altered. Transformation functions are used to transform a + variable before testing it in a rule.

Note

There are no default transformation functions as there were in + previous versions of ModSecurity.

The following rule will ensure that an attacker does not use mixed + case in order to evade the ModSecurity rule:

SecRule ARGS:p "xp_cmdshell" "t:lowercase"
+ multiple transformation actions can be used in the same rule, for example + the following rule also ensures that an attacker does not use URL encoding + (%xx encoding) for evasion. Note the order of the transformation + functions, which ensures that a URL encoded letter is first decoded and + than translated to lower case.

SecRule ARGS:p "xp_cmdshell" "t:urlDecode,t:lowercase"

One can use the SecDefaultAction command to ensure the translation + occurs for every rule until the next. Note that transformation actions are + additive, so if a rule explicitly list actions, the translation actions + set by SecDefaultAction are still performed.

SecDefaultAction t:urlDecode,t:lowercase

The following transformation functions are supported:

base64Decode

This function decodes a base64-encoded string.

base64Encode

This function encodes input string using base64 encoding.

compressWhitespace

It converts whitespace characters (32, \f, \t, \n, \r, \v, 160) to + spaces (ASCII 32) and then compresses multiple consecutive space + characters into one.

cssDecode

Decodes CSS-encoded characters, as specified at http://www.w3.org/TR/REC-CSS2/syndata.html. + This function uses only up to two bytes in the decoding process, meaning + it is useful to uncover ASCII characters (that wouldn't normally be + encoded) encoded using CSS encoding, or to counter evasion which is a + combination of a backslash and non-hexadecimal characters (e.g. + ja\vascript is equivalent to + javascript).

escapeSeqDecode

This function decode ANSI C escape sequences: \a, \b, + \f, \n, \r, + \t, \v, \\, + \?, \', \", + \xHH (hexadecimal), \0OOO (octal). Invalid encodings are left in + the output.

hexDecode

This function decodes a hex-encoded string.

hexEncode

This function encodes input as hex-encoded string.

htmlEntityDecode

This function decodes HTML entities present in input. The + following variants are supported:

  • &#xHH and &#xHH; (where H is any hexadecimal + number)

  • &#DDD and &#DDD; (where D is any decimal + number)

  • &quot and &quot;

  • &nbsp and &nbsp;

  • &lt and &lt;

  • &gt and &gt;

This function will convert any entity into a single byte only, + possibly resulting in a loss of information. It is thus useful to + uncover bytes that would otherwise not need to be encoded, but it cannot + do anything with the characters from the range above 255.

jsDecode

Decodes JavaScript escape sequences. If a + \uHHHH code is in the range of + FF01-FF5E (the full width ASCII + codes), then the higher byte is used to detect and adjust the lower + byte. Otherwise, only the lower byte will be used and the higher byte + zeroed.

length

This function converts the input to its numeric length (count of + bytes).

lowercase

This function converts all characters to lowercase using the + current C locale.

md5

This function calculates an MD5 hash from input. Note that the + computed hash is in a raw binary form and may need encoded into text to + be usable (for example: t:md5,t:hexEncode).

none

Not an actual transformation function, but an instruction to + ModSecurity to remove all transformation functions associated with the + current rule.

normalisePath

This function will remove multiple slashes, self-references and + directory back-references (except when they are at the beginning of the + input).

normalisePathWin

Same as normalisePath, but will first convert + backslash characters to forward slashes.

parityEven7bit

This function calculates even parity of 7-bit data replacing the + 8th bit of each target byte with the calculated parity bit.

parityOdd7bit

This function calculates odd parity of 7-bit data replacing the + 8th bit of each target byte with the calculated parity bit.

parityZero7bit

This function calculates zero parity of 7-bit data replacing the + 8th bit of each target byte with a zero parity bit which allows + inspection of even/odd parity 7bit data as ASCII7 data.

removeNulls

This function removes NULL bytes from input.

removeWhitespace

This function removes all whitespace characters from input.

replaceComments

This function replaces each occurrence of a C-style comments + (/* ... */) with a single space + (multiple consecutive occurrences of a space will not be compressed). + Unterminated comments will too be replaced with a space (ASCII 32). + However, a standalone termination of a comment (*/) will not be acted upon.

replaceNulls

This function is enabled by default. It replaces NULL bytes in + input with spaces (ASCII 32).

urlDecode

This function decodes an URL-encoded input string. Invalid + encodings (i.e. the ones that use non-hexadecimal characters, or the + ones that are at the end of string and have one or two characters + missing) will not be converted. If you want to detect invalid encodings + use the @validateUrlEncoding + operator. The transformation function should not be used against + variables that have already been URL-decoded unless it is your intention + to perform URL decoding twice!

urlDecodeUni

In addition to decoding %xx like urlDecode, urlDecodeUni also decodes %uXXXX encoding. If the code is in the range + of FF01-FF5E (the full width ASCII + codes), then the higher byte is used to detect and adjust the lower + byte. Otherwise, only the lower byte will be used and the higher byte + zeroed.

urlEncode

This function encodes input using URL encoding.

sha1

This function calculates a SHA1 hash from input. Note that the + computed hash is in a raw binary form and may need encoded to be usable + (for example: t:sha1,t:hexEncode).

trimLeft

This function removes whitespace from the left side of + input.

trimRight

This function removes whitespace from the right side of + input.

trim

This function removes whitespace from both the left and right + sides of input.

Actions

Each action belongs to one of five groups:

Disruptive actions

Cause ModSecurity to do something. In many cases something + means block transaction, but not in all. For example, the allow + action is classified as a disruptive action, but it does the + opposite of blocking. There can only be one disruptive action per + rule (if there are multiple disruptive actions present, or + inherited, only the last one will take effect), or rule chain (in a + chain, a disruptive action can only appear in the first + rule).

Non-disruptive actions

Do something, but that something does not and cannot affect + the rule processing flow. Setting a variable, or changing its value + is an example of a non-disruptive action. Non-disruptive action can + appear in any rule, including each rule belonging to a chain.

Flow actions

These actions affect the rule flow (for example + skip or skipAfter).

Meta-data actions

Meta-data actions are used to provide more information about + rules. Examples include id, + rev, severity and + msg.

Data actions

Not really actions, these are mere containers that hold data + used by other actions. For example, the status + action holds the status that will be used for blocking (if it takes + place).

allow

Description: Stops rule processing on a + successful match and allows the transaction to proceed.

Action Group: Disruptive

Example:

SecRule REMOTE_ADDR "^192\.168\.1\.100$" nolog,phase:1,allow

Prior to ModSecurity 2.5 the allow action would + only affect the current phase. An allow in phase 1 + would skip processing the remaining rules in phase 1 but the rules from + phase 2 would execute. Starting with v2.5.0 allow was + enhanced to allow for fine-grained control of what is done. The + following rules now apply:

  1. If used one its own, like in the example above, + allow will affect the entire transaction, + stopping processing of the current phase but also skipping over all + other phases apart from the logging phase. (The logging phase is + special; it is designed to always execute.)

  2. If used with parameter "phase", allow will + cause the engine to stop processing the current phase. Other phases + will continue as normal.

  3. If used with parameter "request", allow + will cause the engine to stop processing the current phase. The next + phase to be processed will be phase + RESPONSE_HEADERS.

Examples:

# Do not process request but process response.
+SecAction phase:1,allow:request
+
+# Do not process transaction (request and response).
+SecAction phase:1,allow
+

If you want to allow a response through, put a rule in phase + RESPONSE_HEADERS and simply use + allow on its own:

# Allow response through.
+SecAction phase:3,allow

append

Description: Appends text given as parameter + to the end of response body. For this action to work content injection + must be enabled by setting SecContentInjection to + On. Also make sure you check the content type of the + response before you make changes to it (e.g. you don't want to inject + stuff into images).

Action Group: Non-disruptive

Processing Phases: 3 and 4.

Example:

SecRule RESPONSE_CONTENT_TYPE "^text/html" "nolog,pass,append:'<hr>Footer'"

Note

While macro expansion is allowed in the additional content, you + are strongly cautioned against inserting user defined data + fields.

auditlog

Description: Marks the transaction for + logging in the audit log.

Action Group: Non-disruptive

Example:

SecRule REMOTE_ADDR "^192\.168\.1\.100$" auditlog,phase:1,allow

Note

The auditlog action is now explicit if log is already + specified.

block

Description: Performs the default disruptive + action.

Action Group: Disruptive

It is intended to be used by ruleset writers to signify that the + rule was intended to block and leaves the "how" up to the administrator. + This action is currently a placeholder which will just be replaced by + the action from the last SecDefaultAction in the same + context. Using the block action with the + SecRuleUpdateActionById directive allows a rule to be + reverted back to the previous SecDefaultAction + disruptive action.

In future versions of ModSecurity, more control and functionality + will be added to define "how" to block.

Examples:

In the following example, the second rule will "deny" because of + the SecDefaultAction disruptive action. The intent being that the + administrator could easily change this to another disruptive action + without editing the actual rules.

### Administrator defines "how" to block (deny,status:403)...
+SecDefaultAction phase:2,deny,status:403,log,auditlog
+
+### Included from a rulest...
+# Intent is to warn for this User Agent
+SecRule REQUEST_HEADERS:User-Agent "perl" "phase:2,pass,msg:'Perl based user agent identified'"
+# Intent is to block for this User Agent, "how" described in SecDefaultAction
+SecRule REQUEST_HEADERS:User-Agent "nikto" "phase:2,block,msg:'Nikto Scanners Identified'"

In the following example, The rule is reverted back to the + pass action defined in the SecDefaultAction directive + by using the SecRuleUpdateActionById directive in + conjuction with the block action. This allows an + administrator to override an action in a 3rd party rule without + modifying the rule itself.

### Administrator defines "how" to block (deny,status:403)...
+SecDefaultAction phase:2,pass,log,auditlog
+
+### Included from a rulest...
+SecRule REQUEST_HEADERS:User-Agent "nikto" "id:1,phase:2,deny,msg:'Nikto Scanners Identified'"
+
+### Added by the administrator
+SecRuleUpdateActionById 1 "block"

capture

Description: When used together with the + regular expression operator, capture action will create copies of + regular expression captures and place them into the transaction variable + collection. Up to ten captures will be copied on a successful pattern + match, each with a name consisting of a digit from 0 to 9.

Action Group: Non-disruptive

Example:

SecRule REQUEST_BODY "^username=(\w{25,})" phase:2,capture,t:none,chain
+SecRule TX:1 "(?:(?:a(dmin|nonymous)))"

Note

The 0 data captures the entire REGEX match and 1 captures the data + in the first parens, etc...

chain

Description: Chains the rule where the action + is placed with the rule that immediately follows it. The result is + called a rule chain. Chained rules allow for more + complex rule matches where you want to use a number of different + VARIABLES to create a better rule and to help prevent false + positives.

Action Group: Flow

Example:

# Refuse to accept POST requests that do
+# not specify request body length. Do note that
+# this rule should be preceeded by a rule that verifies
+# only valid request methods (e.g. GET, HEAD and POST) are used.
+SecRule REQUEST_METHOD ^POST$ chain,t:none
+SecRule REQUEST_HEADERS:Content-Length ^$ t:none

Note

In programming language concepts, think of chained rules + somewhat similar to AND conditional statements. The actions specified + in the first portion of the chained rule will only be triggered if all + of the variable checks return positive hits. If one aspect of the + chained rule is negative, then the entire rule chain is negative. Also + note that disruptive actions, execution phases, metadata actions (id, + rev, msg), skip and skipAfter actions can only be specified on by the + chain starter rule.

ctl

Description: The ctl action allows + configuration options to be updated for the transaction.

Action Group: Non-disruptive

Example:

# Parse requests with Content-Type "text/xml" as XML 
+SecRule REQUEST_CONTENT_TYPE ^text/xml nolog,pass,ctl:requestBodyProcessor=XML

Note

The following configuration options are supported:

  1. auditEngine

  2. auditLogParts

  3. debugLogLevel

  4. ruleRemoveById (single rule + ID, or a single rule ID range accepted as parameter)

  5. requestBodyAccess

  6. forceRequestBodyVariable

  7. requestBodyLimit

  8. requestBodyProcessor

  9. responseBodyAccess

  10. responseBodyLimit

  11. ruleEngine

With the exception of + requestBodyProcessor and + forceRequestBodyVariable, each configuration option + corresponds to one configuration directive and the usage is + identical.

The requestBodyProcessor option allows you to + configure the request body processor. By default ModSecurity will use + the URLENCODED and MULTIPART processors to process an application/x-www-form-urlencoded and a + multipart/form-data bodies, + respectively. A third processor, XML, is also + supported, but it is never used implicitly. Instead you must tell + ModSecurity to use it by placing a few rules in the REQUEST_HEADERS processing phase. After the + request body was processed as XML you will be able to use the + XML-related features to inspect it.

Request body processors will not interrupt a transaction if an + error occurs during parsing. Instead they will set variables REQBODY_PROCESSOR_ERROR and REQBODY_PROCESSOR_ERROR_MSG. These variables + should be inspected in the REQUEST_BODY phase and an appropriate action + taken.

The forceRequestBodyVariable option allows you + to configure the REQUEST_BODY variable to be set when + there is no request body processor configured. This allows for + inspection of request bodies of unknown types.

deny

Description: Stops rule processing and + intercepts transaction.

Action Group: Disruptive

Example:

SecRule REQUEST_HEADERS:User-Agent "nikto" "log,deny,msg:'Nikto Scanners Identified'"

deprecatevar

Description: Decrement counter based on its + age.

Action Group: Non-Disruptive

Example: The following example will decrement the counter by 60 + every 300 seconds.

SecAction deprecatevar:session.score=60/300

Note

Counter values are always positive, meaning the value will never + go below zero.

drop

Description: Immediately initiate a + "connection close" action to tear down the TCP connection by sending a + FIN packet.

Action Group: Disruptive

Example: The following example initiates an IP collection for + tracking Basic Authentication attempts. If the client goes over the + threshold of more than 25 attempts in 2 minutes, it will DROP subsequent + connections.

SecAction phase:1,initcol:ip=%{REMOTE_ADDR},nolog
+SecRule ARGS:login "!^$" \
+    nolog,phase:1,setvar:ip.auth_attempt=+1,deprecatevar:ip.auth_attempt=20/120
+SecRule IP:AUTH_ATTEMPT "@gt 25" \
+    "log,drop,phase:1,msg:'Possible Brute Force Attack'"

Note

This action is currently not available on Windows based builds. + This action is extremely useful when responding to both Brute Force and + Denial of Service attacks in that, in both cases, you want to minimize + both the network bandwidth and the data returned to the client. This + action causes error message to appear in the log "(9)Bad file + descriptor: core_output_filter: writing data to the network"

exec

Description: Executes an external + script/binary supplied as parameter. As of v2.5.0, if the parameter + supplied to exec is a Lua script (detected by the + .lua extension) the script will be processed + internally. This means you will get direct access + to the internal request context from the script. Please read the + SecRuleScript documentation for more details on how + to write Lua scripts.

Action Group: Non-disruptive

Example:

# The following is going to execute /usr/local/apache/bin/test.sh
+# as a shell script on rule match.
+SecRule REQUEST_URI "^/cgi-bin/script\.pl" \
+    "phase:2,t:none,t:lowercase,t:normalisePath,log,exec:/usr/local/apache/bin/test.sh"
+
+# The following is going to process /usr/local/apache/conf/exec.lua
+# internally as a Lua script on rule match.
+SecRule ARGS:p attack log,exec:/usr/local/apache/conf/exec.lua

Note

The exec action is executed independently from any disruptive + actions. External scripts will always be called with no parameters. + Some transaction information will be placed in environment variables. + All the usual CGI environment variables will be there. You should be + aware that forking a threaded process results in all threads being + replicated in the new process. Forking can therefore incur larger + overhead in multi-threaded operation. The script you execute must + write something (anything) to stdout. If it doesn't ModSecurity will + assume execution didn't work.

expirevar

Description: Configures a collection variable + to expire after the given time in seconds.

Action Group: Non-disruptive

Example:

SecRule REQUEST_COOKIES:JSESSIONID "!^$" nolog,phase:1,pass,chain
+SecAction setsid:%{REQUEST_COOKIES:JSESSIONID}
+SecRule REQUEST_URI "^/cgi-bin/script\.pl" \
+    "phase:2,t:none,t:lowercase,t:normalisePath,log,allow,\
+setvar:session.suspicious=1,expirevar:session.suspicious=3600,phase:1"

Note

You should use expirevar actions at the same time that you use + setvar actions in order to keep the indented expiration time. If they + are used on their own (perhaps in a SecAction directive) the expire time + could get re-set. When variables are removed from collections, and there + are no other changes, collections are not written to disk at the end of + request. This is because the variables can always be expired again when + the collection is read again on a subsequent request.

id

Description: Assigns a unique ID to the rule + or chain.

Action Group: Meta-data

Example:

SecRule &REQUEST_HEADERS:Host "@eq 0" \
+    "log,id:60008,severity:2,msg:'Request Missing a Host Header'"

Note

These are the reserved ranges:

  • 1-99,999; reserved for local (internal) use. Use as you see + fit but do not use this range for rules that are distributed to + others.

  • 100,000-199,999; reserved for internal use of the engine, to + assign to rules that do not have explicit IDs.

  • 200,000-299,999; reserved for rules published at + modsecurity.org.

  • 300,000-399,999; reserved for rules published at + gotroot.com.

  • 400,000-419,999; unused (available for reservation).

  • 420,000-429,999; reserved for ScallyWhack.

  • 430,000-899,999; unused (available for reservation).

  • 900,000-999,999; reserved for the Core Rules + project.

  • 1,000,000 and above; unused (available for + reservation).

initcol

Description: Initialises a named persistent + collection, either by loading data from storage or by creating a new + collection in memory.

Action Group: Non-disruptive

Example: The following example initiates IP address + tracking.

SecAction phase:1,initcol:ip=%{REMOTE_ADDR},nolog

Note

Normally you will want to use phase:1 along + with initcol so that the collection is available in + all phases.

Collections are loaded into memory when the initcol action is + encountered. The collection in storage will be persisted (and the + appropriate counters increased) only if it was + changed during transaction processing.

See the "Persistant Storage" section for further details.

log

Description: Indicates that a successful + match of the rule needs to be logged.

Action Group: Non-disruptive

Example:

SecAction phase:1,initcol:ip=%{REMOTE_ADDR},log

Note

This action will log matches to the Apache error log file and the + ModSecurity audit log.

logdata

Description: Allows a data fragment to be + logged as part of the alert message.

Action Group: Non-disruptive

Example:

SecRule &ARGS:p "@eq 0" "log,logdata:'%{TX.0}'"

Note

The logdata information appears in the error and/or audit log + files and is not sent back to the client in response headers. Macro + expansion is preformed so you may use variable names such as %{TX.0}, + etc. The information is properly escaped for use with logging binary + data.

msg

Description: Assigns a custom message to the + rule or chain.

Action Group: Meta-data

Example:

SecRule &REQUEST_HEADERS:Host "@eq 0" \
+    "log,id:60008,severity:2,msg:'Request Missing a Host Header'"

Note

The msg information appears in the error and/or audit log files + and is not sent back to the client in response headers.

multiMatch

Description: If enabled ModSecurity will + perform multiple operator invocations for every target, before and after + every anti-evasion transformation is performed.

Action Group: Non-disruptive

Example:

SecDefaultAction log,deny,phase:1,t:removeNulls,t:lowercase
+SecRule ARGS "attack" multiMatch

Note

Normally, variables are evaluated once, only after all + transformation functions have completed. With multiMatch, variables are + checked against the operator before and after every transformation + function that changes the input.

noauditlog

Description: Indicates that a successful + match of the rule should not be used as criteria whether the transaction + should be logged to the audit log.

Action Group: Non-disruptive

Example:

SecRule REQUEST_HEADERS:User-Agent "Test" allow,noauditlog

Note

If the SecAuditEngine is set to On, all of the transactions will + be logged. If it is set to RelevantOnly, then you can control it with + the noauditlog action. Even if the noauditlog action is applied to a + specific rule and a rule either before or after triggered an audit + event, then the transaction will be logged to the audit log. The correct + way to disable audit logging for the entire transaction is to use + "ctl:auditEngine=Off"

nolog

Description: Prevents rule matches from + appearing in both the error and audit logs.

Action Group: Non-disruptive

Example:

SecRule REQUEST_HEADERS:User-Agent "Test" allow,nolog

Note

The nolog action also implies noauditlog.

pass

Description: Continues processing with the + next rule in spite of a successful match.

Action Group: Disruptive

Example1:

SecRule REQUEST_HEADERS:User-Agent "Test" log,pass

When using pass with SecRule with multiple + targets, all targets will be processed and + all non-disruptive actions will trigger for + every match found. In the second example the + TX:test target would be incremented by 1 for each matching + argument.

Example2:

SecRule ARGS "test" log,pass,setvar:TX.test=+1

Note

The transaction will not be interrupted but a log will be + generated for each matching target (unless logging has been + suppressed).

pause

Description: Pauses transaction processing + for the specified number of milliseconds.

Action Group: Non-disruptive

Example:

SecRule REQUEST_HEADERS:User-Agent "Test" log,deny,status:403,pause:5000

Note

This feature can be of limited benefit for slowing down Brute + Force Scanners, however use with care. If you are under a Denial of + Service type of attack, the pause feature may make matters worse as this + feature will cause child processes to sit idle until the pause is + completed.

phase

Description: Places the rule (or the rule + chain) into one of five available processing phases.

Action Group: Meta-data

Example:

SecDefaultAction log,deny,phase:1,t:removeNulls,t:lowercase
+SecRule REQUEST_HEADERS:User-Agent "Test" log,deny,status:403

Note

Keep in mind that is you specify the incorrect phase, the target + variable that you specify may be empty. This could lead to a false + negative situation where your variable and operator (RegEx) may be + correct, but it misses malicious data because you specified the wrong + phase.

prepend

Description: Prepends text given as parameter + to the response body. For this action to work content injection must be + enabled by setting SecContentInjection to + On. Also make sure you check the content type of the + response before you make changes to it (e.g. you don't want to inject + stuff into images).

Action Group: Non-disruptive

Processing Phases: 3 and 4.

Example:

SecRule RESPONSE_CONTENT_TYPE ^text/html "phase:3,nolog,pass,prepend:'Header<br>'"

Note

While macro expansion is allowed in the additional content, you + are strongly cautioned against inserting user defined data + fields.

proxy

Description: Intercepts transaction by + forwarding request to another web server using the proxy backend.

Action Group: Disruptive

Example:

SecRule REQUEST_HEADERS:User-Agent "Test" log,proxy:http://www.honeypothost.com/

Note

For this action to work, mod_proxy must also be installed. This + action is useful if you would like to proxy matching requests onto a + honeypot webserver.

redirect

Description: Intercepts transaction by + issuing a redirect to the given location.

Action Group: Disruptive

Example:

SecRule REQUEST_HEADERS:User-Agent "Test" \
+    log,redirect:http://www.hostname.com/failed.html

Note

If the status action is present + and its value is acceptable (301, 302, 303, or 307) it will be used for + the redirection. Otherwise status code 302 will be used.

rev

Description: Specifies rule revision.

Action Group: Meta-data

Example:

SecRule REQUEST_METHOD "^PUT$" "id:340002,rev:1,severity:2,msg:'Restricted HTTP function'"

Note

This action is used in combination with the id action to allow the same rule ID to be used + after changes take place but to still provide some indication the rule + changed.

sanitiseArg

Description: Sanitises (replaces each byte + with an asterisk) a named request argument prior to audit + logging.

Action Group: Non-disruptive

Example:

SecAction nolog,phase:2,sanitiseArg:password

Note

The sanitize actions do not sanitize any data within the actual + raw requests but only on the copy of data within memory that is set to + log to the audit log. It will not sanitize the data in the + modsec_debug.log file (if the log level is set high enough to capture + this data).

sanitiseMatched

Description: Sanitises the variable (request + argument, request header, or response header) that caused a rule + match.

Action Group: Non-disruptive

Example: This action can be used to sanitise arbitrary transaction + elements when they match a condition. For example, the example below + will sanitise any argument that contains the word + password in the name.

SecRule ARGS_NAMES password nolog,pass,sanitiseMatched

Note

Same note as sanitiseArg.

sanitiseRequestHeader

Description: Sanitises a named request + header.

Action Group: Non-disruptive

Example: This will sanitise the data in the Authorization + header.

SecAction log,phase:1,sanitiseRequestHeader:Authorization

Note

Same note as sanitiseArg.

sanitiseResponseHeader

Description: Sanitises a named response + header.

Action Group: Non-disruptive

Example: This will sanitise the Set-Cookie data sent to the + client.

SecAction log,phase:3,sanitiseResponseHeader:Set-Cookie

Note

Same note as sanitiseArg.

severity

Description: Assigns severity to the rule it + is placed with.

Action Group: Meta-data

Example:

SecRule REQUEST_METHOD "^PUT$" "id:340002,rev:1,severity:CRITICAL,msg:'Restricted HTTP function'"

Note

Severity values in ModSecurity follow those of syslog, as + below:

  • 0 - EMERGENCY

  • 1 - ALERT

  • 2 - CRITICAL

  • 3 - ERROR

  • 4 - WARNING

  • 5 - NOTICE

  • 6 - INFO

  • 7 - DEBUG

It is possible to specify severity levels using either the + numerical values or the text values. You should always specify severity + levels using the text values. The use of the numerical values is + deprecated (as of v2.5.0) and may be removed in one of the susequent + major updates.

setuid

Description: Special-purpose action that + initialises the USER + collection.

Action Group: Non-disruptive

Example:

SecAction setuid:%{REMOTE_USER},nolog

Note

After initialisation takes place the variable USERID will be available for use in the + subsequent rules.

setsid

Description: Special-purpose action that + initialises the SESSION + collection.

Action Group: Non-disruptive

Example:

# Initialise session variables using the session cookie value 
+SecRule REQUEST_COOKIES:PHPSESSID !^$ chain,nolog,pass
+SecAction setsid:%{REQUEST_COOKIES.PHPSESSID}

Note

On first invocation of this action the collection will be empty + (not taking the predefined variables into account - see initcol for more information). On subsequent + invocations the contents of the collection (session, in this case) will + be retrieved from storage. After initialisation takes place the + variable SESSIONID will be available + for use in the subsequent rules.This action understands each application + maintains its own set of sessions. It will utilise the current web + application ID to create a session namespace.

setenv

Description: Creates, removes, or updates an + environment variable.

Action Group: Non-disruptive

Examples:

To create a new variable (if you omit the value 1 will be used):

setenv:name=value

To remove a variable:

setenv:!name

Note

This action can be used to establish communication with other + Apache modules.

setvar

Description: Creates, removes, or updates a + variable in the specified collection.

Action Group: Non-disruptive

Examples:

To create a new variable:

setvar:tx.score=10

To remove a variable prefix the name with exclamation mark:

setvar:!tx.score

To increase or decrease variable value use + and - + characters in front of a numerical value:

setvar:tx.score=+5

skip

Description: Skips one or more rules (or + chains) on successful match.

Action Group: Flow

Example:

SecRule REQUEST_URI "^/$" \
+"phase:2,chain,t:none,skip:2"
+SecRule REMOTE_ADDR "^127\.0\.0\.1$" "chain"
+SecRule REQUEST_HEADERS:User-Agent "^Apache \(internal dummy connection\)$" "t:none"  
+SecRule &REQUEST_HEADERS:Host "@eq 0" \
+    "deny,log,status:400,id:960008,severity:4,msg:'Request Missing a Host Header'"
+SecRule &REQUEST_HEADERS:Accept "@eq 0" \
+    "log,deny,log,status:400,id:960015,msg:'Request Missing an Accept Header'"

Note

Skip only applies to the current processing phase and not + necessarily the order in which the rules appear in the configuration + file. If you group rules by processing phases, then skip should work as + expected. This action can not be used to skip rules within one chain. + Accepts a single parameter denoting the number of rules (or chains) to + skip.

skipAfter

Description: Skips rules (or chains) on + successful match resuming rule execution after the specified rule ID or + marker (see SecMarker) is found.

Action Group: Flow

Example:

SecRule REQUEST_URI "^/$" "chain,t:none,skipAfter:960015"
+SecRule REMOTE_ADDR "^127\.0\.0\.1$" "chain"
+SecRule REQUEST_HEADERS:User-Agent "^Apache \(internal dummy connection\)$" "t:none"  
+SecRule &REQUEST_HEADERS:Host "@eq 0" \
+    "deny,log,status:400,id:960008,severity:4,msg:'Request Missing a Host Header'"
+SecRule &REQUEST_HEADERS:Accept "@eq 0" \
+    "log,deny,log,status:400,id:960015,msg:'Request Missing an Accept Header'"

Note

SkipAfter only applies to the current + processing phase and not necessarily the order in which the rules appear + in the configuration file. If you group rules by processing phases, then + skip should work as expected. This action can not be used to skip rules + within one chain. Accepts a single parameter denoting the last rule ID + to skip.

status

Description: Specifies the response status + code to use with actions deny + and redirect.

Action Group: Data

Example:

SecDefaultAction log,deny,status:403,phase:1

Note

Status actions defined in Apache scope locations (such as + Directory, Location, etc...) may be superseded by phase:1 action + settings. The Apache ErrorDocument directive will be triggered if + present in the configuration. Therefore if you have previously defined a + custom error page for a given status then it will be executed and its + output presented to the user.

t

Description: This action can be used which + transformation function should be used against the specified variables + before they (or the results, rather) are run against the operator + specified in the rule.

Action Group: Non-disruptive

Example:

SecDefaultAction log,deny,phase:1,t:removeNulls,t:lowercase 
+SecRule REQUEST_COOKIES:SESSIONID "47414e81cbbef3cf8366e84eeacba091" \
+    log,deny,status:403,t:md5,t:hexEncode

Note

Any transformation functions that you specify in a SecRule will be + in addition to previous ones specified in SecDefaultAction. Use of + "t:none" will remove all transformation functions for the specified + rule.

tag

Description: Assigns custom text to a rule or + chain.

Action Group: Meta-data

Example:

SecRule REQUEST_FILENAME "\b(?:n(?:map|et|c)|w(?:guest|sh)|cmd(?:32)?|telnet|rcmd|ftp)\.exe\b" \
+    "t:none,t:lowercase,deny,msg:'System Command Access',id:'950002',\
+tag:'WEB_ATTACK/FILE_INJECTION',tag:'OWASP/A2',severity:'2'"

Note

The tag information appears in the error and/or audit log files. + Its intent is to be used to automate classification of rules and the + alerts generated by rules. Multiple tags can be used per + rule/chain.

xmlns

Description: This action should be used + together with an XPath expression to register a namespace.

Action Group: Data

Example:

SecRule REQUEST_HEADERS:Content-Type "text/xml" \
+    "phase:1,pass,ctl:requestBodyProcessor=XML,ctl:requestBodyAccess=On, \
+    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+SecRule XML:/soap:Envelope/soap:Body/q1:getInput/id() "123" phase:2,deny

Operators

A number of operators can be used in rules, as documented below. The + operator syntax uses the @ symbol followed by the + specific operator name.

beginsWith

Description: This operator is a string + comparison and returns true if the parameter value is found at the + beginning of the input. Macro expansion is performed so you may use + variable names such as %{TX.1}, etc.

Example:

SecRule REQUEST_LINE "!@beginsWith GET" t:none,deny,status:403
+SecRule REQUEST_ADDR "^(.*)\.\d+$" deny,status:403,capture,chain
+SecRule ARGS:gw "!@beginsWith %{TX.1}"

contains

Description: This operator is a string + comparison and returns true if the parameter value is found anywhere in + the input. Macro expansion is performed so you may use variable names + such as %{TX.1}, etc.

Example:

SecRule REQUEST_LINE "!@contains .php" t:none,deny,status:403
+SecRule REQUEST_ADDR "^(.*)$" deny,status:403,capture,chain
+SecRule ARGS:ip "!@contains %{TX.1}"

endsWith

Description: This operator is a string + comparison and returns true if the parameter value is found at the end + of the input. Macro expansion is performed so you may use variable names + such as %{TX.1}, etc.

Example:

SecRule REQUEST_LINE "!@endsWith HTTP/1.1" t:none,deny,status:403
+SecRule ARGS:route "!@endsWith %{REQUEST_ADDR}" t:none,deny,status:403

eq

Description: This operator is a numerical + comparison and stands for "equal to."

Example:

SecRule &REQUEST_HEADERS_NAMES "@eq 15"

ge

Description: This operator is a numerical + comparison and stands for "greater than or equal to."

Example:

SecRule &REQUEST_HEADERS_NAMES "@ge 15"

geoLookup

Description: This operator looks up various + data fields from an IP address or hostname in the target data. The + results will be captured in the GEO + collection.

You must provide a database via SecGeoLookupDb before this operator can be + used.

Note

This operator matches and the action is executed on a + successful lookup. For this reason, you probably want to + use the pass,nolog actions. This allows for + setvar and other non-disruptive + actions to be executed on a match. If you wish to block on a failed + lookup, then do something like this (look for an empty GEO + collection):

SecGeoLookupDb /usr/local/geo/data/GeoLiteCity.dat
+...
+SecRule REMOTE_ADDR "@geoLookup" "pass,nolog"
+SecRule &GEO "@eq 0" "deny,status:403,msg:'Failed to lookup IP'"

See the GEO variable for an + example and more information on various fields available.

gt

Description: This operator is a numerical + comparison and stands for "greater than."

Example:

SecRule &REQUEST_HEADERS_NAMES "@gt 15"

inspectFile

Description: Executes the external + script/binary given as parameter to the operator against every file + extracted from the request. As of v2.5.0, if the supplied filename is + not absolute it is treated as relative to the directory in which the + configuration file resides. Also as of v2.5.0, if the filename is + determined to be a Lua script (based on its extension) the script will + be processed by the internal engine. As such it will have full access to + the ModSecurity context.

Example of using an external binary/script:

# Execute external script to validate uploaded files.
+SecRule FILES_TMPNAMES "@inspectFile /opt/apache/bin/inspect_script.pl"

Example of using Lua script:

SecRule FILES_TMPNANMES "@inspectFile inspect.lua"

Script inspect.lua:

function main(filename)
+    -- Do something to the file to verify it. In this example, we
+    -- read up to 10 characters from the beginning of the file.
+    local f = io.open(filename, "rb");
+    local d = f:read(10);
+    f:close();
+   
+    -- Return null if there is no reason to believe there is ansything
+    -- wrong with the file (no match). Returning any text will be taken
+    -- to mean a match should be trigerred.
+    return null;
+end

le

Description: This operator is a numerical + comparison and stands for "less than or equal to."

Example:

SecRule &REQUEST_HEADERS_NAMES "@le 15"

lt

Description: This operator is a numerical + comparison and stands for "less than."

Example:

SecRule &REQUEST_HEADERS_NAMES "@lt 15"

pm

Description: Phrase Match operator. This + operator uses a set based matching engine (Aho-Corasick) for faster + matches of keyword lists. It will match any one of its arguments + anywhere in the target value. The match is case insensitive.

Example:

SecRule REQUEST_HEADERS:User-Agent "@pm WebZIP WebCopier Webster WebStripper SiteSnagger ProWebWalker CheeseBot" "deny,status:403

The above would deny access with 403 if any of the words matched + within the User-Agent HTTP header value.

pmFromFile

Description: Phrase Match operator. This + operator uses a set based matching engine (Aho-Corasick) for faster + matches of keyword lists. This operator is the same as + @pm except that it takes a list of files as + arguments. It will match any one of the phrases listed in the file(s) + anywhere in the target value.

Notes:

  1. The contents of the files should be one phrase per line. End + of line markers will be stripped from the phrases, however, + whitespace will not be trimmed from phrases in the file. Empty lines + and comment lines (beginning with a '#') are ignored.

  2. To allow easier inclusion of phrase files with rulesets, + relative paths may be used to the phrase files. In this case, the + path of the file containing the rule is prepended to the phrase file + path.

Example:

SecRule REQUEST_HEADERS:User-Agent "@pm /path/to/blacklist1 blacklist2" "deny,status:403

The above would deny access with 403 if any of the patterns in the + two files matched within the User-Agent HTTP header value. The + blacklist2 file would need to be placed in the same + path as the file containing the rule.

rbl

Description: Look up the parameter in the RBL + given as parameter. Parameter can be an IPv4 address, or a + hostname.

Example:

SecRule REMOTE_ADDR "@rbl sc.surbl.org"

rx

Description: Regular expression operator. + This is the default operator, so if the "@" operator is not defined, it + is assumed to be rx.

Example:

SecRule REQUEST_HEADERS:User-Agent "@rx nikto"

Note

Regular expressions are handled by the PCRE library (http://www.pcre.org). ModSecurity + compiles its regular expressions with the following settings:

  1. The entire input is treated as a single line, even when there + are newline characters present.

  2. All matches are case-sensitive. If you do not care about case + sensitivity you either need to implement the lowercase transformation function, or use + the per-pattern(?i)modifier, as + allowed by PCRE.

  3. The PCRE_DOTALL and + PCRE_DOLLAR_ENDONLY flags are set + during compilation, meaning a single dot will match any character, + including the newlines and a $ + end anchor will not match a trailing newline character.

streq

Description: This operator is a string + comparison and returns true if the parameter value matches the input + exactly. Macro expansion is performed so you may use variable names such + as %{TX.1}, etc.

Example:

SecRule ARGS:foo "!@streq bar" t:none,deny,status:403
+SecRule REQUEST_ADDR "^(.*)$" deny,status:403,capture,chain
+SecRule REQUEST_HEADERS:Ip-Address "!@streq %{TX.1}"

validateByteRange

Description: Validates the byte range used in + the variable falls into the specified range.

Example:

SecRule ARGS:text "@validateByteRange 10, 13, 32-126"

Note

You can force requests to consist only of bytes from a certain + byte range. This can be useful to avoid stack overflow attacks (since + they usually contain "random" binary content). Default range values are + 0 and 255, i.e. all byte values are allowed. This directive does not + check byte range in a POST payload when + multipart/form-data encoding (file upload) is used. + Doing so would prevent binary files from being uploaded. However, after + the parameters are extracted from such request they are checked for a + valid range.

validateByteRange is similar to the ModSecurity 1.X + SecFilterForceByteRange Directive however since it works in a rule + context, it has the following differences:

  • You can specify a different range for different + variables.

  • It has an "event" context (id, msg....)

  • It is executed in the flow of rules rather than being a built + in pre-check.

validateDTD

Description: Validates the DOM tree generated + by the XML request body processor against the supplied DTD.

Example:

SecDefaultAction log,deny,status:403,phase:2
+SecRule REQUEST_HEADERS:Content-Type ^text/xml$ \
+    phase:1,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML
+SecRule REQBODY_PROCESSOR "!^XML$" nolog,pass,skipAfter:12345
+SecRule XML "@validateDTD /path/to/apache2/conf/xml.dtd" "deny,id:12345"

Note

This operator requires request body to be processed as + XML.

validateSchema

Description: Validates the DOM tree generated + by the XML request body processor against the supplied XML + Schema.

Example:

SecDefaultAction log,deny,status:403,phase:2
+SecRule REQUEST_HEADERS:Content-Type ^text/xml$ \
+    phase:1,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML
+SecRule REQBODY_PROCESSOR "!^XML$" nolog,pass,skipAfter:12345
+SecRule XML "@validateSchema /path/to/apache2/conf/xml.xsd" "deny,id:12345"

Note

This operator requires request body to be processed as + XML.

validateUrlEncoding

Description: Verifies the encodings used in + the variable (if any) are valid.

Example:

SecRule ARGS "@validateUrlEncoding"

Note

URL encoding is an HTTP standard for encoding byte values within a + URL. The byte is escaped with a % followed by two hexadecimal values + (0-F). This directive does not check encoding in a POST payload when the + multipart/form-data encoding (file upload) is used. + It is not necessary to do so because URL encoding is not used for this + encoding.

validateUtf8Encoding

Description: Verifies the variable is a valid + UTF-8 encoded string.

Example:

SecRule ARGS "@validateUtf8Encoding"

Note

UTF-8 encoding is valid on most web servers. Integer values + between 0-65535 are encoded in a UTF-8 byte sequence that is escaped by + percents. The short form is two bytes in length.

check for three types of errors:

  • Not enough bytes. UTF-8 supports two, three, four, five, and + six byte encodings. ModSecurity will locate cases when a byte or + more is missing.

  • Invalid encoding. The two most significant bits in most + characters are supposed to be fixed to 0x80. Attackers can use this + to subvert Unicode decoders.

  • Overlong characters. ASCII characters are mapped directly into + the Unicode space and are thus represented with a single byte. + However, most ASCII characters can also be encoded with two, three, + four, five, and six characters thus tricking the decoder into + thinking that the character is something else (and, presumably, + avoiding the security check).

verifyCC

Description: This operator verifies a given + regular expression as a potential credit card number. It first matches + with a single generic regular expression then runs the resulting match + through a Luhn checksum algorithm to further verify it as a potential + credit card number.

Example:

SecRule ARGS "@verifyCC \d{13,16}" \
+              "phase:2,sanitiseMatched,log,auditlog,pass,msg:'Potential credit card number'"

within

Description: This operator is a string + comparison and returns true if the input value is found anywhere within + the parameter value. Note that this is similar to + @contains, except that the target and match values + are reversed. Macro expansion is performed so you may use variable names + such as %{TX.1}, etc.

Example:

SecRule REQUEST_METHOD "!@within get,post,head" t:lowercase,deny,status:403
+
+SecAction "pass,setvar:'tx.allowed_methods=get,post,head'"
+SecRule REQUEST_METHOD "!@within %{tx.allowed_methods}" t:lowercase,deny,status:403

Macro Expansion

Macros allow for using place holders in rules that will be expanded + out to their values at runtime. Currently only variable expansion is + supported, however more options may be added in future versions of + ModSecurity.

Format:

%{VARIABLE}
+%{COLLECTION.VARIABLE}

Macro expansion can be used in actions such as initcol, setsid, + setuid, setvar, setenv, logdata. Operators that are evaluated at runtime + support expansion and are noted above. Such operators include @beginsWith, + @endsWith, @contains, @within and @streq. You cannot use macro expansion + for operators that are "compiled" such as @pm, @rx, etc. as these + operators have their values fixed at configure time for efficiency.

Some values you may want to expand include: TX, REMOTE_ADDR, USERID, + HIGHEST_SEVERITY, MATCHED_VAR, MATCHED_VAR_NAME, MULTIPART_STRICT_ERROR, + RULE, SESSION, USERID, among others.

Persistant Storage

At this time it is only possible to have three collections in which + data is stored persistantly (i.e. data available to multiple requests). + These are: IP, SESSION and USER.

Every collection contains several built-in variables that are + available and are read-only unless otherwise specified:

  1. CREATE_TIME - date/time of + the creation of the collection.

  2. IS_NEW - set to 1 if the + collection is new (not yet persisted) otherwise set to 0.

  3. KEY - the value of the + initcol variable (the client's IP address in the example).

  4. LAST_UPDATE_TIME - date/time + of the last update to the collection.

  5. TIMEOUT - date/time in + seconds when the collection will be updated on disk from memory (if no + other updates occur). This variable may be set if you wish to specifiy + an explicit expiration time (default is 3600 seconds).

  6. UPDATE_COUNTER - how many + times the collection has been updated since creation.

  7. UPDATE_RATE - is the average + rate updates per minute since creation.

To create a collection to hold session variables (SESSION) use action setsid. To create a collection to hold user + variables (USER) use action setuid. To create a collection to hold client + address variables (IP) use action + initcol.

Note

ModSecurity implements atomic updates of persistent variables only + for integer variables (counters) at this time. Variables are read from + storage whenever initcol is encountered in the rules + and persisted at the end of request processing. Counters are adjusted by + applying a delta generated by re-reading the persisted data just before + being persisted. This keeps counter data consistent even if the counter + was modified and persisted by another thread/process during the + transaction.

Note

ModSecurity uses a Berkley Database (SDBM) for persistant storage. + This type of database is generally limited to storing a maximum of 1008 + bytes per key. This may be a limitation if you are attempting to store a + considerable amount of data in variables for a single key. Some of this + limitation is planned to be reduced in a future version of + ModSecurity.

Miscellaneous Topics

Impedance Mismatch

Web application firewalls have a difficult job trying to make + sense of data that passes by, without any knowledge of the application + and its business logic. The protection they provide comes from having an + independent layer of security on the outside. Because data validation is + done twice, security can be increased without having to touch the + application. In some cases, however, the fact that everything is done + twice brings problems. Problems can arise in the areas where the + communication protocols are not well specified, or where either the + device or the application do things that are not in the specification. + In such cases it may be possible to design payload that will be + interpreted in one way by one device and in another by the other device. + This problem is better known as Impedance Mismatch. It can be exploited + to evade the security devices.

While we will continue to enhance ModSecurity to deal with various + evasion techniques the problem can only be minimized, but never solved. + With so many different application backend chances are some will always + do something completely unexpected. The only solution is to be aware of + the technologies in the backend when writing rules, adapting the rules + to remove the mismatch. See the next section for some examples.

PHP Peculiarities for ModSecurity Users

When writing rules to protect PHP applications you need to pay + attention to the following facts:

  1. When "register_globals" is set to "On" request parameters + are automatically converted to script variables. In some PHP + versions it is even possible to override the $GLOBALS + array.

  2. Whitespace at the beginning of parameter names is ignored. + (This is very dangerous if you are writing rules to target + specific named variables.)

  3. The remaining whitespace (in parameter names) is converted + to underscores. The same applies to dots and to a "[" if the + variable name does not contain a matching closing bracket. + (Meaning that if you want to exploit a script through a variable + that contains an underscore in the name you can send a parameter + with a whitespace or a dot instead.)

  4. Cookies can be treated as request parameters.

  5. The discussion about variable names applies equally to the + cookie names.

  6. The order in which parameters are taken from the request and + the environment is EGPCS (environment, GET, POST, Cookies, + built-in variables). This means that a POST parameter will + overwrite the parameters transported on the request line (in + QUERY_STRING).

  7. When "magic_quotes_gpc" is set to "On" PHP will use + backslash to escape the following characters: single quote, double + quote, backslash, and the nul byte.

  8. If "magic_quotes_sybase" is set to "On" only the single + quote will be escaped using another single quote. In this case the + "magic_quotes_gpc" setting becomes irrelevant. The + "magic_quotes_sybase" setting completely overrides the + "magic_quotes_gpc" behaviour but "magic_quotes_gpc" still must be + set to "On" for the Sybase-specific quoting to be work.

  9. PHP will also automatically create nested arrays for you. + For example "p[x][y]=1" results in a total of three + variables.

\ No newline at end of file diff --git a/doc/modsecurity2-apache-reference.pdf b/doc/modsecurity2-apache-reference.pdf new file mode 100644 index 0000000..ecd74b7 --- /dev/null +++ b/doc/modsecurity2-apache-reference.pdf @@ -0,0 +1,7855 @@ +%PDF-1.3 +%ª«¬­ +4 0 obj +<< /Type /Info +/Producer (FOP 0.20.5) >> +endobj +5 0 obj +<< /Length 1085 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gb"/j9lJcG&;KZM'g+OmRc1/8mVVPmCl5)\>G7C\#?doETsg?2FOU0bP*0BJDNGhR7D6;8SK:?Bc;;A>,,mTGP05EPRYXpQK&XTa`Ir!%=?+,kMA^'*==:"JCPj`Lnh)rGP1*JP0nHap-sIrBgmJl`6-Fp>2CP;a@EL"X;IaSYb1>e*jP%jCfOA'Orp^,>7bR*87h+g,NEJlYi+h'BQH=7+MEfW`Vq?fX0&PE;X_h(j'/X8m@AAZNdH!?l[eXZV0)?Ms(`;9GVck=j$.d8+`]i+&;nAt`'o-SAYf)e"HolW>^@`oR(u.`>\NSX=\0%QoMrYjt@^%&NmH*-Z5M"recL9SQ5Ij:,E%`6@$NiehM23((M:1EB_(.7"Y4[gHeM])KHL@BW+I9(.^r)g@:j`?lGM_6WH$]>Vn:5/2&R;j=mb0ksq!=rr9FlPehR29*-G9"%b@dmS,El*"M-Gr.gf<33Ie2>3Z.Li?0+-aH21&@!g'L0CSMl9@"F*gMX_N"HC\lec>mVm.!MEMCV,d.NL"_9l7YuC*t`38^cql`_Xcml:4HiPPa?WVdmlf1Ij8EJ:N/?KeI1?b&H'Ke>nl5?LF,P>If$o*R\L6B&\q!+WrpuJ:N0#LRH.ER;%?>[j3WY1HV5`q/l#dK*67(moSps*PRGAP+eaUmQIQu!&3r68F"<2[dZntnlY$&U#AWPZ[=TV3"K(+n7/o^SKO^`;aAg./VpilqeM9Hkq&HtQM3:A[5)!8uANcN~> +endstream +endobj +6 0 obj +<> +stream +Gb!9sLV"j4[4VAB]Q^ROhG"[q",MK%LuBP+:,Ola%8?r\cqR"AM2ELu'd`P+]5u9^OTMiqn;HhYJ0Vq?+XjR\`OlQN]C1CWbV79)ni@cBBss/I*UH:XZ(-;B=2mVfE4/V>29soVReA>OaaWbRFXtb>1I41WGTd7Lf.69#JjLH-"jdG*af.(S$`S3>uYPqHgEF`_a`@!E*'oTE%?GV9=LlKL=&AC"0$rTAhmXnC1dWWO1#i[LD@4J,)O2mD+]/L&0MWn`K:ICfWX`KMX^ZOP%J/f_O+baXaqM7C>)e8qPXN\bj3N^>Zoi)bqpVm"NQ>#U!,8C=HSj(NDm=hW!f:.qNWpPHjY7Vj'2HML9(ChoUd#s]fX7t!g%rqN;=8T7^t_'qR;S@"CsV[@)ff\lptm,W721@?';E^MNsV8@8Pp[=`uNAB4Qe!c!BuKIOM.k,-ClBRu5$h_scOC_dL`m)LM"m9V3pjm'/HJUS8uht"mk'\-)h`4If8OR(NE?R?#M#?&maH&7>nLtF]5c2Z!D5*u%FD-ii2:6WH:5p/4YSG2O:Ko:Z%]957fjW5KdXm@58/>V*Z@F="B)!jSZ'%h_V4&KL`DZabGoBGC%Q;_N/qKTID^&Tr4YP\@PH=SW%?Ud;\sKYIZg@.iT7:GHZX>08$[IR^D4VeqLrdJ%r6#7DY-C)]M-ci.4]R`r^V17!d=,=)-['J:T3^Eg_Z6-WIgh<(gFb&H&e6eH[R-79"mB%&A%Ves"7.W2D-,0^^KK>S)-YfJ"Mt?*d-ha0)f)18dH"MK\A#R;gF`#7uq28%Dn'hM(EB8q`*_b,j4_JK$S>`_tS2_T^(7,W$52/a?a?kZP!U8k+uL43PCTNU7B]+0QAY;$Ypb$$gCJq53U&\N\,$HF.@6D_^-m+0eb/?02pJ"#)@c*,J_[S6kAn)\n/1''h1f,%R;6CNMV#j_kS"%m;+XWaf-F/4-`!]%d8>&9c4Gd6pP?o,uQL0eRH["2i&4N$BfP3FqeD0Gd8g%9VhpWk`-s:X]:?+2Y971f0;"+]J5saQNKD>>lq<@jN]/qQSV^cYht39@\d;^$E?b.5+_SVtXX;2#LC'J^,(,'N+WW39UCh";9uX_>)Ur?s.q(^MC"aeX=*[uROb>YN79rRLE^r/@cl??.?9qWre;4uFC.;/&TP6Bdg*?MY2>L`>:n`IAXRW(>oU9=_![_2ll_T/_S(Dp3nS\UmO[_ibZg"MEW78.77Shaf+.kr`'OHf!FX.%mWPp;K$#/'J=c,92!`N56[8`eo7OlJ&A<%'],@Q)lJZBI'kkW>7TOaoe)(R54@lC=B@A&6Z1N=uC"or0j4=\**UJ-roa@eKIIb*$Q_6%01Ch\Rk*Y68krVWt7ae8f1)'q3,n0lQanhKGJkmN7r!c@TB/0g=2X[$O\CN$WMb2K3=DY4/gn1m'RuUYnjTVo!n?[5`:QU!&cc$XRVGWd/_aRQdJd?sQ2\HY$mQGFQeW:okZr)C*BRVHB_^5kTPa%rDbMauoK>mufH89Z:qfVZ<4#il`Wlt<5g7,0CY?o2q@k[gNX(Z?s?#Gm=]GVV4N_WjXF)PMX?baHK9b"!Mr)EsU$E&n'ElH3K7K9\*k]E9K/QsHSPa-7)7"*T&HbbtONaDh_1ll?tuA6]9ErOIp[::*2E1)\&R"@F:RVdZm)eW`6.f!tuNRWXcJ#"YBE1;/&DBh%+;JM?AK2!e5uW/s@uPNGfA__>ANL96;7KN8is/+I4_#!KIUm"%R1Og-1?)btWmVh&iQ.(H=t/3"?U7O9X%5h:SGopA9p>E^]B)Jq%2U)L+:LJ!-T#TWhb8-aFEI<%:8CG[G0-jE4QGB$VGm/kq/^gSE#"r0]CeE"D"*')r6.q7^%35\41LgsNVY_dtZ&<,I^^BUaQ!:f<2)1kjug;O33A'5WD)/%>":0,!N9Q\p\cp?(07>sXVM2cTZLbt26TYkiX3!U+uSeqPeP``B,fp+4;(ZB3M^WCVs+IROJU.A_[.j53`7A7pBGRbQeYP5,O+'uPqL2No&G*I**urRIM$e;Hr"8aR.s=Q&i;aMn6g$CO#Z5`V!egoQb3BXBP6s*EZlTTWKO2%+I!RC!+HQAHBi5t.;;f0OX*;jAB/[iHYeKOR!]H3\7EVfL`NT$e#;!6,`#P6T\!EagC-\'+*553XkF*n/"?P@CKhq%e-DDa!\5jJkF#lR]hq"6'TTh?n_%$gs[T(@C(sC[I6YM]EYbE,>B&Pq_bMq!WOJ(YmFr>14I5b3_;TN_1intL'5amRNX(fS:eH6.8"]2c&?S`k[B3Um$eiPO%;IZnG>4$\0,,b.:'sHc5@;t*J[$>F:d;.KuiUE+]h$E2k9HPdB-'9lB:KMKn>l`q1G"-SE6^*nk>e%HNeU()\:4Xg464OU]fXFK@E!/7Xj`!fUNjeC.N9L?pY4DX40P4M&2X53oQ%1,'J/p"^o_"oh<:ADLY9=i,tgTi@(]DbWKK)MJXS2G'dI54f>2VS(3UKqO`K;ZW1!#bb19*&Y:oPo5\g;IPZmBX^EGY5fDLN%/'^m\m_CU/;+M/lFt"EYssI4?aY!La?V'"b"H:A*JPh$%SW=oos[_9:k]r+-m=JndQ!JmXnLO'VP0bpY?tUTjmR95)O-mRHIR8H.V.81m7J8=A5%$&)''/J1Re]sOqWBCi3a:oi`bpTHub$#3.h_.obq(co_-M?:%+79$&"R=F[s&Aum&C&X"hSs7\`B$c:icXU#WSG`UGT/$s]JI1%ugS$H^>[qd;@:4LU^kj'4fn$37[QcnY,S*?425"&-+sI)\cB5[f[0+%'24JJZ$5fL'kLt#gU+,Y!`?r97QN/2p3#;PVF3>QI;DkCsKUMTMo-GWiV@Oc_R_@J[#'5fjUqid3Z<#FC%-Z2T[Do^)YVIq%91Ook*4?l74Ep)8k=Q'E'G9c]c8JI',f7(hM*-SnJYSP/.ptW2De"ekRFF@ei]KCV",s4K6KD1*Y6I5cEMKI59=Rts&d>V=_1/cMK$CPf.*BDO$,)'b^2B0Q9A3grM<7OQs#3e.9tKAE0XI6LhNU&n.cT\6pY,ChauqcZY$kt5kaFUY&mB'e:?=K5PbMumUTk>Ee_it5[OD5%D"=;&#WiXe]_3?Q766^p3Lfi^c?(ni]pQUhM<#:eN>N+AhhVeM$dGW72V8Hcdj*#qMRdo'6skZ*:SkcNhiQ18H3!b2>+Zu6i4ACX2Vln'I'u?,R[n50#V<_7j;(%>?-#oX2Zal'=2&0X\ia`'[Cb-ll$b6lT@TT`?%Tk!r0Uf9UN4+:iK,fAJn!_WtE'WCBWl?ls^ij&XAlh$P[WG.p5fJY0]V.,Va!q!^Oh:EP>gH.+###0,cc,?5,ZLZ(lq>gCZ*:"(6A@P3+)1]hJPQMJ*Y*FUYO(+VU-"7jJ[;IO'(t`t\Ls/hIC4!I/-oQC$Ce*%fIV<'ipi0^A30S,lcfR>=*FUY28j.dU8"=a4eIQ:MOf+2ng=``c5Jm&6++mIst_QK5Y9e7B?bNW9\m+@g%8/U.%%$;%gP'/[gfI6\gCR*'laY\m1fM`o[[&iTrMN@16D[d8`LE5([;GIaW\>s?-Z7o"s[j^/5-&]ou33fG!O6&EB.5t+ujU)4$S44m[kEHV4(P$PU0cVUI(+^r=3smJaP8]95`^_=`Nol%KaJ73E_7ra_5r6=aMV\2Z"ADE8X=b2+/>CMQA2^+i8\CJ!rD(cm\VU^>:0O!!V?OlQBW-LLK#'k7e(YQb`^%B^CnTmKi_W/?%,KGVK_5Yn)uHE)+HXMegQ_bdJ8(37$GjruU$Z.Pp\@20![J:nIu:%-Et#>YEefe+fto*:m)Z7n^Yap(BE>RdO'o^f^UDdqlc@\+)(7CP?H2'E8-s,&2&q:PN"q-n'b5-C@4\6E8k*fA7maHlkZ"(U&'0XI,k"5L3/T(Fg*(fSZ=!Ar1,LqlsO[De\,pHFCCSdl>9&A%>8f08.%TM2t6[mWKA;NBn1bLBZ50cnr%LA4g9rM`"qes^9o)uSBtl#,(GGb"9VMjO!h4@Z8H,iOb.[Zl!+:FMU;EQ`Z7arPo[sR%PS>N*"*K9QMTr=q1Tfr(o@a4R1UKQHA,ode%81iS;G-4.RG%rOh%SJ*rJlU#QBJ,V">S#$3Xe@#*gK5VadRj,aTVX.FuF8,mG5*iFa+7Q6Npg^`s-.i`aN`nn1N=DgG>R^/a-Nuu,&*+9L9HtaE!L9F@\=WgdB9a<]BQf;].\5ICF5neb4#.a-F)5BbJe21/MN'WfVP]UeTa"Db^lpN+,A0XGanK&J($LW><6[[#>T&$R"6]/Bi]/_aE[D0p8X:MUr^&Xkch4NL&_N@JChj3/KJf/9SGOQuV.e=Ckl'I@Ap:P#ru'1[;WS$c3U0RH)0Nt4\d:O#JJZFJeG"t1\i7)WjO,D)$=10Y0[KN!?dZ+i,f6)*j*+2*&$gmpp%5#pFK*WXesVT3eFRV%)6AZ>`4K,r"qH17tNC9s+@8ANoTBXIgojYJ]8&b8:6d>3?86p?36UKPOXQe>@e;"#=OedT9MF$oqa%![!%Kn;<#i1%*jIh8j=r^),/A>P@=jWak4Zt;IF#J1k(liUCDF(i")Bi6;6T/+c#=g@dOB.+@1pTZXDA$Knt6jCHJRI-$G3[.J#0Q`YCLscGT%b_n"hT&HgHl.d)k%BC,mG'5=0b&aOEL`mgc*4epP.e,A>J+5Ob)70!u-O,/8C+BdG@@h$?l0kM^hRa3fgdj?Fc#*tZ^]`s9ZoJ5JiDFmLb4&Os6aY\2((IE[*aAk]4-*F)-LlK&d?$$50d)@m2,,#(pC;-WgK3GLoR5d#o7>Ll-jsnpJdD$=hV2`SA(VCW;fU>G0E'B/q_I@:,%ZV"H3X1-k%2csj&L9iDk^a?&0>YT7[GmE&V]*,T@h^ZYE>V"Gube[e1"f!1DZ;h9/&AXd#[dYb39U.&(6[UfE:"Wf5PCGX+#!.(+d;NDTNG(/_1^e,)E.>N`ZuF459fE#l2_13'TSh[DE&=NfM[Q@[7m1%,c9Km?=mg>[d@,R-[--7E)Y\q/nLqN$oIZO;gbS(Imc_pO,`%:C,tK+%09V]ipULakO7ks;AnVhi\?NAk@^LtGW@SC`oa;$uQ6e>=#c@j6U?p_R+VBo%:h.j]Bh4UpQT=:PB]K1lt"fI]dIF%oKT6%l.BGIMSZpB1[AS3u0c(W?Z9?B:a\\(asoaC=M,t?[_(M.]\/Rr=I_1<)sQQbT0*9r6=GZ(E9\u02f:;[MVUE;Ha@76!(p+;@UN+@Sc+un>(jBiUXAAI&!-YO_,_MiVNHZ+F*`ij7On>E=F>:ags\'jLjJJk(2]E0u5OT#PslRH/@b`&cM5%XJXQA&\@dp`+n(blrXI6B!;X_QlF.WBqCZL4#V.1\Y'ZmG,rb1[Eh#ah4k@lAr[!]q^tNMk-ERa=A`n3bh?V,U/+Db[mPh%=.cpi#jRTFSikEKQMmW!_Y,Zs0?bq"6%OICUHWOM:E1?et\j01']F)qnpnDbu<\gR'1kL^M_1uKm["A)'"'+G"_&mG$jSUqc#'9n-LG:6;l97EnVb9R.La2ihd(1=9=J?ij'S$EWa^%&I\q#p+ZSY"qW.e0X#83Vi+M\4H"'WB2kkQ=L.A\-_aSRTXoHEk[AK75h_Ck!?smjdX[fP7CXt([05EHNo6/NZ>Q-=8g,1:>*=&+b`]7VSO.61#jB70%GD3d8L#VEdFHmkE&#qkGaf!cUhh1_Wm:12i84nT6Rn)X16[*Wq5E[ICbd#:j^mr2j`(;eR3)"H?tGOC#R*hqF8CH1MTZFe=0r>;eL!:9?CMc6nF\'WZNcJ`K"?E&aY$ld2B\:[K->*tf6ce,3F&Q:bj^RVoFJ`s4[AM/_h)]1E(_c=,0]-[nq>m<*``^rrC5lDGD4#3)tF74'!sIPh-j"?fOVaag.Cb_9g8WeHEQ@.]&%Jf>l!]UNU9q-HNjlfYj!=]p`$>ajaGjTkAZ(Wu2P%-t,(uaX+8E_M0a6C93Hp(T.E)u4rVU,T#1841h(Yg-?Ls@fc<&l#/,<6^^Mf)M[*7TiI^-FJ2/ok2giu2bADhG+@+nrUhUr.GpO(7(cTDV/rHse6Ih#j3fME,:GH?F,;"7m0V.&Af1nPHsXHmk(?r6G%63/?0&S#/.q#X_6R2rVLa!;kuAQ3umftti\fnKk>=rXh;aH`\8UU+s$,%k1%a'$)W/4!@SbaX.@7*]])!L^&o-/Dpe%Xs+V33Y3%:7uS`$6KR!'(qBg1%in(18]j\AK$C45@b8@#^C&XY:H;-4eqFSJq^ciXr+%^:;KiE\_*ccCco]P!d(65>)"=*al,?B"QcH+#\QFTm4%,SDFEDZN(fotDdN]]`bP/0ikXQ$b2L5u5[onR)O/Z&<((r#jt]r0kO5("*9F((:;MuKSU18m+DEQ`13N\5Y``/-!VtAP1EmLWCp:$?)P&&Y-tK[0"j0d!/?t>XTUg"+$K_mc's)olXmcqCn+M![3Za+Wam-;I(#$#bEb_<;;^a,G+o"U)W2pHmOJ7(RZSS,\2>I;dE=>L<1c=10VduMBl!GueG>B3mFTDh)!=sdE'=jE)LE\KBgd"32;;FF+ap:RB,']a^i;ed?C9;LZG5qUr\q\[TMg`_l7+!^uhs/uIelM5"oB-d.gck#*.!-@8D6EYM&3Y=iu'o3EI2tWi$.#$2HSV=pHETcqb)jKl%9XB[\l/U0-A+5nL/2YS/_t9E#Y!E;7,\;c\]s??/s#,A<5"R$/e`modK>['hFP3!9uR3-:t])X[k5RL9:h`Xj%[DdF/.fk<7b1eJ8[#&)7HNQaeAZ>mGg#Y6YPM@dre67e^;3^"CdO@8+7=b,,g"3/ZpDU^%9s?kM\8BfCuDdck#D8VD1*2$ZqQ'-a'!%0IE$it2<63K")2OPXEdfY@\c^OkcCs&+VDHm4F5K@Rmt\A**1cN4kHN'.s[+Ae^hX:'sHSU16"%$2=q!mFt)$lXGN3il=5LNWSNpLESJ1,b"+fK#hP8`Fln'`#2,DYR)`X=eQr=7S+H&/l3+3B>3=eue!18:>r`+5)8r!]K6!p!Zh["m#r]i_iGNRsp8XQ)@I51i]CD$ZQa%G+e1E7%jX7S-[hhJJh,.TW9,:fpPqYIj`u##[#LSVh,",^*55_Cq96"Z)I_LI@bl6e[/:V;Ka:/P$52O!U%aJk5!8e9,=J>S#Tm'PKA-lX_*D/&BrJ&LRuWL6Ou8BIX`c9r4LOJP2a^$>F((7d0K]`(16TkW\L5?l&X^i!FEN&8>rR4?#i\j`FBM'<,I5Xo_7c!";oj1'E`:AH7<1ok&KR#$T:[5V3C#P*sa:pFG?qp=BN6Jc.*jM^g;qlH:7VN&EES"d]7L=[9i,@Ik=Oqp30[Y2Mr+7s`=4!7K(bfQ8g%j%0OpFQ[(N*KZB#<$Lj($8c_014VS9Jd`g,69)R`pn^Gr"Ui2`-J(!rcFJ*EN:NXoUXs/,+rRD@;g00P>bIk?^k_kp@H,p+(7#=0N,=G#Mee7?&d*YFcsp!BMF@riC&Ah&RI_@1:J(4#t$Bu\.`X6B;o*EN@"];]\"6C@:mV9NYJg5$HlI"%Xl#_o?rn/BGH7M>]mZ@Za\97g\G^ID"i'qpcQ38ac:*R``ic,@Lj)s6CT5*[7e4VSRg(f)p<=k%?f#i((.E`e@&:+RkQA]-gu+/!&<7Pl+R[!%Xf>`2pfbf!m&n^HfcgtW"d?+lC\o]*?(+OcFHm-,^*l?+ZtQXltZr9._Pp^H+6$r]3[f=AA;ZXO8SmZ?Kp`Ya7@7-u>48SoEKRV8J3A&2L_0T"?@L?jQ;0HFUk.H`NmrgJ(.(e#2+1cZtb5jq=@S-Tj^NGs8OamO>n_PR5*?MVJdbk>STg!?mDj(/bgHh<2t7eE\LfVVL_!A(T#85cm[dQgaa0q*s:.9k&CQN&FY.[tHn"?RB_R3a6;3/!VG_V(Fb3m2W<,`/+t%SedHY>)EiTc9QmdC:Z">LQN$I,J,\%Bs'C$9DduT.s3UbO3.:pgMATn/%S<*J&/a+,07>ON.(#Y'98Zb0jP$!PfooTqlZS`RV6LGfi;b\teKu/XMQ.mIj$4Tm4m[m_pc/RpMi>%nSVT*/>q;8>+jb]hK58_QJ`hHs.NJLt;l(-iKG`c3NqnBm0;$q4H"R)Rid^K,j/27rNTFfbZh&=ZL/%Pnj!rBi('@H!$pR8>i,iD5JqHW'b6F7LTJ@:8LrL=>"Hme9QOT,K;[tZM$_HeB>SbGL64SZXm$,M!a"(Bc;Am8%($EiKo0E,npX*iX;8FVPPN:,jgJ/blZ3`*rp5t)%$lBMI.>`A3WG,,j_^o:(a$Ol,nH=,??PpUkJQ*!",E":Wf0Ur!(h@#C`@N_006$5MTUT5"f>N,o+Ng2:W?ArajC=Sn_qcSb6eflZZ-:6_@82jU?\&.Me[ZG3d0;H^1I>?6X_WmZOZSjA8NgSp*ZZXr]q[XG9CmE:t']amA'i@t[,:M%`_VXJC!,HZfn(lj?6'4o^NnMs$q;ptJos69l\lYc7sk+1ohY1YA)QdP$7$X#TqItu1]YDk_#YCHFgUlo3NK`WhFJV1N3P809Y6J%Tpc4R]TNEKLp!]qi/H#bW",ZQ@biE0?Q\%#J?"HE;`+D)`Sg7NsTfNXp0\fP,Y5\Ua^?gXZ6aKo`$KVD:o>EXZZ9.'eU(ro_*Ck)p[poLS#lRo*@'("6iB'`sPn1O_ZOpsf!kVs20n?;LrDeiFuP(#gOBp+_p'LQq<0J2%LMJ9Yu(9$,i]5Jo,^lsMk(RUZ5+4BU6s)Q$8^l@_bCH"0YVR9LYleQG&t$0P?P'S&&E'"KaM(L2fT-HA;^6@b:O#6eM9]Tn8LW]U=n$W#_BB!WKLUb]?X/P[jgM-h6U)BJh%lec8@XFD8j>%<,A3U75%)GWNJ%3&u45_:KCn!7;8^Mk,>u2:e]W]o.-4cG7"W8G:31CI_S1h`$qACA\YrtuBrV2[_4jmYUC_9CTp94J;VYOb\HVp.g6`O,psB#H8.SV9i:!Y<2k]t%*`4E'O=csU'-+s,#$]8Q@k"mP!]6QciS]Z<'BSEX$!R3V%bV(ebRHP\AmnrdCu(mU9d.`Fh7KD97SjD'IK5.rTZagMo(9$VLbLm]@^.CQZZ9K>.Y[j1oj<2D3$E[Z]%:#F=Z?cIik,I3saMhbcT])d@?eH@j#c'[EBOtf(j]u-QV;m-1^KKD77+Zie1)e[2n/VC'T"H:EnmW-/_'DT;k@4fO70MCjdL!?n8D-1cN;B\Sb"mA]UXPo#Yhg=[2"kq%lUB,^R.U7LE<:/_:7Fcfme`7i:""1KV/-i[IMi$$p0u]48d.mBD&hklI[VQ]j-F!f%Sk*,Mhg"-GUGRP$D5A&.=TZc6@S,?S"nR"71V-0(Z*dCYm]3LZrM'4-:`Kcr4U,Bt)t'b?=*#0nE:%QccMHh-8SqDX7_[nFc24;#X1f*?[[1g*QK2/C`(Np/n+LikY30&p1HPN_ZtJcVl-2K?+!MNDlMQo%_2.+jspNA4C!XMF\'1'DV#Emg1$23BnlVFJ]dFW/i+*`/\D0*lR32$u;MFVu,Z3c`_e3p_b9!>\Z.8raUSV>6<'@>i-3$>b(jLM!d/:UtIo">U\GYbA88.^&f3kejp[-E2MS;-21\KU*P:Wc3X%LLNE!l3,E?bW?A^>He*d9IV>4dr\R*5g'G$s/DZnp"_'Tlqq-fttk.83_Ygd^C0@LOVJ/VRD)I"92Pt3\uUigUMgoJ_mJ]U':DO%s,tS2.N=hCn^?jEKm]E(c;*)'d@04g@oW'2WdE_P)gl-;N46D=!Sp.*^F$CZ"ja)QWMVg?C*)-;NO>,mQ:6p$hpAMBEd"M9K0C+97QMgj6#Y:,b>r>Efh`Z@^?J?:>fli8!CL[h*WR]d`8Jk7OeC9fU7"9?2&O)2!e3;fAZ.3g\#2-)7;!<7J?+':+@tkEUita\_0SZ5k)'7]Q=$@Wpp?6f?i4cqUVmO(7lLQ,[6Umf/if-2/MS"aCCm;Voo]3,sC8Y%l@eSMUraTo6NUi;jAg/J)0^!\qTt"0Vg,6]RL'U`Y3Y3k1f!LW^PD7&pPM<7p..M2EC`f*a5:D5tJH^ISEKN$N5bVf<2HC/$I1IiNW;AV0n>OctG>@fPCg32NRFkpAS9SY4M`7NgMRe1RR!p,(LcIGoCttDSs6_SmT/6X38dFs(kEO8oPG\Pj1*S\QW2_<%[Q#8dW#b]Wm8J.q:Xq$;s(O6q)5[?5Q3nI%SW=MH,<5&DfF6[hjL9Esl)+3Z$-V#[VFRE;sk>rhHTQqH")+KlP2t8H5[i!IHhgBQmt72pkr?4.ZN1WcF\i+[k^bs!0;N*N#2Ds+8WeAV]PF-r"0B`Qgk::n/qK/ok]"??i9+/Xko:PCBN7#^XnF53Suf!UC4.9,(C#MGu#pfI/qmiq;2gcgsJ:H74PQs(jEK7MH^J,H[kD1@N8D=ME\%Y+<)`-TSZS<&R!q;,^(p]J$"r$q,.n3<_cO9YH&W&W/n2Ps!1HBoQ4NNr_>uH_B#n1:A"\+l:!#Gerh7rk`^c@]d$-'[ind]/(WV"4as+n&9aTF+Hnu&IT>3)7t%Z58s+jF2>TnN7q!nLm]"eUh8+nY:BoD7VP7W!jS0bXCuTABhd+Ma]l7-3\rcMTLd/^E$V=sO=a;P%'?a_0Co2FU$J;%Or-:W,Gc1DJtRb!M]V-24*VaPl#J@sN/;7$CT7oaeut'][0F96Q]2j]h#nOG]A)rI6Ueh/r=q^>OLA@d[]Kt/s#mK$8'Tlgk]I,Xn!9`74Z9'[ct/Qs^Cb+eA\];eQ9!*,YbfKP5c!Fh)P`UM=HbE<"HQ8FX1T6&U,f,P@dhNnQWNg148dZ7l9Z.CVESX>dUd^"3,M/BVIY$EEplStcAP3(a[(cdjTBt?_[+5/(1`Y9pOa3eV\7`fSegZ+>!%T"&qq5&M%9>R1E/,a(Tlrn]Y^p9hGb^PK@C!\5I%cTpi`8b5pj&$/#fm/)PZI1-[%EXKAZS6\E9b:Ng`"&=5lK9$`]$XW3M.Th@^BBTggb!qeRbVjI4fF'T7a?/St\WD^@#-.V)in;\@aV5mkAAQhI!s0m.kj!=oHiD,^lr'g28O5g6%Q3/?T7R"F-Q/(e'9PfZ;,X!diL#J2%ioXd:nkl.)(0=$Fl*TnsJDYRrK$FN\Fk@GgUY*=2EYlG%)->IC4^gM!qRpGagZdX7Po^Q99XPn1T@2F9H._.%erDTTa=t5J_XY)h\@Hmn+k[O[qY^6b,geM$LZ;T9s$49N['tKMJ5G+Im]I:$;iP.6PmU,$#>\@"R\NjGa*QTmL*%WH'I(a`DlX-I_IpRBntiQ1gt(BMmR,pjUOTUUFJ6(U4U!GrmqDW1K'0=NEWr0qIVT,\=:6geOpoNX0h\sZLA`I#s4"j1h:Q]CKWl+V(W!u`DakGmN;Uc)`j#3H61buR%Cis3JELM`_F39.]a/]8//r)NBD/Kdf&d,P_6C%Sj5iHejaDiBNCQElZ%2#DAKc#Ht"V=R&^28;6S<)has/g&a/:&_JUM':=ijE*1B"NnPMXneQUd^#8?ctn3(Mr@3(OuGCkA,u!c&G8,5d?UBcFHN->r6/@3Z!nWih=>$JLo*+g,_R(QT6gu%hq>pXsl+VoiM_,Lm&kd:?MV%=dsbi7Zjc08SiE.nl(9VF=n_e2jk.#-GUO%6=fdNm!S#2D0+Xjh']BFq;%Me/UOi\K5KN4:rg=c]QV3P=#cO@'GE*bN/+PYofs8;Jm&ln7Jnjhe$N]=J]nH8qA1eWk;:+#22=7m5qjun#T,5h9qJ"3+uVN+j7qC@PS-D0J4Qk`0efCHrfQ-\NaTA79U3Ilc=0W.c=g[aZ2WD!^Y#Qmt73n5nOtDbrVqK!MOd+/"0QpfC]P@m)/*_'PK6IRc+\-.0k7i*CE(#"-k5jZZt$T>(O':4Wnh+AJYQ9IWG"JdHB>*oVs9sK%DWOVO?VOqQ&W5NXY0&=W:G=qbSI)_4Z+j9M?I#qM`5k,G^$l5LK=oYKH1O`A!Sa?FNj%HjWO>K4UZt/Js2:=.8+>0b0^["1DbiRllC.L*<@&ClLR(5$^RT0]T#&R;.F.'r]NT)q8KmL+KsOBk!2X`bRb.ftsp1C((]dA_2G/D>d*f<=6ECrg9gqW3n[U3jm<78H[>R'd.!\iWf4/2^N?P8)_tYB\n1&@&`P=i3D;LUL8c\FI>s[IY[?M)7>XB`l't`gR;3.cQ$cn2Y)[NiC)*#N;$7h\8&cLMI\gA^57:JEN(u^8R[V(SFc*=e#u!5Il"aj:u5>k(0@Ej/F<#$`)TcH+tjD#@$%_HUCrYSI#&mi8q;2p'?3:F$j,E&s-;k;"dsH6^Y+F8WIAm#jKf\f=:AZD88Ng"\cF)8`Kj`Zici3pJqYD0[G.>a-A,,:=nAqWWWYs0#Kj,-aN:'_p@`17P+Zr=6_%NO,$fMVh`(d=T1UApdF6(Sp%1^nk-i_2amnWNpc-"LFpA#Zbi_R(OYY.8;O--<<[Ka>F&))d.Di'nNn/QEnA39mZ0bM9,a\dZ5I^Bo.mJBTJm>f)p6H^bU?j,2q)Xbiq:NL7'mW/=rpHHgLZO.Ukc4$4(j$XS2nU>)a8=f4M=H`TtLF[L67!-Ghk80=(l\lAPdqSIKG21oN7B3@Rm?e]n)UIf'g'M(o4CRnRlH89:C/aAjm2pg!%paQWdg+?ER;`bmX\Z?NK;+e(9d[fUQG9I?f`XA3Rg910:&)`ss6iVc8,s&uZ&6+O(L[lSA.iDm-nU-QAe;.S!&-nUe>-cUA`WCT,.3ejUSmUlDLr@M,]4fb>D614#[8\a)!pAh=;O""m(GD!YW76g":m8jikZNns7523kkSC]&\I_^9rCYbdXXoF#r5Zpa;R>ZYb,\u5m4pTBQ8G<+rqXcod%bDJ02T-Pi0U=XQF82UqU3<@H9rE?dL.]%*62:9Q&+Ngm#k%0P`o*2PlI2P/C&ROsmW54jn[UP[=Pe1K'R)q/O6tBMK\$%CIq*:n*]%Go1AVqZf4/^C'mSi=4I_bO-__0jgJu->KT3E+4Jk$r(\PaZ]^(l5eWN3!kE*$Rh&a@%jfZ:l%R_7i9DH*Qtc+3`10d<0LT].f>-!G^ROYi&K"36YqkY$7,u53"#sAf@Y`;rj#%0f4:>($,_g7a#:HI_aF/HAA767VpQ5dAE%%DP4-[2mR+kPuO;;6GEspA_9i.S$9bm>pa"=6>]?bsrP)=8-#/GOL@d=VNYTcbMJMe35Eb(rq7Te8n"'So.1]OllaS=IX6u%3;AVQJK05:k?o$`Q%Z;";-cU_l'VSb$fau(_&EU!91(5'F#n_HC&%U7Q1s@dl`5\;A.t)<.$lBq#,%)^h$l-#_Y:Xbh9#G9fGWlHI)/MRh&?S7&q!__W2NUHm,[AGOh:R/."mS2J\pJ.*\bS=!sgfag""o(,EX5meUq_f%\KHr\\GM`f="M]RLpi5]CZF)2jm?Cag!N)^pj`0pUf'ErH\c#l[Te("_l6klQ[9[U_f+S(_s#2-*B[Ij?pk,qtV'B&kUVJZt$eYVLW3(6.ft\Gc4_dd4#N(:AD6Ths4p0-V3Q)#sV3!d<>NB[qTE^npmhUIUp`Ei9>C,[k;TNQ$#P[b="eVDq^bQ;-_K1?I0&(5ZhJl+K\+kS7]UIi@'>p@bC2P>PNSd]8@L2]/pDJ,m>.Q0Ulp_T*@V5Ych;L/d3[8DJpt!t5R4b)(ChY&Fq3'2:64)KUXEO>%#jBZ@fC1N2M?F-cZ?hbObTFEd-b*/=fQIBk&c5"6>J8/!$1\'&^_@uK&R>;#k+?@KIK%5FY,#T%_)8N]IEqsDON^5!#r%Hr.:7V`i1si3q1.7b?)YrS#X?u_frIi/-9H7_)8I[>f2k`gosTWUbkRkD>rI8;4hO#+.$qV1h&uaV"6]#ljKc$.D/-]C(PE`;00K3H"Gk-['Qr"WHJ0M97D!^dN>$fka#`(]B4puIdeFX=+,2_]O<*&,H8e8!7#Aa-OYf$,t#C`5I.uSpdHE>X?#A-(J[3ll=8/Pp@NVhS\OM]k:aGaf$`"ca<.JFmpgrmQZ-ET&UW*J&%QbPq"@&R>O(A@UUTnmUkT';;V8D2k.9@]XPSppr+Jm\pj3oY;j(8rHV$tb5^=m>E1fF\tdQ`4?I`b?AC,X)7d,=QBO2j!?a7#GV%W=5&gf"KpK'.#?#rtuRn(uq8'fAjhK@hX:JKZLa,CBiII'E"k#k1fB2Ym4Ds\tUZP#HHFt[]rlDW$,!kJ+2Ki(l91P0Nc25Sl-(gR7Eq_$K3hd[:;(cK_e.Zn#0?cl@IEMEaJ<,Xn]\Vds-*W.J.209`9Ah$\YTDFH"8+NF:/u`+IYP'Rq:EX4DTdGT),"jI$Kpd1'6:WM[U:4?Yln//V_h6GCQ=Ap%pmc%mF:eh9(t@)dN#FENLnGr5b4.!ZZ=D;4IAdljhWP;[.j4Y'E!bahVdR(>nPRGb\^CJOCs/90eqenhWOJ_`5-]##&K@<9TR)5U)7qp%i'[K734@`:1%EFPQjGlZIr_d2+X[uI5#s!ER`dK?e[:)lPC;jL"1@o`,Bb4:ADgteZYOGoCX%=NBaEB@g=Zk/U&W-^c;W>]<8R4c9!*Bq50e_n]u^\gUlpeCBO6Vn%JJD9<[MCh/_CK:S2^g5*K"]755%h39mU$NO0r,FriI>d$$+bYi5#^*r>]YIds=#s7s'HhgLQAi,>g4q5aOAnbu%.21OH<@ufIAOYQGgGsY;l6/_r"`j#QIE-8*rs&gEb2>;0U`Yc?W9(!g:f`$#MdS:9]K2a$X*1V`n++9),f>Ao]fDnc%umsb<-PL'6r#<+j:eaHhLa5K[G$9FO%RFf9;Oc2Jq9V;7ulV?G9->rR@X>O632sUifK,h4+07g;UZDSkD&HN-,/SP2/)(<#MZ6Adn._O.P7ZjS*Q:oeU%8K,mh@5$\LbR`r8=Vo^G1RuiOhqqh78I8@L45CJ;A$]7ib:\NnmNG.Y:,A2LB_M[.rYMF'dRXG!Cn\=k'[f$!DC4Et\PLYFn[q.%#j-'>OdijX,'A(rMGN3#\VT#daMJlSe37qXQfC31,P:%EmX=q5?(?(D_lG-fG"-8\c/iMF':uW:&VcueiQ+rjU:HUGO@8$Gn]*)94Rn`f_MH;?%;abRpUI6NV=FUb.mkY^V'48/O/*6o]_]k\10th)6L>YX:&D,:qZ]#7:/.>lDniPlG%iKnj!-Df"ViN4-3S5^%(5h^]*Un=5NT1f?V'AcbgR>JL@k/<;gtU*\A_//.IJMBn&"S,ETug3^bsGC5dSf9(_*r7*O7_qPpOD;3lZP@)oem'![Fq+1,S[a\NGUn+_4g7CVQP>ZlIr0-G0G`>c%fpm>P7I/CK;a0Y9YH#_Va8Dc:[HXEdc`o2Isg7uhD9Y+eC$ju$I;^X^%ENJ3bcRn+"d7HNuO]UnZjS1RR4kKcc#8&)I6A.R^2(T0:dJZd!lOpK3NQ_Or+@Gg<%$_+8BZ<>05qlcR<+;(bN%jC==*EWcUu.2&s'uR68ahdOA8KplQr-7SuNi4*lA=h+Y7=X7/!m!.Kfrq8$G7`mq_L`>5&J/d;r!M?J6bN$)c!r&&.mQ"N7B>pBtb+ucH(-nb<)rKbb?mGF=.h0JY*Z^9PF]0EqjfLGGH\)2W^0@m"kH26%Q'e;)%nrcVjni,Fqh!9H>^U-=W3=B25ocs>R[CglJPN6'g'oTlUcHjYtl!*No*d[b9YQ&Hq1<@5#..`"^2Z&6b`\$OPjsT:g,?1uD+kSW#f3WfF-t<,QT6X?)+&c2M)c8_IA)^>$:qV9DP"XC=MV4d9+1uQbj*ra8-]@J7;OaL1Jk"#9Tt,bJ4Zd*B_`>-lI-?`4m?K6gXsLW8?Q8NmfUeFM#Foq[UudY[_L?m#]2L&R#Nkj[mRGT!o'lSHdkI/%?b/o(aL_0;7emZYRIa%`-kM7MmOg\jSE1ScEj]0F;Hn!qefD5G"T5k*5%!]h,O@X5,ER43VeR[Lb`krkrI\,IRMCZl9-Rqae?8lirZA5=pIji'b2#%HL_M/^ZSnF*Df:@/#TrFbLUISijZDrrA)(B".,07WleJt$p#25cVGE9[O;J$XR@DgqT3QF'op^%]=;s)l+Yf/L="0(^-M1Lb^#OmU%^^%dWbIeqV[GpqW(dfhf,_j^f^G<]9Nq.'G=l"Q.2f:PS/@Wu6]S4=bg-.F/r)$B+KS,ERp"kNHe@-N`'e9U03r.K1fMHtp.4CJ+,;[3+noS+D#g>NgIj'`.4dmpXD^PmR>ZHoWBR4Y[%o@%Pg%l*S@CF)q99S/?:XWL>%p@!i=g4m)pke(njORZD:%1L7r?3WJMqm"K_1bM@$RY0F/\)bsZ9n;#%:n?%C8W'WGeg\=SV4Y@rq"+IV-[#%1c()f]FH8M1IT=3gHc\#!FplWtq0"g>oGM_51F8b">Isq9s7CR)W_!KKJns3pl]&TuDI=9:CmejcmY@fcl@H;Fo[i3(DnWZlXYeu$5rcA'5^]3>$58XE9s8Mek=3d31_]=V[Ea&^JTGKiR6LHa\nZDP':0i8heDG>:s#B;Roq+BVa\\W0HpN#V1N0f]a"KI2Hai(m=1t,GPKpji;<("EAaecZ4>Inio#WP7rMn-h=.POFas/'N+uj]<]u4FjFUuH1R%$05?kP4Z[M/JM3A*h,3gOFua%-R.KbtB0Jn6ds]_?;:U3o4+!P\@_i.n:>atVTD;A^:/$7h;d6'+V`WDZisH,%FMkH<^qTpl,,seqmrr[%g*C/g"a'N`d6l,h)dK[M=Yi9_b*ih?k3!N@HW.(jQ\0#O/I'X\r+hpZ6(l(MYZdmY8o?dD:0R0U?Hbksa_VHd,!_k"YFKd,b?HIN.JVR_46C..'<\8"ra]To1_VG&17>#7EW!eJKb&kd%jW=,lk`3a&gr;4?hYDt^?JpD-]r8sJQ<;G7_='g=8PeQJS.Vu_ZZPTeAnJcEGo7LfR?cCHsHQN+(h@l4blN*8sW8ot\8&ib[]^ajnrG#Znb!NG1$7m=S^[c#9Win`"W#,s5JM4HQp^!';t1TC!C)Xm[(8NWSe'`2T=1&TJ:")^pWofMp"fVitGH52ZNcE25DlnXfFgAGgj>i4#(^GUudYcp8\u?G74Fen;7&nY:4;GAnQ5KT=`Sg;Brmk?Q$#i^L9+sLl(A95I@'7^KY?WS'fS_rG1RT2C]YGIs0o0:o(BPfV5JA4;Nip/94IZCbRfd7EFO"`b0l!nQ;b8c(56&1R0+#j6*J)e:_N^1P7C5=V_O4"M-<&+&p9LtRT<15G<;R$9g4il4roo,<5G2/k#HnPLPd5WQ@:0pNBQ`jS.;&^)IJMO\iW,7@E%22nkEX;1'*K"qnme$Y'rEXjV.N=m?6ET[tf4YKDb&G$$)=!h6ZPIo!dP-V3Kl/RJI:r-MdPAg5fj0I^;XnS]?A$7]E^`mp*!J_^UU4!)'(L_@:J'H2bQ:L=%Q-RQ"_gc.PFVf@UTAenFDp4o8:s/u6Kp43U5;m=$;CV[^[rWRD-O,RFlq"t@$\C:mb\F2)NTV"ugo<.3+=Z5m$kDm0A>TilBDtd;Z>n1))9;p<[)6=HJNWg8]/;g(*1OlpZJTHE6(6':FHGVr:OhrW`b:NbD1#,iBKErQ%6(!5uL#iS#Mrs"aWqA7=E8fOjnX.S,CfF&4\I4qbW8lBD+J(5sNs+^C%-R;""-pPDAB_][%nbR/t8,Yhn$>0;*Ur8EJe(Sp$K%Z1KhgFAVJ$ekL0t3:s7cS<%:[@$S=%uor9G4U*k$3n$cFJ/rc>D(6R'g"cc.YV4Ujh1Qs-Mf9\h<6(^A\u'"3Tj\9,lkBTDsuOjlE`6iqp49CXq.V7eC94Y5@H:rq(\;_Z0K$^[rSRDHM\;pd1I0HcM_#jo>>qHKq]G(uEP&GOA%jhjJJa-OVE`.cL^md8W%NeY^J=L?)uA>l=(DLFo>Rh3-U&UZNWmrEEp3C02?-dll9e_ZnLf0&b;;:ZlksaO7>0D\RE2mJlS>MTaHNc#qc3$O?Gq^EdRM.^IhLLX1J>,NWK2=069;[C"q8fNm31gj^RO>14=#i;h+[JJe7ql:NUcs,NQ0'h9loG_UtflTO7Z([dOU7^64'djkmkdq>ZuqRX=X3ci7>dP5aJ?n,CVW8n$\EUp_IWV]p6FL?D'sIY5muXU`MXRFB_H$+VtaiM+NaZuL&F=&b=6CiR%+dtBhTkhN5eB-RDXdjW06jQ&0gYC(BK1k9m,h3E1d)`I?[bbdj1=]If(bT>XN.Z$,./:Ci:seVp#oCOI]SnV-K\mBXLtb"o]pWPWq*)`C:a,,4f3.RfY@n)$CPW$s*X(mfDkK[X"V0YqO;C3IIYrs?@MjWY?tt@F"K*:1@q0BD>>eSj3[b^h](RC,$b_'R-5>SW[R(D87^:Ut7P;fug,6&HcI+6S743u4Ra6ZuWq_>X7pP9!@+r4U+kX=n&neaH;mX8Tj]e(mt%U\_@jHYdm4hB!qF=,/GkJ)&kFnKf_\IqB(F8O0HNqWK<(Y35*d$_Ae':?ll*ma/X.BB)2d9/HBREtFa#4$P5)0NPI`[6_2f71F,s&sIW*FSd^B7M^/r%"8Nsbk"3lh>"re.V+rf>ls;LF/]EO(Vq$R)&"I]3lY^e62sk_+e9XSMt"[[_hss2VnJXh=TsVQSWmoXl26c/!iugeWr;2"@'%gj&"'DnYhh('aJ>rT;G4RBYXNE9,Cq3k],LpC>=[EqbLL?aRL3F3;;/"=8q9qJ+qC7fUufjdnm$cbmVnZg[^GR5'_NeC49`_2Afkqlt#^[AS9=`TL%lJ\Q\!a8b=_]=:ekpinb`OP_m'd6h:;qNZ>WZd"&Bo@da@"7d^GhT%"Ff^G;2:L*H],/ttAaFhp'9-5a(=-<<%Y)PTAY+N#b8Q_R$j-;0(MP"o&N1G+C(JhSNO"'C8#sWmWMGHrLqtUmX*HU'X`H/`L?edO[*RhcKjEGMp(Uhla05A^&>Oh0NlMfZXm\%9"]tjKFpU>::^JWRs#"@PN?Xae6e'QZrWFIW\j51R&BNOjtl"ujL;C-BbX!./PhXI!!GWiLon1(=q3aQp%P^H_Y\Ppp?P5.h\Jl[:.a\Ga.8YNG,as0m7PA-oe/8uEbQK=@g\nL^rl3\,U5'q\A+`Ebgr]5(62(E>/0nZu=GEbir::#e+%8)]Gr48/S6`O0CeAWH*eS,^8ONa1+KXTuMQHm$tBPLgeZnA4MmEENd,1@43tnTdXcq!FU/ZSR)uSpjZ:>O7c`lD]2-\nq7rk1fV9Pg?hrm\"it4mq;SQTd1"^K(HAk_nbhEcV!>&^0E!A%MXS2.g[2HYZFIBT!5V]_8F"5iM_")L]2#ZHL"mrcom&s!ZAdDXl#-G+.-q].M_#ON%*fH8T$h*r(bJ1$@F30!@X-MYrsq$Y9C=B17J8GBC@`a]BTpWXHH4N[-]5>^HpH.6CD62F>SN,2k+KT!dg-09"#ULX*[7publE/GW/LI"tSNEM@(9C?Vu;QTam*Dhf+Vs7t5-hckKoYRu8@=V*Z5r5n,N2h[K8#efo^43K:gJ%LiLLOm3.IJ1rkpT*3LH*GPZJ+gTFgOo^-hOlH(QJ&7O-F`SV/'No!sQ5,326e`=,.'p#3>5t6R9]]F/#]6C3Fo2@I_]@^iQOq(?,FJIT`5*l]oQ#@`>b=+p`bK=J!0'*o(YhNe&Cg\rcoa1j6m20=#oO@)eG&*le`-XI3u4-M4U[dq6q*j?a0c_dMQ+Bgj^#\K's,jMrNUBDd`PJ4KC"-`QYc=!c$?c8+c1pe>fLKT,'e[=t0`*pqhfp+#BPUeTCGJGP?fTY@(>V#OHR'MT9d.lct.I[80J;Ym*uTUCp^X25=hFRc]KESP-he7_#\AeL!79J>[K1q)bD8:Zd/Aq"9Q;R8?"Xc*hG+Yf\!LH])bZ>*\s>k!+GG/WrC9-:.6/mU`fA'TP$?3AAhN3,`1k3P41ZWoN$7b>m/G.+BNTDI2n`%=5(u.Gh;o+VI9e^"J/_fa0lp#FJ],2Nj9T%8dA_M%o4H"cp_@!9kY[.M:J\_dj$+6n-EKWnd'uT3iOe^1l:0PpTl^\H@XLS8Acbq!X^R&4&fQPfh*i9_/U#i+Oc`ueBGk&0b1k*hpO)8):e2EXI9/?Kps&l,2])L$*q:f:]mddQl-C?_LnsHg<%_eoh+9'6^it`-j@I$a]p9Ck1mX&KkjSm#SYDtY]_cG`m#,T"&oUXRE@0d\#f3SCF[NjO)]OnRQC[;?HLUOWCXM8KcceR0$b51P>IPm=!k^Cq35J-Yk05C,](q2*0$Yl0Eh`%a,R>P9*?uC4Z!\Q\N\+oqWW[g07W#^-:OD5i)qFNiQtI9qpj;4CS'3p`^Y9g-)K_"W4Pi.GP%m_oUW+i&hJ2I\`>+[XfcRX-$EWMs*T<%rTf9Zh#H,\!#=))<&/[[T>,7N-t5P*[:4eBleg^uDgY;No)9l[$_DYg2a(N^JSW:%k9dBW@cEP@%dCV&T^Ud,'4T:sYKOER:V3L:2[A3SOIA):j!q#AT>/dh%pf/t?r$/.2`O\;:jM?5/%]8+Q#gN!-0578fsEOKnsNu@$;%"p&=_4Xf?Ua'St"!8f4kguhToGDGV2)L7\DQ;A2@UV68^16Z(H+nG)i$Z:.Z_b^j(r4Dk$`K*1XS&)Q2c[WZWqRi:]K[4_4*+Q&Jq`]JmU?;c2YAV1kGM'8S0;VH]h=/E,MorNdIV8B.+#hCg"@[')i%QP'=Y&nWlr14]p:iWVVE?fALD?N4hJ6n14jo]i>>UlDb[dejpo/Cu!Hd(]Gd;S062C9WG@HTa.I-K_8Gm+[=6;E%-SpYhZ^=r#PK)>'bgjZTEqC+'q3rI_G:%P>5lT5XJQ'@i,1X@Su]oTe8]^Nk`eg+>al-&C7o*#q-/%cTGlDc^"YZd1W5J$!B7DKJF,s5il--n2C[qD]c)P;TMk]`/Of1B$Y'p$c;`AMogn$dsd/5[;\GcZVkYrp/WDu#R-0;/>hUM/o=U=ND3>P6S]-QnSc,=#&"JQ`JIureoh5>44F-0VnW(Sg+tGh#RogN]*8%dE(-UZ^GnGZ+G++923%#tl_>O^$,GHVIc=S)4\O7>eS2q>;jTk79?ZrS.#'"V3iflbU$9l'Hnr`5)g"=dqZiiKP:!X8Q\=fDg*"NW1M6s"2i0p%66"QVq(\ru4`R2uB3+EH=^0kICK7Ynt4ae)H<;F>'Gj=QAG:TiBqO+L@$O-?7T:XG;c+nO,S*l'u5#5>W`9sK>/9u*YR2:YqmKi4!&"WAjVd/1cSo3h-KlmRrSoErd%C-@3qM%&S9<6>&rhJlJoj=.e9VjRSrA.co.7Ajro-Wt1b25,(s6^fZY)jh)G+\e>bs-R/=JT/YC-6idCX4rFW1DpPQ"l0*-"j`Lljo\2<\nB@Za0V9a&UrF"CUnP=VEm/_:,)RAn89Sk&5`K#asCkF_@5PERlZ?u*b7?8L*eT)7kU0.n0/n:/3h/gS*VKg!f&1p6efY;.m3Ob97s"4$_mQX=>>PrRuZi8+e>K:m,#M8MJLQ,eb*8gSTYA+T:s2MSgfg?Ve`f)BAKlS(u[MIleS"dX9.Hi;0=4RHYeqk&&fqf(([6,Q3rId5r,=4su<@(X_<\b>7YmXPUn7D!a?;J1]lX\TrJ;J'gKOAS]h9>-`OQC1i5Ko*-Se"+qNV:lf!p#EnCF%IZ=A!_\#3<.c^jSo.5,2GSbI/Dguc!#J=OSF%RC92nF--h"rm_ILCjki-dG!lqe`7I+-YBVug45N)iOO.8#-Vm"b]0rJaKD5ulr;;KS;Fr"H0XC-1O7IZ5;8'X<.FZ38b3q.ajLX16Ykqu.i$?ZH)Xf"Wq$!ipGrB8iI0s3BX?'/fR+9`ERjs)0Aonhc-j?SFFJ)PZK!InnM.OB94mqd`@2#h;YhVH(`?/ObCHEj0u#=>nhd>\!HR8U0A^TPoOg):Z[/ael.gnrqUg#Z2>cXt+<5jWRRD9SkMQ'=[5C/f\5T5o#^=#oq4TD45ps;hk5LKkeb->lLtmqVV1@^Erf9POi1FJ:HTbS33W2C\#&Xiu?YL9H=7kDHJl/p-%LH&[=X7^X"rTk;e=XQ8nl_]$g1gs5r/oDqqq8TjUuB^X\]mnZe:h5mW=2Q9Dh&iQI!VQ`A6.B#!adq!#gHY)ZT$lU,P)/TW\9\E)%S&"4=0GC.((BE7Ugr#6K.JmL&/-H2"kIh$.Sp\t_b.WkK1g:Cqj3W99)\PsP's-?dSnultqM;GJtHGboE%H_#i7M;N%F9Q9#>a]Ll+1gOS,sSAsRAlohK4(Z.I00&CjEX]*NU2V_`3IlQYFrYGd\^G'!'d)F^SWtDJ]?eb(*+hdo"[,Kp$,MT!=^29`h\n%&3?MWCO3VVt?eVgk#BV'X!&\B2m9S$^38p>BR:1\b8iX(MaNeKi[OB(GiiSX>l\M-5@g.;fjoUU%%?1h0+Y\le2inr-rhc;p^YCq*pE/05&5ur@YHr6:Q\bP.SOk2u('Rt_SErIXdN%^^d5%M1ub)[S2r'0>\T,tQ8Z0`$ihlQ83EVKL%Us!gj;.e+lkANVM_[:h%?2okjQnHYCqi:gY%\r\uSd;8eh-dV$jH2PP$j#%fXdmdUqWD5-ZiPYso?W"JT`14U@iSPi.9>":Xpb'73H392oBt]&K-fgT;TYK!_%2o-IMY3:IGDeB2KA9+I*VU0ft#:6[P)/nZ$ti'!Wl+m$2ih(ANq-Lm-g6GfidFXph$tF&W>X,[2-2&R=>^uIlWS4U1T/"^G!P%Q^Kf)d^f?=.d,\T(R9+BDs&8e$Z7$&6UK(*qBL>!)3P+aeR*_!\$)I()O.hU_8PRlpgY"GY^#H.qlI^E)r-Z0qP]Lfqu;5u-Un6L4"0T@N?,WJFOKosAkf*^&bkcQ%"7??f@+>6Q<[q/UUReD+3f3H=/Vn9h6^k,fm^q6taA"mESTRA4Vn4kDd:Pml-OTt"^867\<7X0SHhahMkt>+.T;'#c%jOo?4<`0/8=`=<>^)>*J_)l5'6K]ScA.g)aF4k;;],G>R=F!?V&a-@AE^\W"L7PMW[4I,1%->Kr>6JF\=`[m/bQg<[RXOWdj'r@l6$rjFg[a2HU$^\GtasGbY9j,d,2ug>CuW?NS6O&Ue"Mp$+S&V)J30*RT/Hg`geYV@dk0lk/-hDC51na;/5+"ZI,g2KUl(1&lDMol_F,6kR3j43%]@;N0!9@_6i6DCoWIs,%\W+g6AR[s[aWT[hJVc9Kc@"OFk5tbG2&>PYL,SQ%D1_J(]s`OoCffffAA`m]&^6KLqXbi>Wl1dhgYIYe,$69^2K,\B.B.3[bGPq2hTl^O%S$Y@I1l$SV"qmfEPEe_'\=.E]0>op6e;Emb7QjM`s7H@M,R/Eus6QdNf.Y?4)]g`$Df7dZ:@ECE^bcZ?(arbWY(*=LaamS%r[f25nml$\J1@!#D@N8Kf@)2b<8S-OC>\L&J(2n:51Y"d\=kf^nA]M!k9h-]M>>kgU].ZEZC28u4oQ;Q55/8IV,RD36--H0B*'nj*qY$QD^?u8mX<(Po?cd[4"<22OZ\!Pi+If9^MhE.EN\;h5(qE(Tul]g7ETX[=`>WmC1t5q&FY:PF&W8hk;]X&'s,=dA_1Ks#Rf`T7TjrMlAB]Y.fmfGQ/IT\RO_h(H78meILmW?@_Pk_T)08?ILi.%52^G5BGk=KR(u;l'_LBR_%oc;qL3emSh^*?@7i=*l1$egr2:aE53WGVinfEdo":0h=6Tp44j$XmW/*.8]r3:F,U2J$l/g1:g?;]S/bI1#][9"VJWN7l^1&chl$[LDGA5H;;?Z.ReW3N<6Q4(s(W;\cR6!d56Cfnf7+%b5mtOmAmA^c@;8\C48!#;Ypp0Jn,J*.;q&t$q]MJ[L"AC)pAQ9P=:HWY`,oXsRoV*rkO,s>csE5@q_Y;ith7cQ;GIU+!'*kLPjt^p!hY0!"=c4IqXJ.*mAQY?^h-fjSbYs/%V5XF'niW;PCK:,92c3FMR"f+-o9'/RtHk23m.$PK[YG(TKJs8R"E3WJ_?[gli3f/7b7)bR4Bs.2.pr]U"E@3Znrq'Dm[,l\W3k>fs/Z[_$D]`BnI%6B6.:XV4CaWi%U\7*u6=*5T""o#C4)pZ!-N]JPq4b8+IdV:fn=T@0`FjIe*D12-\7!O'LNaf1`1\/+eVf>?3s*f@Tb4q,*>r(p$%fa!*mM=2^abOD2:*"?99Ec&9AO&lC/>kR!X8-Ci*3W^Nn,M4g/p9[@Z/F-XIuY3lmbnWQ)rjg*s0D;L/T.#_nd/7Sg%^t/!mCP[mJ8=n]:u6fY0p4TDcTfK"7WLqXC5^&,SDeagp7JMlXn67C6rGl7t0Q(f+(=?1u`jMX@MpAa?Ou24K8C?DFr?l^ph(r#aYL_r%Vsg)g89I\6A"S.c/s3_6MP'a8XH-D?)LdR[.678^u)(6F]+:3uBjL>K2/+@Qj'hFkYeml_EY=a=$NI_2,`ef82DFi(hYQd>KgF7)5=Y;Oq%A'Qglg2!ltnF*#.I@>Z]=*+?MBoa`(6E&\AHN(mm]_:'0hnnlb#@@ca/*l*I#24[j?OJd>m81Sph#H2AA09g8^&On9S_'Ej].jsbTV,jbOE+F+^`2t.3t@[mBt)KJkTOr(G&n$?A=LQ`(r_]LG,EOhE".b3.$%r'o\N%kXWXi%bi@@J%F8'Z9K1._^r'f&l+H%6(&`AcD)$n'R=FX9rXC%&`WXj326"of'7_RF:ZV&YHBRildt^N7/;o3V_$G(U;)AjbV995b2"Fbdhq15*Y/;#`/(!2st76YC;]Mq4F]!%@gP_,bf_>,FAk_p`mZIH\m,L%!1p4OslAG]G)MII7P>(pROd6]lOq[\V!u%?)G5D.=IKqKGr);&#l'X=\#Z+OsERruH0+F3NJC!uTCrRe(af]^J\Iu]@KL6plmrC?P5k6,X8Y.Lg=1$eXJSuE)emqEe!Ac;8*n6h`T.Mt=8Mo59MICW?Nec)M*mu.eRdH)cenT)re&*Jo\l\U]ZYnXU:.7AgfSN>@()^m[enJk_U8mQ+#(>0#u37A8"l3rArj-E30S8b:^hne]02;@PK"f)q/GPAr"5KEHC,6g70SF^[(rH3FKSs?bHhgm@bcMu`"i%)^F#.%cenkf+JP8Pi,Z6;tt>Y,HY#7MS1F6hoKO4"S:Tr0[(nJf@Tg.Y!>7.U4VBS8gW9UmdFt^Z0,/mHJuTm&fCHGr8kNqLCO`Y16[)KgFImeC7Bb_pH(l3^89HH2eK+O&/3o-ZneV:>^^TfaJnNiO#T1+0c+\N>d6VqeoGq.%`_-d)08k^F1G2rJ\7&FOf9XA/MF]?gM#507A,Fo;\HC1^A<80n!0De^a.l(0A?4)8IR_]G^.*OkM=g%`NfH]^7iJ*&oC2UX3[`Cmu_4cl_52\NT[=[2JFq@'5"D=k2O$:,83..qMjH60M2D8`AA?bPcZJN!("`P3cUs,rP_:BgcIBs@MNn,ElWIgL8)W+P7OiI_?-nKOab0Xc+2'c$[-6OfrrbBplaYQ(FTf04KX"h0e%d>#-(+chjXE[;]PhT_RS-NZqu7t:lDI!4.t=P1W=@.n>"`WN,VW2)$2hi`K$(#TRY(\R56Zi4+j75GDoSD;i;71u6#mV#S3R^hfNil!'VN8FRRift66I.u2VHPXQrRbiO)pfDJr?j@m3*KugS]^PW\32QOf7/GHpgZN285;0XT(qFYfC;;H2o$#iLhc3MZB/\G#Y,T=&gOST7,&$lcb8fMC;`n8CP"n+2"fq5Ha^FSOH#O>hh1)kYsdN-,jjo2tYAcLM]Tgm\Y'*WFk,p_SNUs#,U4s6_)lW1Y%eGlIY_[2CF<^ThfSC?PM>HJ`rhS&RA.fK,criH^VYsb+\rJU>Ml^rIs\5hM`hoNR3GlT;2c2=on>FIV`obmgj8._)d7Q*)?gZ`kTT1hK+'lN$[qQ%R")W9MDk"%t<[f0k;[1i=M'VOKDIikZbQ]d#mI[]*TT-a$.oomS=:C.%r'L@'Gr+cLMRD!#R!8V#MC$dujc'dmhAs=bZb9>rF47.oPWt"(*`;<'M^LaQ#g`k"08'8NQ+"VfjA9:L[p-(IQ&+0pS[o_L.R<9n.`E&LY7YD$V`U=O7C-2ePMY6H3*Bs2HEOKju*F"FEM>THpjMbW3\@:UEDa)U+MW5$doH6BnVZl&ceD9C\so?ZKBO&s&,H^Nq%$orusQjV:gs]58X!2Vp4pk;2_UUqGRK5jK5rk\aVA#ZW0[6C5WL_J#c$C^]*N(HMphn59+G:gKBJ*;`\es=af3!Zt2auF3V4Khj[p=d?3ES-_u*9(J)>+ktBq%CdVY%dW5:dc+d$(K7TAfXe^pNWO>FeIs[f,k4Y.BgM5^In+OlXEP]#ga2h@j4gLQ68ckC8i9rf\t"_iYs^rO^52_(nGni$(W(VFpgsmiV0jXa1,3>Q2%XcOOL\W:^)8$L.C_i89K+COq(a>9CE6[Uf:64((&H4(`>Yr]S`>e4U$NYg*]J9:%!>P[AdibcO>CkI*%J(bN;?5j[u@?T8"_esO\k^GI\O@bP)rneoJJ-hM+!Opu]YC\c&.Q/D:8I38=a?e_7L18OSEG5oZ-4TBc_J"1H]JX263N0Q3l"\ZT&qS*74C0eINC.S9W,LKN\=k:??h2K<8N!;484=Gq*\:m4iImU;U'.bcN:T5Ug3#$F:sHiY3GC\)V2Q9T]8Z:?sJjlT52Y"/%Ugb[.B'CBMW*gsCpZ*E[$p,]nDs/ImTm-OpHfn,VFNR.Xu+:`bQ*+:+3iVM!2V<3k<"Zg=k2.?M8-h?^+J[]c6.VShkU0S_\q#.r;*RI2H?2p@?@1E,55o0MXRo,g/iSP[gbd_r39-iXUp&8%FX;'J=]NM)dC5CT5^%Db>l"jWTkjec[Dhs>3MrfIL\?[9gbJ*bmLZorhmS@Por##_%reeNgKm9H\nCK2`Ra;hH:-X&^^P`cm=/ZYjpn/Bdt8V60f!ZWPolRHrEqd7n"+-Fuf_Y+Jps+M2'-C><`s/T;\1cp!5KU\gA@Ws43ZjRlY=t.Hn#,rOfb%>'/te/\MtV5&JOXn1M@Qaj;?U#>[!re/;T--GEX><;f)T@L-13D\LtaQ>1BRNqiY[,hits%B^kRCT1oOgG(QU6e)+6=m9p5YTcX?Hdt9eU0$._Ij[6UUiRCDR"i7[MLYkPXXLf$q=TOBDL7UY-@+*c!1!`turOH->jEk+.Zq5TYO?`r:9e-A2*V(POAg\Jcfb09>IqgYB/m/G>L^REQ=#eiuNb9^sTSPVZg4ct*u@b,WMU.9EM1ShdHk+$?#d\0*q`ej>N:Y0Ar:@)Zq\Mpu1FIuXC"76)9c97H%H4bg#amR@DbLPN4up@%GtKLK3B"&;Dm1I2s+g>%7)VPU;[U^_*&qfqXA."ZSL!c];N0D5%\:<_GHnj%Y<$alPELl58lfT5',E_bioKq>h`+91O:,k(RU%7TOH0J6,7=lbG$=;k[/eMG:lOBQ-+F:TdkLW#4V(uE"onC*l=*s2&'b:\ZA$GZ`9V5;^tm2r76B4l4kAUJq1R!Q9_l;#g+K`p#==pYW4@YGu6]SKn4Wq[MUAH.g)Yrn/V&kZ0qUe\UbSL&)"/q_T'"[(/hFVmR`W%("8%\Tpq7_BUHt^\]habjV#V["=F).BDd;?W:*<1J^1]M9k3G5Kar5B?[nIkJGXF9TFNMeG>G>@f`'oE+LkG:h/Y6`5s"\Ha'?n3*)'keL=Rokm:bBu;6>US-Z%Q*slLL_[2m4k0\$c+49;g.;/%XdMFUXdDo'`f/+&;&ZG#WTIioJ((L,8,S4&>_D*S"eerES\2m/=fg#Fr%G9WI1Ol`@kdBCRN7f_mb1l85sfY4mEEltKsVLOU*ErU]mk0m.KsXM3?MIjr%bfgRhTli%j)&B"8dXYR6$QJsLK\ui_>qSE_jZ_?I^gJKXsmh`b+^I,j0=RkkX.ppT9E-n2GHmg)BmX.H5Y:eW$_Y`J5-cIhQo;n)Q?`2Lh1ebpur+b\&,SGn<&+H6F7@_:W;qH5Bj.erJ5a/'D],OGf2VojD)mRQku$O=$4VEkL,>tC1Os0J^E2`NUA@hcfMb+^;e7.ijD]0b@TNT4+f,FF9^T'LfF@Vb1>/uH_f_PN];=+KLHFBA?!bejth)=1C$Z]chqQ(,lZW[e>3foIW,4NY>igp(]P;DY0T(GIsKVBk74,p-.jid^PN[kaM4rtE7VJoXH!h[G5jLh6&"KOUHb4A+0j5$OT9p9s.l?@mQo00[Olb'aQ#[[Q_s^/jge-AJ),C>DZ#E(]0%P[j=aO=IIu7=bH0AYG^3iils&@kpGd$3a^;T:-Z.*++KOcV.lo>lYaVp,687sdMePfPno#MC<5+*IR>?]=.8`rG2]&pX%#r,ZlhQ*Tn_4$BA'4UK&$)air6))&DZ@t"#0aikI/DUUU#u"`"pFprJ&u));B2;n.UeqS]b."Ua3U\QeX,)]0,cRFpj]bMn>Ulb)(-qO*X_T\Zi$%\n)h3h99*;-k&5bF,G4pL'nJm9FL1W:E=38C0B=p+p#?:IZ*s6.3\9dBor@Bnkc`d,-OFe-Ln<18UDKPGg"fD_A+-;:&FsL[n?bn5B;q&V5KLOeip;HY_)lt6#s,Q@0Sj$QQ\r]YVr%l`OB;Xtm8&b=;SlL:d[K:aX!:(1BUqbJu*&9R'l$m\&Mg6sB"T"8A._?U^3"p%^!q57PJDa"`1KJX+3?A>K"qOM)6#'SruYV1uk'[j*qU*Q/EZS>n0*$L;QLUcGpkE_aHI'3&tq@MLJ3%+362:=B3A8(;4m\uOJ'r6$N]Zk__")[5[Vgc'u\]LOl9>XjUn)AlHQTaiZNs==W+928JO3HDoej&>):7Sr\B0ZEgJ[Y1FMuPZ/I)<%#Pc6G<`sE,+>'9!NVW-Y8)eD)9:#0dZ-$Pr.EV[_k>]N@1IspD;o#Sf3_;bLmqjjLsI)eP'X++dqdM(OdAG^iXK;(;IlV7qQ[fnU5Jfo;7PX1;r<_qi"`:Flajid-]pQ\O_!>hQNH!0(%)rBCYuY#7[TX[>rK$q4g@)ZdSF@.smW6V&T%(O[YMP^G__SZ.+'u[m=eO_q_#NHQ2t_"S-JTh/;9L\+<:/Qknnm>k2ggJ&=.-6crhMBq'r^D%gOsP;&mc):uSe\R*.[?bSed\`;#Nq91]lbYt04``Tr4ksM)U8HYh'6F$+PR8Ikc7/'A0TM0Za9euts(d0T,D4M%I$!Qt!pG0,Q^YSUUXSI(V&DmF+g>N'5A@0D!6fHq4HLq*!=247QJ7$.^ZiC$B_3bs9Bc3.s-TQrV>4mN?$s:WTr:i5>S['TD^WKbBB'S(jYP`..mHjW92*1uCLj`(1[>ph1*[.XEL2ZB#Q),XQ%k`9*.REY$A@D6Pj0B\)g(sUiJmZR%2IoW8!+(lhZkC7sUr*/<:8,M-#,I[_qG!"fKmu/YA.uFL!fb\OMmf./\%71Gn@/g/3Y,4@hNAm!O[r_P>:G8-4U/e4YS<6$`_,nlbc,(YH4RXVp8FKa]kL'0Z+2=DI0OtEUakZ?D[BRj*cDNB)lHCcLSBEr&G51g*o_N35#oVS!2'J).Cc_#lkdp4lh0uX.3Em?*7-gINj:K'FriN(4iZonI2naI3'=;!#qZkTXWi:J.P1ZTgSb:<9L\^,3RH.Xup\lhN)blIV$/tF)7[/YGTij1GfpeV+\G1X93Xm<<@JpY]*'A'_KhBT)77b0AUM5hl+Zn,C`S(269=\!f):OXp7GH(4g2g42,3^?`KRqq$2Z2p3ZE6cLa.igHDL[%76pn)'`kF2KVVV_s*`L##O>?[^+JDc4>]*sSp?\N'%IE5;*>AdEUkcPHFo&k1E5necVejE9RmGfXY=a37="r[mHn]Zlt<]#8H@43CO]p^:ssZ9_Z-eq=`EEhYe3F[']JjFpb!MsWTd3qrJZojZik\HM5Ho<2V,/DK7)Zrk9>I/`HmqbFf(UY2=s[s%HbUN#L=EIWancWKo1Lp4?94b)Ni[`a^f2a&,RT*/"Yr+H"ooReDGh`La_;OW*ILkc:(VuFXT#/[?`1SPKH?Ni\2(!0Yme:N[OG*7??*0$\CIsFa)dn3HjHfo2u[uB)#.*!?mGdftfkBiea:L*NWGVEL4C2#ETjU8VBheAs?&:t<=5h#FD.nn8'uMk(@:rbnGKu_CA-hnqqL!5[Ve,*\*_1*G)mU+'jpYQ^$*1#Ilu)$rq+7G:;5Z?c79/p5%_WmCO=sfQ@A#2*R+]q(EWP(\%noNk+/@C3q&FLVZR*5DtNuQ9EGFfh(^;*KarPHM6j]g[&CF>T3oBh%9>.23Y1a[c)INe>N%h2nfFJM\V@3ZIX$Yh,lnkdrc7k3M)$)dk881\7K$6@r_G^"^>n++uGJ7^PA4G>T3%1K/oZ$r60"LIKX@0fK.@Yf)'AbqD@Y*8e\?-_nLUs,#VlIWk_=j/5T,O7P#7%m?MUt(JTnU5;JbT1&D#RoaF"$d4j8.q:RK%9DJkK-ok?n8cpOLtCj,Gu6DRls"YHF'7"=jm"fikoMhRq_H[K#BYDgl-VS\'hc?o,1&]5)>7AjG_tUAk%L$Wl1f-;0HP=lABnIphQqTDdr'D_Ae92e+;g35,?nX1PM0oE&XM^IOlDN@o2oQRkc]%/$TcdFh=0jN_N>3H&HCM/*Js9?%F6O",;fCJ.\mZ1kbndFg=>kTV#h4Dj,;p%[rS>k[F#Y5XcbXa+CUM/+LZ^&.H`':4+(\bjrriu99f0BLUPh.)de+LRo9dct_F(QV_gh0IA3[nR!Snka_nB>6>e>8Y^.h`oa(Rd\8Vj`KT]B4#L#IgCAoP=Ok7?bXG6lcG"ZobZ;2Z5(tUDi^3,?isY7mse?h^ID1if[k/O&aNej-'QPapOD>47/?TE'\B`fns5>$5MlDtM69OZRUU$`d>LbZmii1WHdD#g_H:o6o=)GY7!V/?9e]NT"Z)9TLlb$I9acLD-^M4ZWL=3$c&5h8E'uqrp.MQ>_7oITpt+*ZG!td1s"[u:aM69s^Hq5dGN+315'chi#QEN'SbMU*n$Jp+"k*#!-SN2Pi/=dfs81EfT6F;&i=Gj5g$8&(Hf1s4YP[%;H^5>L"I7omH-=Yh\G!*.I(6]_([KtAIh//u-&6K32WVmlo#PdeVf-^M\S)hh.T\nhbN!$jSsgGrqTEF(/8a,4e>;2/M'XHc9^\"]$V-b/D55.s+dd(%#ar(bW3:SCAI.GVKI%._[l&jlEg]_;e3(uA<3%U;T36Fg?1*#5@0^SHi^dB_T,I>\Tn(7D#5oU*o4D*j!;18Q:>uJYAXU^)(YiU*"9&aMNYoHSr1XF[&+.g7lS&&4_9u$LrWV3CUh[f^+_.u;8H):pN.L6j^Ib..q`f]X+=Z7?8*S'^WL'_?p6KVg0]C_3$TKoC[rpIRDjh%e7bLpNXaYpU5BZYZ`KNfT))BmeS0r_>5K(%MtoiQiW#@I*ZW,XkI9s[Dr/ujcJ2CenX+S!F'C&u+?_p]ZFc$#Q)LEFGGlR=R,P1a;?j-#SA0KmZ(JPJ-JKau]%pM`l%Z8NcaW@&mIGTnS@g*mKY0l^sIodr&7hbFE,37GhbsOGC)jke%kpJei^D)[X\pkA>_EKVCY11q%4TPQ--lkJ$):`4$7Baj\j)FjQBGJU`Hcq`f"?p0Xg<%+Co\Q;5!WSpH;'R8L&G'T:gL:KdKqZkpu-'O;r<9kT14@WQ:!]O5FsUKsYpP/DgNR#tj:P6(E>F(UDck'E>g#*;+IlVtTj`3c*=ukWD=qQ'Ul:4+-7>;S4')lZJ#iI]^qU)26`GRYpE+\YgL6g"5CXC"VqOaYgPq7([&H"AI'`k8a*%gk,\&u=8]&&iml[#I]`"/:LSL=qM^l,Wr7k#]rL_[Gg>G3qq>-GDIG8cR!2cZ:jHMMT]KG*\V"to&[q]d[M//ukI+5dOL3$2BBDZ&)]'Ag6-`h(T?mlMAHEDt_5'77/il]-n;6eI+@5G>K_DW_cqqa8EqlGe'R4tqq<2'*J+m@!f^(b],bI>-BUH`p-Z2%^@i1UP&&8#j+iP">B5W4d)U$odr)eN(8buBHd7NEC!(:Qt?n`]rcf1L!NUfm+ge09Nm?9+E;cjk1o:cCjEi8e5n:=?fChI!>:6QAO9WBc6`WYMmcgr#E!,Uf)G;G`o'9CH/0JSn"'^>))c;gh@rtGS3dI!'gC\Rlk/sM1)9/Fse92Q4enL/8V243VS0;>I+C"4iRFuHdl2GT9EYguE_NAnQr7aU/%1$j<@fPVF6bE@+"E`56\,>W3"0O/(o=Mc]r;7#AMEQtb"'(*FXqMSp^@;!V$uj7er86E2ri\=h\4KaqjZ1G6A!]@NfRT;rjo:q0n]Ts)XF&R?\D;&/IZc2l'FQkU4,?U%Wdj^=(HV6XSu44&BCO@^fQ_3-]\e`WFmD-j0Mc(t:IaouCMM9e&b9#O+[,n!P4:-<-kpn)6Irq:@en!R?kEJ(%Pl"5.S_7`lQ((Ej*`)2ZIk+.4LGPWKBu5b3&Wl,3h+q07[WPqTR5e+!l)67`];X:r-OR,Qg3RP,E@Z)K'l$:m.$DuJD(cr[_6"F/p7V4oc@XIPFo#H+Z!=D*+Ye6'?DfHKYil+ZBMAeI/6LN=$Y.9F_=nHQ>;:uQeSZ-%g+?$TB:4J>)!fegSeCCfi8=-E%djXC[6Bb_r4u1cjK'k>gaXJ]fQ5G!8"?l\)G[^+>%d^iiSSrp`T+ruS9S)tm<^d$/C.f:S[#_V2h,8K)6b.rGGunPp-r%/VX_/lfa9J__kAtKFP>,hY7S;_eWuGT\Go%]QClD)nCIEnpYVqD^N,O(15`dZqbNZH&"Bfoale+-d+7c;5Q1EH5'G&M#G&T13O7;S,1fEcIq*$H!FqIeqitB8o[B"jq0ci>eR8j?=T;qIc:"2eb$J^OG`Ph-Tln.$1+(prcsO;eh,S7rEm+e#.(0FX4tr!PPqFd(fX#*YY.u/XXl%5We'\kZ`io>mNdmU;9[nfr2H%=rP#i@qbCDfmaG8*ESAibO'T]Hh.Rr-M4e+($Et8+s>KgbZGYn1T:eqtIi)_e&cWHu?nDo=fUq7B=20XT*Y)Hh`Brqq&Y8B6sOLIp]oJ^0DNHZ1be!/spkQc$>A&B_dWHhL,6hT7:J32m^&aF1^V-1Hp4]cK9c3rlb9s0;ImPc_Je"Ap0OtllP%,D\0D;UJBbkosiJl]`X?*"PETc4?k43k>b/6*_BtD52RTGNE^3mu(UZ6DtQ+:u0*6h-@'8G?j4dJPZFn$Jtm\+oFR'ujJ4B.oWm,=J+3fimF*>6DFj\'Q1ce6,]LQs31*OTSQ`HUBkc-[re060*DMG6+nCjA4JcDll:\dqDc@9A9VThjJQ6(;@Zq#Z0>DdfejDM'tbCIO]&G]Pc-T*P(ogR(!0#E4\3`KV].6lu&WoglmbBmod*\)H_q"Kf;ZO@j*0g@X0bi*S5\nfXNhc7Srej`mkR#lRZGrNt'rfSL:g(F*3J[,QWqWq3ES+][!cG?>D@Da50S?4Fao%&N*lKZBBjqYIcp`1rgB8KW:FLJa0c6[o%:eptaCN?Qfd*W?eo);a,ZAEBA7HNrZ(qY.1C^Ad6UG;SF;`tkD]B'lF!mX'"OCR+oQrfn"h>oDtchJ-opfB8u^gJ5qppo9l*]TL^hCWoP8aY1uNHbYDQjCRtS,/&@?iT!,^.!<7p3mmo_omYTHepVnfRglL,*T@pFnr.;a9Ie2-.BhstBdsgp)R$p:][1`Y2ju,I]-4FC3dfN0R2_d_p-tW+2/Fj0kD`+mT:m0.a4ll/bOs3/EBO6neeB89WqZO^.^&`_$2DNBBsHf-\%jQ_3;7h"lV<*#&_HI$I+5a*luVSk]1Jtp0bA6_b$A)nL$V,T/Vf=3c,@"_RPLuG$(+pJb7.h;rSk.V:Z'QPIK*\frKYLO5_nI;+lE=]Bn;qO+[1D*J1#=tht&b`1Od:`pUrE12W(chDn^Ag"0W\*@3n#a,aD4JmQNC=@p[(P?\n4'^]$#BO9]la^'lMnmfAX(9b";0[4=2kFY@#E^Ej.h;A.a##E?n_B5`7eW/k9NeIEbGD&rAMS'/EI#tD/t3kQfPO:p:eh>HXn:L3pDnH+$(,4kUhfB3`Y>s2uPZW(G[fg`mJ)LM!L>WQ_@oNWp[>P-i;j&UlSNaad!gN`pHHrqfIIJ>'QZ?ifLj1IESM:aYS$Too_F4M6+hR`\HoV-J;h0"L&]kZ'd00Y"khn#rI^EE10.]:%FkK4'r#D_]o#2hn`r_*7(2XJRZ_6u\mHfo5.X\.Ehqd2[VM;NC!O)*Xf>Q*88Q[ak2;XpAO&s,-/0i-=0BH6bhRHnrXdu%@"uHsr(uh]QL>mu]A'.FUpIN-i5`#2[+TZah^^p;ootMT)]%bI3<+q([dsQGeWkc7>dqnkJ,\d,S%eUGc[R[R?*N\=3.`(?d.a50hGc$GUA3sWJ#<8YWeI+>;j$4dEX)DocePt`W'rF$PQ_e]o'Nn6J)rc`;B\3B)K)YE69S)tY[b]LViR3p($uc3db6C_gZV'No)^0obJdtIH]mQjdY%bJVYWC49-#pgeZ"-iOq@JMqUi4RW,aBY9Dn7QhUu+>R(Dick;E?a6#5=tRE&Q]pMTZ+l:Tu:s/MKMi.V%VQ((#Fa;8hLF<<;&Kt2+n0FEjEe?1/Nm()>Lc9+R_bVn!ci*UDo[_h+>'3<.2(lZ/2$bYfSntbIoT>%_T'=Js'GtX^M9n7MgG'5YfQlN8mn77A'1XEAKK7-^V1*nkq&kZf&G*,J;9M?!^(0q*6'gA(V'L1bJ/na[f632mE:^.$ia*MbXL5ur2L']+.UqOkGi1(du&X['ICI10m_5]Qf#]aMK\B]4dM_nS";]Pk*AKljLf6\ED.3]HC?d5fhQ##jqT*KlGf0!UnMpdAAs(o'_2X2`/Yg3.:bs*<"B#oW%pP](NrOJ9O[]>a<6?7nXea/33aLUc1P2VbBqW#Li??Po4F[,iXi:pA[7bQ8EHi0lu$h![h]Y#8F92=7[YE*g5&Tq`'I."r!IPncT!?;a[iQf8K[Fg/_`AYffD+A6]N]2K7>M9!6F0]L0%q!f:4E9H8<2ABJ3X@-R4,^7?Y^WbU7ns#E#^45#5cDF01R3?fEC%K:9i%m;d=o!r">^]j`77LLWDh=H3\UJR.)KEo_W7^,*URH[(;-'*D]!D=+YR1I9(e\!e\1PAnW65u5OKeabE;:CY/V8*;B;+o3pehEB@\N+c=FYJ]FiqIb?ZJq&rdrm^a4AW%(d'5LD;R'^fu#h#j22/>BPna+MT$Fr*b5@!8ni?eM\P$E?^t#;&n\ubj_=DunkbrC1@H<$HK0q^"aXA4cF`B3B7<%kpEg;8Sqis9l1e%\21-bW@qX`SRkZZi%'G7k,fG10qHq3ulP0Sl\A!&jtjnL]pj5^r9*-(]&@DO`'.sp<2P2X%\53Y_tEh4Euk#F&*6>3[If_WJ;ep["d?[M(MWXXKK*u6SMO40DdnCb"i.Q56ai/PK(5P=?(MeRjLIJ4a=AHOr;nA,;YZdSZC1H'HcMc@^__@,3M\B-6BX'QCmH2f"T4#Nt*J#BAo@`0]g@j,QYs6\5lCF7p<39XV=^qtZfu/q-/TSXh?Y!V9"H23d]q[%TW$M!hVHc7.:NZ:]u8ci1r+iD(Q+joX:Xj6]&X7c*%r2pqgYYNIU3L_I>5E6fkIe1^V-a8msc);?Rn%k;^h85T"Y_1?aoic7t13EGMjVbpYTn:B!p[?G?ibQ/t<6Qg#OaiecME;!\p(YPrieHGEB%?K+-Ap*RYm?_`!qHh]jE2JH/sCa0`qj=gQJ__$21#:eDt1>`mO@l*5PemAjXGMIiU`g$5**d.5]0CMX7CQ7025[Lpd`WEH*8sq:0c0mrOR_@I)rs!@H7W]";CTOLlH#:(O_0Y4=mjs,&,hptYgf*l,LVZ6Iaf;^.#7EdpDC;WqId!Yin7\O5/:5J^/aS/rV\*m3pHRC6Pmd:?iT_)%#f[/0O,K57[U[g?EimOeTp,>Q`.7"4?n>mbOpKV4"r"'WTicdkoJ;ZDK0l@rR7Mp\atpIRs,gZW)7K.kB[K5YFZ!d4`8eikMMe"l.KVrgW?%6Pkj@b=&i^kLRkEF*^AVi?ThfFg>Uo<(3t5ra]_G5J?VtBp?jXcNr?nU',Eg"QgKL*@9Z/JGt=-)*K"oPkEjWZ@mBrK?O`D3Ti(X;&okEl^PQa30A\m6j0SE[rXPi5d9^D5)&o22ktB"@>uagKZLQmLh,LfBIcbq]oUTM0lLe5mjP/X%.sjD17X4rb3u86h=5?r?jdrd=LpO9&fD]*Up6Q26Xca>Jag]!OPG:<^!l;+=Dq@jE:;5f7q?7YjWd(P"o1SW_H2hXB[%5MI4#L*+F6oMn_()]rd%T'p:qZU\5T[b6g4:+T,lXd\^O72k\FT(V^&4Xtr:Yn1q9@[lr9,NCH2PdVAS5l9AYdum9!%U>MJc176uJs#;/>@nM"nEa=1mW?2^=lT)[,dr:BTPjpARPJ,S[t++7>+7'S`0K>_Z%@i?4Pc)kuSTE&SMsm1Cm/++I4]akqYQL)4bHk/!m)W[*IasC":Q95IpQ88/G0lKH`Ir=2\io@O"A%j,+[+aVb4r3ml-",kF'>3AimF9P43oh!Nc2^GT`i_a^8TOD"s3h?GIE,el#l7kX1kk?O43h=u#BIjG4$Bu@IO=FKu2D0_W"f00MeX[%1Dm9\FerR7ZLHIq,^[dH&"O^7sKQY*cOVO!kDKtc//*m$XWk,5A0Cr2nO%[aUMg:c.cEnQi'mjWbRS6::^24r0dZ2KrKSppJu`Ec,/jDa!^5Z`VAlc=.MY*og*71&94VP*!1h&lO!CD"?W-J:YkKTgHm5()LY'0c/uENT,a>l/&gh?(LS:1Db6UP8TpT,7&3o)*@Yb/Z\"s2nb5XX<1-R\1`#n`pju8oSd*IpX8OGMaI>/8<2.L(,[ih&MIWM_['A!mh3ZDq\Vh<\BJ6m^=-d4moMM%aNQDD`"pnN*:Jee?pBg\KUtm4*/+2ZG-05IQ!S^`D9!r\SeVAL$"j'fhQU@*^!lMLM"rq)oBW:$/^f8^2D9,E7*jD7[[R(11?1l<\Q"EhLJYt0e3G7Z'Qef)ZbC/9ZJ&cW6r9?d:rTu7fq8Zk@qN#n>pqO$2^&$gIJ+`+lrUQ;)aFAX;Q!\t*rg-])J)K*TD`qP.QFqo`:MUf87T[c3>%OM;a&2$%,GqR4Lg`2,BaQk/mNWF2Kf?2a*N!6N2HUQLdY1=-7,HHhd6arOj"r,:CM6Vl\eIe7I`f3HNZlS!((6-n3W_D>ZRA(NTGR_e*iaaS@dXC&dtI&*:4X[+16#_G">2e>uBjQJt%hZP9UqY\V4Q':(bF1WW)3^ZD\&>Or3)\eArQi9R1KICnBT`hGqmaOEp]R%1O&T5c@lRD/KLT=A=ZQbGV#i<*^DHXpk;lImUueXE#=nX9=$r8cGLKaG6Mc,NYMOK?lMUZeX8>qio$@5,4ApXcVtt,El;l[_tmlo/qWmc@V0$K0]g:[@L1rLL>9Wkf%h?gOJ4OK-m_D5DN"kr8-,]o$?:$[N0DNVLp5!gMaso4\f3^/]=btg4J)0[W!A/XU$r$8H/.ZQ]?`o(@M%/+#J7[??G@A=s[T0hLUmB*cOTRGO^L:M`^C?X2WO1^s"=;<\`rIG"t(1cL6SC)EqopSu40`20RoR6I`nf;%K/$q;<^fo7Qq!?b'gCb_:%/]LQt\j\Gu>=LF@EZOY02]:ZYkO7S(jAoFf).EjhmocC"`/X0;Z@$oQ(cTObIo)#Wk#5p57faHh?iFP:DV4+U'/WhKLP=nAHc(]6Q,Z\_WP$nRF:*@[r5@0"5V=fN.Zu,7=JLPpIaSkp4HZG.4j$%U,f/rb6;7s#Uo'!c.qMdST\EA,]`om2.-)jDg[Y&$i'bskj@M_eBCV^Z(1H@<\o*/fA)QhHqd7M$nFeU3uL4]KJl*q-Ks%t0#bW4B$G!oMc#\I/28TJ^pWJ!Q3L'q,pO[j4(;ATc-WCXR2'::h9Bpm4&&Dh(OHe]T,aT1ub3+Xja4>Ua'ENJTM!o9CNrrcI6;UQ[9j.;EhW%WLn#0gH^;(MfRFer<#46Yio>Ut!oprAP2<(tF&N`$?PKpuuCI;l0jqOCme'gQao!F_\X!j+'U,D]RA8W$Z&Fd\l=>L4agB&`tCbN\nI'Ub#&ACl*TL#+ZSJ)tGUJT_;c?Y3b-(m?2Y6U<7BgVrZTK6gJ^_PiM@Y<:3-n/2l:>6oo=(6iekX<)l>h/HOG@4bKJ1qH+Ei<0g&NFf^KSte9-iE1J`D:G677I#Xo*Ve2AgXq0b.gdaosNrE6Gj5<).nQ-Vu^t.mjSN,nL4eK$@W7r^;HhhbD$)K(^oACY'OQX+_+BN.ed'bGu1SG:(^-rEiqMrOr*<@QU"*<@5Q_g1(u9K@Ys_oolXA-=]$$K[58-\UMru1o"5SoP4@@/Hr*loC&sI?9]gmr8%(0;[#7,KQkYnqVh`EEJ+*7N$Z92?LmE-R0srMkBr_BV`mYET1KUD`<[YQ0+Te`7[LUt2"5(n#=KT#@S)-iE-J/cE"N1LFeY96MVl&/R;O_%NBuj::4.e>8;o(uV+&XOF!H895L'U4\mnb`5FMu.-"pqi38Db8cFJ)m@hbHnl8Cn>O6Z/M+'VJ`U_,&%qdBa,_(7@u\?66N!4OY!iE#WWQ>MDHLHlo>cscl(Wp>(=SYL"%IL#7rY/]BO%tJ1q+LpaVTA5Ub4JHNfPC\gj"07H/>5&&2I?<\?)O6FdD];NE'saeI%@\4%35ZU:lacHEjFPR$0(bL4b8/=)*FI%:+Yc%"B(oke#:mA1oOQXkL*8UcqH/,afPkOkMB35bR/H*or($L@;p::ZFGU?b:tUu>V59Xbd+R9(1ft\FaKP4<3W6p,%%T@A#,*=,CH$4!)Jq8@dj\18]++UHQ/FU)_#CU4a+f?A`)Z`mc]3Wn&aI,mJHW?%:6>3ej1h8_9*b;/gMKPac07*"7^AdpT;u]'2;(mo+(i'XDR-t[)]aPN\KB0ph.aQ3I7&teDVjq8[oPh\I2eM!D(^p#S>>+5a*,L.uSaf="d=+lMlNo3Y7U:>*N)M5]S&6b%)YT0\D&j/VXR57S!r?0[+Q1:In27Ca+TkVM4Q/o-$.,d_c%X$gGnL"(JcQ5!NAAR+ZAM_Rfi\/,nSNFDmDoP)PTn'jJ$@?P$L"E&pa8Q`"!O1%+Q[.4*4`6h6rN+hI3Y/cX8:?(%2k8R?C?WY)F^Lp:^F$:p`;$7`moSS*ip\0l3e8B6udrk'VL9"9;JS`T??O'2$DLY`1Z6L8I&hY#"cj&h8E2]5FpCdD0di"/&N`8K/f+n!dQ4G-rY`Tk+MiAl,"c,f5P+XXDLG`)SoJPR=du!5GP:5.@qhS>WCIRSq3-WZ6VATUGQ`WUpL7#e;WfCT&n6il+Tgk0;#Zb64JKnQ]*h::#js]>,R3i2PF\0_H7YbGTb$uBthco)N04"iE'&`7^><"EttF:-fB,(+SfGl$E.OM<*b$Q"?B7WG-hAnR)E97]69%r2;s[K@E,$K)"dCFLf9UuD;RR]hqc"Ehn$4jr02,[?MieIp$UL`5iYZd0T%,8Tpd1h0NGK7p+mO+"5]e/kfE6[(]6A!pG2?eFTVeDNt[JO``c+'4ZWYi%I-J9*lMXT0BcI1:F@,n:2A?be$qk;X"cOH0Z]cmkE!=\*QO9k?O6+W&8,I74U4<2rFr/s&5TdXZ2Ju?FfdA#Up`;)e\)+m+j/=D*H=tI9!PHN/(7(N$"%ApYGp`]\4n-_5m;/mCmnh:NuE)6P;/KCg5^rGol[Fcf:.d@[-_Q\IM/n+YmR2EaNtBLW,N8'`-kssTTJIrjjpYHKe*iA_$RL-S(7H*9oSlDm)o>$AAY/8].UTkGHa@^Y?ha0]PcGl-fE,(eE.]^r]*4C[*.kI]>0i#>7O3&^r\i12X!0$,E(<4.bUB]39bhF=Nu4%`rYWR4ZODrd,IhroWYKU?T@J!mcI>;64#6E?5NG$'HWh<=fPD0k%:idW#8keYVlBD_[Tib=>[I1.r\#ijod%U3Ms(JoWSCd@InkVU_*eG`Q-6D5#l(R:M2D:Au;-[,"segDI[W!LHm\Y$-JW!k/`QF3F%GTYkdC^%82X94t]DKu4_9r:E1'u>Df*=ui\B1#N^_(YsAf8s[$_+)8H(pZ[d)E$6X:+A*lPRV9"71AI%r]TE(2jA7[mJ99_,i=K/5BPaV,U(Elf\qKj!U[]p/_K7iRTGX+$4Ico&i$*>,,/.&=FIFQD70PjfTIltj;;'?J0M"6Zuc`[jC138:)Jb'ORZU-'8Fb>h1?ZK25T6I\cr5M_F#L\+Ia]?(D6ogFfl37N!Nf0B%.SPTMgK'A;MeBWuM@SL6BL+35?q6U0j9Int#kMYuUf5)5+rELb3Lff,4huA/:>6Qs#&nQs4&MfGm:&-T7(!BHZS@7T@EU`46"J]:_1dM>>YFi@%B7I`$n:06#V'].J,U-n'k/TGAPdTG[BC1/h-R25Lde*N?N="NRm:"9nlT>(om1'*tOfQOl\3-9Z!=e*GXPHU^$-NF"Hq^@itXZdO&[^cP/#DKt<*l'n^OW#\BoM(&ecTKpQZI=tho$R?jdW&C.q8c6P@gPt/8LN0%@+-`(67!]T.'YW7W62m&<9s5cZ6:+H!J#3)LF[oi#ib_pmH8hM9n$G4F&(t^>*(7!+M?W226]o_m6seh/Nc\l;L9RQ&7SM%I!JEFGFFc_UfpHJn6<7cG@n^mRWtX#rZsYpuVVm-l!S`_hmk1F7?G-"+oG(;+4bf$lRTF>Qk+_J,GN+d@p):9=@J,J.U7&jhL0Y)%6uTtk19FufEX]n#L&k-#l\*1n8SB4VWf^qNE$^+HXt%l..9tmLlOb^0=kg-l<\I!!YFJiVOpF$LV^+mO,\ONd1O>&LKW:Ius/'m2ojI]l@@@(pD>Va7!">hu&Um:V1eQ]_=hTDVebF`]BC5bX([?r/XH(DOrS!_SI@s'q;uLOc\Um)d?Ekeeu*\[kqJI-iKRVIFfK^Q5)'-_=&ZLJ%jYSDZo=[-A_t>qNhS\upbeWDp(i=MUd]"bL:pd,,qp=RA?>09Q850a<8`Fg7>7G'gI?&tf@nA>lbSrWiW3X"'uPu"76&WUR5+sg>B]g+LeSa0R7Np:b-9EUO#5<%WD4@O#ebeaG"pZs#MrPlMb_WG2q[eS"DoSrg!=@-_l6S+gfm(Uee7'!t=7h4_e;uH6RjiGiJR[GarJ""''R6-/-^XA_Y?n20k7M,HDj1Ba&Rq6TrEi8(e#oS;`Z]a"^q3SOC(j(:?8nI]:mj[!FKHUR&r^f$*gnoM^OQ,J=F=MfWVjKgKAg0IE.akTA4Y-C.GoJc,@/+6sTd[\dFh6(pO$!AX9t#E?HK$FZ=.3),rR)eHkE-lcos7r,*lmUc/g,Qom=OTVU7_g2$i#Mb.7dp0+ZIlV.hUOeWI^/SAH.J0_.AdYpr)[i\>-`23R?!!MgN>D,)i@9iLR_(u396DGTgFJ@#3HN@.n$.l2t)7:SIb"N:Y/>W#F-%YeJ0Gq)"cp?S03MKj2jFJQq:]ALr?oV_EH.kX]XTbI@Yc)!g.G@-%/qBjKIIu+NE]YQMK#K/Q)#9('HNcooa<4WJO!2B[.p$#l]RHgR0kT7!_k$X@/Ujg31+OYEL4WRjafIW;?6'(m']=JKcT9mS3/3V6'CS9H-Gh3QY+5kRs:,#XFGU_',s8JTl`/nQNr%cB3?fjV1j%dh=eR)+:^RR>.]GX$!].bM[`R.[LiaeOq1[\9:BBQL%(A5Hb9]IA&/@ZUe]I;Slqb,pLMV'>B2Jd"eKl?Og=&%G*Sg@g3?-S*BlIQ%ch3*NPKMM$QQPJGr*uc3`Z>_EU7Fb8''dlWt#.%KD_3r*o.i/rR;!Tr)4ehe8VFp:Yh4,KH5W0(K!oMp.UD!E2;o^2DoMS_.F,XB9!$4^#4(2BKNE!%iQ)%ti.6;:PE*;[#$OXS(F',SPd[(D&pI1:CGcH%:62dAW$N)`a[<`A+qV`I9(W3W-5e!9+"^5/8pFAqBh0Il7!`#='1hdp/#SY/P`pu[oYDI!`=GP'UeZs)hC)P1-b1_<5K.%LHUHLY"h,h+Jt^rQ0<6"^;3BP9D5IP)FRDu'SaSN:aXM2=ODC13VkN:QKYFHDHPh2]\2[/1E)*$Ae5"qoqa&=jfMFZlI]BT5jLU'kIk'5&bmL$Q/_T*d.Z[KbTkM&cq(Zl$+RO]ic(njK=-hlP@%^Z`q(D[[5d_:fIE%c/#B^/fK1OF!!-ei<4.>brm<1p2%cn`gnu5B:h(64U+FLqqW'Dc"Mq.0Pdu^k;!-gbORa(NNBX+V]Sfj'm%ELa513:[QM\19h!%=JAb(;(O?QlC]."!q^.:.X2kF&c>U@P2E[aMJU12HXI]GJLRVXn"MLlI>G&r@'l)MnI#\/I@?gq;^0jB')sjL`.p`?.:"Y10m/._db[P-..G?&CPZG+6]"Os4`0X4lg4p[KB7R:/IdL:<%UtDh4/jb_7pEQ83*s5/m#GDGm[A8Tb$qHM,h6GVn->5dQ5mC:?o92,9XQ=37)&dO5_mV4tUY:`m!(4q;6qPmr3,+0'0o]/3U^BOJA1n.cWX;1]CG1u3"&c!i_d&4Q4iCe#79*35+*lg(j2rn)m4)pp[:AWJXFg=VR^;\+,LZOq\l@^UCp9BI"X#^124G-SRXarDD9_Er]K:i&QL75s`gh0"qErY`"jY5ZQUZd=Iu)+I<4fKV>Ylj"fR"l=0$mTnX`,i4+Q!#=+*-_bh,ge^?oXk5$4Y:!I*6U4iX@a@[#ZdlD_pW_EaAbS35e3V[T4(npM[Pr1R1nMm,=eSLbri1Lu]@GY0dE96E%TFQSV6B4N'I)/*B&tA<,A`]9>QE2/7h=f%]E5Jn&0tQt[%`J4("F2YniOpU"'rq-=HY./?B#]S'B<:RmH)CAO4tT!Ko(#3gJq"aC;Le@C+7cog-r@S,q$Bld+^8OJQ/\Y,>:Q0;Fm-G/TVD4+ON\5S$cj.]U:[K?t):(ejeIm\@n%oCs1qW?aU_c!^)GM0c0a;Z\`p%JjIR?%![<8U3DtP[Gb19qLE+5Mo3oS-t0ir+i&&AVk@`Ze^acr>PFqg,<$X4i_k[m?>Jd)SOKq6V5_BLN2=Hd"m9La!$@IJG(b&!h0pk"&LYXA*LDPIsf4D"I7dl)A5BBGg\op:Zspn@N"1H3>"[#G;b?G"tU7=kcmJ-)UE8u!VkhT4pC.=O3\OOjc"6CWQ9q&[]jeU/PM,7RQoZ:]A2IBhFLh^:0.ScC7b,4'.pK7kM8-q_\0"jE)*4VA7,5tQ=n+1!)KN'JWXoGk#Nl7SVAZ(1^f2#(;]MJ8i7!^b+uQ[.k887Jqk6%Tm*[Q_8jHMmj[0GjSPZReY*o,_HTb$-qB5j-6mIjGd_m3Dp.FG[NN16?g&4slka>K=.)*s*uhBV#V'WoQu\n7lp+8A'#[JZ;3'cU6G^pXD,4qL:[rqBNE,X_)#W8me@G7=qTh?$]`Lae7%8i@&]8T"*aLE6ZsDF#LbLFX.Wpm#Boj]2>>8ah2U4!0R'A?GMPuOaXkiA1_P((=nHf:&`0+renVh=9f/c+J0_%tlJ/+-9.kr(3@"9P9@WG%nrZif::G,`6_D^g.^a"uS8RKP2L^0Cd=K):C&e$W(jA&92el#gn[][Z7Ck>[YC[=g4(-P;I@qDf3;@WNqVj<<'_:\(rgo*Bl2JXY='($ocm6Jbb`omC;<,!AGiqb\T79c>i=L$AEPPdC<-,`'UVt?8^G=HUmq-F%E2s"U4%LJk>C.M,D%K$B.AQOjliI$Y/-6`_OCgLe\SYCW0S<]=5+t=#MVT3!Q@jeckL6^]7o:N#U>o.I^d-/FKLu#VZM;_=<9iASjZGnOOT@Yd<]dnk1@NusZG,[AbkInO3T[C+/JEk*N57kX:fF=S_(Ku8rLh/PS.fU]\%+2RcbKg7cPVc2ba]c(M4,7d1)$PX/%dX<-g97h1G."hM`Rj3U)=B%TXOJ&C&T;`oSLhE\70T,2=ZS_N1HN'-C3:gfbNV27O)6ejr5^-,+OHX\jN\TD,.kKK)i[j)Yq16!]8k$a)N3i.`,p)cSuS#aBLs8Sk!mb&;"Q768I2t8$JFnG#%ToHY@_\@e:9G^^Y_1OtKcE0MDh?3InB7VY312q8!N9_Pp;7]>hsqc>EXrYH@%BBNWS^ZXW!n%o5U'Vhm;cBe^W*&E*.I/2AD0RZrm0OW]NKV;g0q&q5OX4Aljd[-eKr7EqO>BO=%]8bn4X0^t74Y5YgXpQF$+(=J2`-B@[1#RUMsB"T,SY!e<^?(kh/$^_@m"7ZDn%),!2A67J6]&N4-rO_Z5EinSdot\Q[:1SdQl:Cr$Af)>j/I'F,!Y(N8%uj&rjB4$j.a]IBm$QZNqlL2EL2`Rfb6e5Tu#NHOl)0cnN]iD#]X/,NYGDLX,r?de;,%qBdQQ])VYk;V#m+-b-G+X]&k4W\t/t>JpA&Ff_Q1&b$`+!]:%qI)RT2tLs01E+RTfuDb([rs-A3g@QV$O_X>A.9fNd1ZrL;Z'gNR_[VJDBIUiR^JchX.(-K<]F=W#.FA)tKSrf@[6Sm.;p)_VNT`RTBm^RWkW_J=WRp9k<:`:XiSWPs3^>NX0ls(,ZL:_>m^U)]Ze8X?^F2_-9'Y&m@Dqi2_f_]@`7QkFCR,2;;a-6L^!LEh#NgOH9;YNf3KidF&n<(2_PAjO=b_1uE:((`=TpLBaT$En/UoZF4<_?pLC;MfGRckl,!1')b+*",?FBf/P*_6B3:jZ\aZ.Ls7D(&C/<.FgmTR$OYCF\$nU_0(st;>hhei-`UeR.Dm;g&Q4IERdDH.Md*68[)T2Z0pkON.Y_XtJ6(E(ZNA4UIG.&idtNEGFZo:00`e&-<'_oY_'j,'%s;F+TH+q(,>Bke@af%M0e\M3n4Vf3*Y;VW!^fHn"84^b*pY^oAQn%uR'B7$q(:#B\3OLGDXXYf6#XYc-oh?p>,boaZJn.mne**eV?[s-mXjpJGmIf6J#5cR>A?th+%R5*Kfun2b",O/Q0'<)NKXu=7HX[a/XV6b,2*mQ%'WGnJGB3NM@O'W_Atb#/J*.PYgY/?"0U2D/(G;n:79Tn^(I`W4%*R?=gQ[isudJLUg*EAu9!`@f@=@r$(4JmaN_Vcfl*=*u/i];^V[6?Zo"1:9-)ZTQ]n-h%\;(MR<5%>Y+'oj=JUkg#4(+>`l+2*EZbeo#fGp(?.J$iHo$.T1TN3i7TT#IK`DaLS681E<;GnrXR_G0%)jXd_`G1&-_j_W`,-AG6)]j2g6FGn=8$qBe7aXO.u-8X[nYo*jf'%d5kU7,jP0@b'tg^F2`T97ia`9jblHD+\M/l?q)/8g`Mk(qSV$:at:#,kWhif7CV:.hk;>#koK4,V9NPAUZsNiUp_3FXb!RO.Ma<82L]/&l+L3mQ\JEp%+^2s0i985^jiJ:l.GQWo^F^s`rV1gV[4E4qV=TS;PcHb3Fb>7oh*aHj]3U*>(HK_^RdA\*['pV?#\b<=OfZH"pm9K#;7>g+-E`Ob9M_$U6IFUd67Ck,D$<1cdjmQi=OWO7EYPEoc#U.Zu%>YRP#'QRuHDd_T:OO]TTk1#;ULg,$nKR*se(=lN.GpT?t.1SP$?R%%&<)Oap7tR"`TjtRIG4^t(]Noq^1R#6fTMJn%2lRf4P:eC,*>7D-Yokb$9bMqqfgpo&C\efZ7W=U\.br5C[8:nT(.csGpkVh'eV!35*\>i\/jd&a!?Mb;3#=Nr?oYNIa5&NbTuM4]/=0f^W=3%kK@#D(N/oIlL@:Vq:l`j_BtsM8`#2&IXO!1i$L'.!fPh>iUQaYUKTpe8]C7P.A$bUG="<=^2g"-rfSgO9/mAP*?2pi>[iaouaA8;n0\Q[5X$()*\95PM_!U5.EO),_$4$bLXI7Y5R]/q^AdU&"KOc[Z==ZNH$dXneA47sGMP\eb/l\[a2G#+nd-p30/)kpX";d\T%T"h)tD)Z:_Bnu8e/]YuCr4W[blgR?:97"#KnN6t&dla+GC@SoGjbFIHL83C%F21<8&C82&VkPY/PH']P;eKkBI]"A)N!Me1pAmCs#'CPD^2o*$kM,Z`Tm]K^;#*;*1C>IlZq.Pll_*=c]?H"T't="&-ZG61kh](APi)Qj\.1o+g7t@ti6s\qm4jJDrF!Bm9Vt"*Dj_1Ha55Y2]=mf%M?CSRUuQ30\\l0J63e7hQpHMQBjOJ#9m/$4eJG;d)C:"7c$4O%_Ht3J872Z-'^1ERcH35Q)M"5L#s=r0oe;+,XgLc)m8)B3S/:;bRQfu;T6%#dnr^@Ds8gM2n&,X@3n``'_\p^S"eFc1tfSQ*rWLR-4cRL/'u[&T`@mEp_8OuoTJngGOb7;*V&>'`tUC36''\`Ge3'4cJa,%)lTiX#o_JsXlmbeG;E0j[G-8s-"".?KZ^Lea=;0I.W=K42PF+N0*@OCT80fEO^;@QDD`LJX+[C@nS)":h8ROe1]pU?rF_,)d>%-%W-d[0h[_-9r:''Ihf#ge0jCGW[BuJFP#BcGIAR[=JDSSBEF-\T`ilf'ZDuVG:jbnS#=0Jmk#mG)Zl^m?uOji;&q&"'l]H2W;9TXF\t1M4dk=qr"P#$/(Y]_,cate--/<8B%g+<@H:o8Sgm`n,eLf"7L=I'Le2CC`3OAE$Kh!C0?s'HLk-R>P"4N]`V/#.5;[chI%@K@qZ;VrGeY^^ai`mrZs_fC*NKg`^s#M%$QrGE6Vc59fXWcJtPM.=,8%5Yl*#7iR4c>1=C^G+N92F1A+Y"(4%8%4c"F%cToT)OAZP)\:gW*:aP8Mm6m02&_jVF98JY!MlpNr>JF+Q'MItD15B:*lXa6a>&Vhk7-C4`_SBI#HL5tLNA=]qo&TmaEk+];`oULA;"3_("S?KJ"3^/-e:N82M'o_R`\!Pmai$nqJcl3@8r()\>f5)6VBgb`K7#%2JS.bp;\<*.NY"F,iM`na+,oARn0Gj&.8kCE*"cBd3jU5/[3J:u=pb/:D-JeD,J)Y:J%)@5^G\'g,lKY*:AqS7'kL*U7.$T%fhh$N8M6fLaj?4[>W`KZKbZr*@E8+QZW>H(U@5^%6cE5o-FG+*h!FMgSo1dq/89KG[RNk(I^.JJ3i1/9egq)jKML2Vc>"H[LgF6nV[mSj>Wn4d.s1%;SjX<0*+RGOcFnp2[KP'`pbVK#Pk1(oOjf"P07!/=u%O6H,6d%G+dYX+T'#U?Ef-*LO'GSL]<-3]BG.lf+el9YHei2Tm+P?Qc>"O:H0FkRP&7b!QjNf/0&7)L:#_&($#6c)Ot,Wqqf0MG8,f!n0j`=/u9Jr4l5%H;h#FcU#"NgrZ^f1*REJsJ/]52jrs=fut9+^5nJ/R3T!0-M))8k:np;`&RoKp=:lK_3._WXEXmQ)*cs0%.i\pfGAs(/NC(`m$A._co-%paB?5EjC:iV=%*,0Ol+]4oM>AGsm7qPT;'a+Y5EJL$@tJB6)#Vh4dl\VUJML0l0IAUX@hSFd;QEZ.-(0QO]DfI1EPm-iT!jbj\ek?Hj9+2$,-"\:EJ/D[5c&CHe4Xe+^_V.#q&=ia`Z43:9iD66$@'c6mGpCa-W*=QRna%,"9\d;*P25O"kJS<%^"@83rEM2X1:MY7Zh8"!+p\<2[50p.su`3^PM>iEOQQTC=mA0OC/u$!]Dj8N^Xb7De_'$kL[43f;0-#,31W8\"_tPK\Z=l3,q`%QUY1-^RYGPCkjAKpGX<_6,%RG;BggSge1N:.dA.Q9l.m0UYMY1:[sMVE+t:d9hPRe/[n#]nE(G1__6kW(8M(\fCL-Ns$`$S;9#u%a?n:H*SiW$Xh(;n@P%8]-]H%lSQ-%`\OK&!@1;c@l6Asg8"n,k$c],7M!)5kB_QoN0f/0VqcqdnD&adFW.G-VbqMdq>0GTd7&D5+R5R[dkU/@Zp=G0mjcVe;j_2MrU!@B9(['(8P`S''-T5M0``7K\+9rc4,aals.MG+R#\R%!(D2mFY4L6_U;9]*#/Ni2,h'52S7KD@C$&9^)U*VuW@K*J@3CH6VKri5,S6>MqfKA?i5%APk3e-9;0IgM9Zf3"2L@u"K"Nc9n)mHK(UQa^E];F/"**?:Id7^R)^GP)HL.oBQN7#Y^D3"(Hp,X1:]6MKi`6KOsK58ubN&U\-nSL.VNq9#b=8A#WFA(,f]@\B9^W`X?%tNQSVYd<#c[7eDW]nI>sh7U"4TMheN\dW4rMn]o"ZMXYL1mQIP]6+#63_PL>[-.t#:&5DCl]o9MVQf!^t9pD?0J\(L!a["EtrWM=Br2V7OM&k-00s.dR'4K-CS5jgT)4KFX_-X"NQpE0;@LI;s8Ya:k\Ikl!(-q9k\EY:1)MaLI4TZqcWfZ-T<1p'S?\[A_Ap8*]jEdb5'Zn"Xd02W;"DaQMEioN/IST0%#E>_aZ;e:^%\1.%jJ(.NB[^\Q'`Oc1a:<&&?D-_[67-sI6A?$fO$ZF@5'cKH9:)Ff?hiJ;;V,G3Sk77ijiSEG'Y2N+*f#2.L/*CJ%BK:hX!?`/e*Q^Ds(A/9UWb#]YnbhC;Z)Qh`JYmh3,ckD(0ug8@$7:+kKC$Ti+74\DehA2<5K\R3j'0VWfF&\CbC]DC\Tm?uf$)=UlO*U/?kdmpj[#cVQ_^auQTni21k4\elVUMAp31k\Z1'Km'Y[EQKr=iQ88mWj[N*TET#K7cH5N+?NZ#Pj6uG@iBI:G=t-j#$"%LYq>!YY,45&tQ*])>Po&b2odt]>,.,2p5]I;rm)Dqm`Do?NH-!<>]>(B7!#m0n6([@B8(^&ZO;;m5IkHXs%%E7YQq:+eg.hPa]2g(>F;VT&,Bfn>IMUkoG/5*6L`>n3P*fp#sW]8ZGe,+Fn-fb?9Dc%_8L$YU'C]eRZRr,(d``2I4tA&pi4GRB,'1-7mC>NqJC[64#m[%hFOt7(A'Rih7up#V]d'GLWQGDG%SB"h#tJa<-rJG-#H/\-_<'?+BT;;n@(DnIr7@\tc3IFV]2dL3u9Qc2gWZb+<3L;#:G+,9#6b3B0))`AFHUR&M!@XlK^AdK'*-;*m*Nr%hKI4$6/5SO&E-q*@+Z*d4[pOl/3AJc^1m)V#j0AT+F6.%W/E`$GUoVqApiRSYXHU&AtT#2FFr8e/P.=#%$970Qh2`6C8QI5ZF_toIb\6Xm)4I=)%,fiLCA@'+d$1"L=+?ZuTQ+X?f::nIU95H!H,qu&mM^ugM\&>6!N,;a&^.V";\?:U=Tl'WJETCe,J7iM`i(f$$:Jf!/+>qcZ`R5iq6[7LnQO&5j1mGq!2\/c^BAHT[bugHVRe&fdJp@J-j&)4S-$V:i&cRQj4uc?F95iKFD`7ao!)KUpk^GNp*c;Jg8Vh+jFdoS.1X)C/NqIAi![RgN)AMK^3?n1h7BJ!`ZgGi,**:HHHg2i)Gft@6^3g51:Q/'ctZ7,P2Y;3GEIHX,CUQu(u"VhXo.%p7\FT(Pn;odZ%0>9+@IDOXUP`h&gE:_F9pSOCXliV%c-Y3ob?Oh-\'Tia:SEYBR?U,,i^B/a`;g-M!.PmSHiFBg[ndg[I]*3X7gD2bV$&OMn@(;)iCB-g*gTr]G%\G+H:NTXYnmb)^&!+ApLJM-L(ai&?/4Y#Gj&[m$6F.=p-i!7!+)spbnGt\4D'11idsPAZ-Sg,mIR#8jI;@n"AUrd.S.'"Fp_]&/\&&Z169PRoq!E$$q&g>Xa9?KCUcKNBH!1I#t.8V\]UU4HP5R/:&?4?0t3K+L,e,FuMWFLOIXN$OAOH!gnVUT$U6q+JR&%;X[%=ig:.'n$+*,UH4X);\;PVKJZRa*/lq2Z*W^,`WiRWT+0p?o82Emnk$)Zh.\Qo6I^H]Vaf>rOph;Qk09i=_e4P$;./,T*&4O5RMoPQ6>4DAiH8m2[K>du;&[#i(*U)*$R]f3)G[,Go[7&#Yd96nZ3OONO5,%.]K6f_at5dC9N<4S,p4RF-0&]UV0Y&(f\o6[_&1\2FPE+a:Ke&2FD^DNb0FK0VHOT@8$s\E;c@*e0rQaJY4DI.PC5+q`t0$+Z3;^2B$QLOeYL!T\bX@N28CW$[MrfM5HUKn&']Cr7$To:rLOs_T2]K>"#-FR*lNH$@&hCM4g!Y'i1;@:\N*G_))q7*!E?XVr)E^:Uea`1N8s[Jb"2L<4:&6G!8n#(OsQ,:96(e.L*\<>'Y-8oem%?@NapL2JZu=p)0(E\&-bY3l7l'i]`@3Z6OE`lJ3+D$>Ld"E#B>"QtS47(HkbNBhq9#5'"FDUs@q#sd.<=@((?M)Tp@WiQLNHj3"X-(XHr?W$Wlr5bC)"HCKEOa&N`iWk9uGI#)s$&Fq>9hj2.]b3k&=0&QBF@`i9e'KWsN93U-2$NIjV$J@+84>\^uSQE3g,\);@e@i:ei6,pj`WH)RD0XXUl32u)fC2j(t6/Nna#:4[F7.9Mk=dmGnY,+$WU93-mc9#NhqIJ&Xni(i0pq&Q?a]ff10%L>:YaepOLb?oA](7`[N/"jbGSrNF"D'[Ka"Q)Fh9!.XfLRfUjh4Y:<..JFk@PI]Va@rns3FdIF-!;c,mPKg$OIi>F3O5JM`^lPo=Fc+58-hS9`;8D>PJ>Fmql:6h<&G%`iU>?Fo(A\Rl@UWQ1[,Q4HifGe4q6oB1_FOdt0X8e3/]o@Tc>ULJ6k%1WCbUfb0e/81W7F\#O:&[eP[X(7@"_+nct:aeT\0VtiLChXb2RPH?l5M[n,5S;--=hu*"I2d>&,^O:75XQob#+,^$JBAV(]?Y9*j/c0:@GI-^4m0U&n=)4M7q@rNkBi-gj3ZkE*aekO_H]:H)Cg37-rADclS]0'eSM@Qj7s;I$q[^lq.++(CS$tI0K36ZLX4NhDb\iQF[GIWGr@Kg;mt"Z&2!g*[@kEe*$At'$`-f.0g14LLOfm>6M:Ud@MF\FRZV:(7_5]N)?j)rKC<(1rcFg^Lc-?$`AVnV]K?[NDW^C['Us0[`Wmu:;ql6o2Zta^Fq/!;$Vrj5bt`kfO+B8YZM&d1'P'b,:H>J3H/7M#\gSm=tRFU,jb3EOD:NYK3p+F5Y$s1,(Ul>)@:\QG!)c9?0A]JdM:)<@V=U45!LEX](h1&3KkPt\]d3*N7]2mt\3N?ALY+AWRRJ$ZdR\+sI?hbiWZZ*`l;$u[$_E7hJ1JdAlrqV:M^\$219`S70Dc)7k#A;g^9AZVU_*_qOJe%97I#t6)6LR&PK)B)dIX^J)lBKB"HXqe,LR5\2;]09&-P:j-Fc-PUM8/W)k0f1I?@\\;sU5/h>I[T:8R)ZL%^]l'gI`m:p\D/q7LR?BYj:[_KTp_B@@`Q<2aPb,!\Fng*S54[`M[1`Ho`-gNuo`PTpHc\-L%6[!K(I=oJ.0SR,[STTc>nmoO8lP\\PZf7E\-7oYs#W;6:=jnbLiGAie">"uS-1AX>ZJ@"gN1g/INRHK^L:592VF\)B"?HJg;,_+TRn7%"=`<=SH$"@YT2pU?.nuoKF'>6p%QW.ik0.)SU\6&6A8cb`;*@cHsE2!"<.23?Ai,eJ:(DIN9Q+VH2q;0Be%69^2hQKNcf'F"#Sh-m'.p(UWDZKU!WZ'&"FH'#=d:Vr>@!lq;UU(_K"@3U;rQmIeCE&b-%6@@g2RC'T>]K^kM(1EUdaR&*4u<$(/@_Y;IMf-pK_:Q1D7.\L)`@m'`(.kj3!gH=T`U59p1QnfXSV`7VKk[Ku.VX06jG1)\M?8$[LJI2_Shg<;FUe(Kn^VK`&$qr_SI*'<"V2MLCXisanF2&@3I]u'HUDa\ZGT9=MPDXCc;.U=B6/2un@hX*ginDD!Q($/jl==>JpCF!DYSU,^0S\9di(MRcg3L7afV4^$ig7/F[q$@e6b2K\qW^D:CXXYE:H/l(&B6n(eLUh3ugpiLB<]>^/7q'>HKJod-99@]<-Ql[P2.h>6I6RVk(8=[Rj78O*sj$\KJ*5/#rR96.L<@bK!mfF?NdnH+<@OP_,5MKf.0P7N86jUJ:?n!`[^J.`E:?)TGbPc&\H9X5a>t9,@PQ^Vp"?+fP"N9-k\;H8OYGmh133$tD3!,LV-Ujg2+SY0!]"b,[^+Ujc.:Kje<$%O6KI#i[K#/\a6:c*QkJkk%YC)g$AUg@XC9R/ECK1R6EAQh3:Dr5PEsE*Ic'Dn`EsCs"K@c,jBqhT1A,QXgb!bS1<:HtGHD5]78KroY>ARAKl.'[OKkqH6j1U9O?+BnN'J>G5aW+ILtWNm9M6+APFFFXk<67D1=c6?B`:DVLrO`AbqpSl::`PPocV_(Xe:L4)%Y4tsu)Z8c-KM;r.*1(+P$5:ZH:i5J+357SAq*\SF[61N'fMO;&FFEu][.SZt,W`NV8\,PBh[[dZ$.*=Z$J,joU#L[]h]H\!-R?#WY;\L]P;;[VKG=>k,Zmj7Z_8I)D1`mg>c*(f/]+[/sSntOM-f$TfSSY@ImMt>cYhsWKkC)*e@q?>ieXT#Q6DDoT+V.]h]Bf]3;ZA;>!A']s'u\fZFg]l7dfPe``Xh_7dO\W/o6+=`U:=fBK#Z*%:T)U=c\ZbG8a@AV)m]HU0519Q$2ckH77n=_kV!`1"qS`sD[K>O6?33p`Aaoj-ZcEU=cX6S2&9,KS>,SPCiqtE1guGX*K`k9El>;I[QYnNdEe@oTBPfjV+"R8]]oqkAg%:n/GI36k=_O8j^QORhDbUITqYIRkW\3O&md^Bc!"EbVK>/pOj^]INr.@GKNB#V"Go"Q4opj'O!E8E8qhf(M8s*_a_OD$F*1C!BHM0bpt`YktRO#>d.CYD,(HtAnb/EE.jq:Z*$/4l'\5"R:OE39te\p;%C;_CElo8U4#gT>'3lQ:+hKDQ?qMOg=D:[L)tU7bKMX=L,/EiV">)f-^LkZdCb&-S]S2Do%p2+b[=q:Ed+dU[j[/Z*0Q"O$mr\sG4`-ak'6-F9ks4>BnNRbogBKV>8dJEL(6B/G&%3B#cfZa#)u&k2:(rZbSDVnJ7C*%:a^_8,#''#12>-lj#n*sW1H]Y@+*r-l-MV.?jafY_CB(t8GE`qtL6)C&*]h6q-BiA,:>E+C_Yc.k`l29%Tiga2mMJV%=nMq?je8se/OlYtAk60qOND7X%Ss23lsM&@V1%nin(;c.-]VHRbZm\R\l7>J5UETU#pWW+pGr:A-n;o,+(/7/*\K'69mU6ee(s*'")KJ"NEg?iG@OE9u$k7uHq.\6B6a[`h_=5U,bQX0DsDY9%127l:7-Y2LPL$C1boe6s"Wb?W^Xd.BoMJ=)AC0d[58ZC)d)k&TXqBl.SSR/L0j%L0=29rg38mV6,Q#G\^nta@6nie-CR!uSF<3(^nV=X7'):E(`3TZ=iEXF9S&@pZ^\q[%b?G1)P%^jaWmRL8XOa"OYQT)+WG'PAgGA5N]?rgqr380+Q?E(E2d&1RV7Ck3\MP=8,=uSg[cf7sUn,]XugAs(J-Fq*/?;H9DV=Eb[sWYc9ui@bj5i0!uiDTQZC&s'qa+_e7]BB>o:'m$OB/\+^gDW\G&X*3XVlkc]f,Hd?`h^NITf4p5nNTCV\.W&+T:9SekMqG5"22o7G69T=@0?hXPE4;'>pagaVo&k#06"f9sML($o'2/jM?EJ(EdPR6=l&+aE@3fp+]H09&=CL#l;(W3$^3`rc:[R2sj`@Vk:<3Foia3se%%a#`172rK@$FjII%DsnH!\QgdgT1@U1ZrF>=bV9:,0WC-VM=;bML!6^.2.<)iRGIlKr0hi\m1T>E"e)kUn=L5L6JPH;="q^4PM';mB,lk$"Q?OdXC&>So=MP/^C.qYkPsjNm]1hDeKuT.9/RVKi#-`VaN5.l/]jIomGP?[JS6F\Z7m]=]<%7O(tneh]q@>"a//=S-2C\67B:kGQ`mm1n)n&9>"'c?R`t@FFq#G"]VV]iNS>pel8DSc22JPJ1)P,ZQceXOMco_!+$fTT7:#J]b2DX(&prM[cFd]'"n^r$kPXE_Q2P[5&R/jk$/4N'(t,BQ`6hrVJn2i,eHR;jo4MSliGP>kdS#bh#tAD`KbG$@X]qq!q`_Vo+58@J2ok%%bak2jIb*X5'+IIC)7f;-n`RWI^af=bElK`I)PRYAE0io]G'$U;b]G'4gCJm>n;U]^a`%O^UH)i=d>RVNjI4rI::^Ie.[O[RX=$W^b0j3Mh7,s(_7GVSSJ1K9)d2X-9Q+O/fR[eE;_T%S1>YjArJ-Y#o_>HpU_1H+T6%IJ_s>hS#>B.0:%-D!qI8#?^"Zl\l2q-=03oPlY>pteM@?t7D,kRTu+p<8n)gV"P(hmS"j_7.]K>3ZZ@TQl14ZbZ"hIWlBQRYF0:gh^7a\4WYkZt=&L;?NN"-,Yt!401u>#>D;9@IB.k$H]L?%RhVsC]hj.JAQJ$')ir&gK(.XrE>('It;PmJQ@!HG)eUc,\W(+Bl:c%Q4=f4X8(RW`9-J5)/&#V"j$ZhGi2ENu67k*g)lk09r5XE>FU6-6+$ZD8ZSm;r!=-Ft2h^WCi;!BGJRMo;q7RCdiNeF?R9ol>3]1'-N1R4^g.XY0+YO%PP-HU9;1s.p`%Yo36?V7'$CASu&*1)pI>(-<;`3E32Ool.'*P`/F"0DeV1_.XRqLg=7giZuOo.D2?AsUCZBIKC'.knZSBW;8Ltl`HUqL;DUk#2QS0Ahs:B&N:.VRroMctdn*T7kQ<1ba?Ise:Znp&QcPJi2Y5*P-K41Uc$W/1i*[LaBr5,,s@K#e.mb(ce:(L/Wnld>eV=K2n1o5Cpal,JpuBqoAh7T0gAm23C8"daY8T[AcnduI^Vo!ktp@2b9\i%&`@+Q_@oZ?-Ws'd[RX=bccc?Y,&'5^B5qRVcm<:hc1_sB>U4W?n/od3f+/V3Y[LMBir**CRibY,'rmsSJX0;1F"qXOhrIPnMfCnJ62l^Z*$f?7R3)jXOsQi.*&8u/Aa%;Q:Pj2GO1dm:"r#4@(9a`0Yr"SH-r(J_JB&t;rIZ>b\@Z3=qac.,:]f0?@2>hp"T'n=pf0gpAHEIf-nbQ]"b&-Ftb_f(_as1>HWm'plkV37+3eDfiJ,'@5"[R/Gr>FuJF7=\\JI)\KQj->f(4eg['3>IITQOPr.pGj^MH#LO&)1U?1"G(ReS]DP"37]eLrjsFQ[hH&)=VY"1lYCL:(hkW\g87N#\n-)MiG#T),T)kj@SQG_!j5`nSEULtj'dKad9lWH?L@Lr"\AIbE6d"^_ZacYL;$'7=P&#FVGLNq4!:MnI_#)X#7D!MeOSB6$1)nZ'f"TJhR6p;,1!JuCPWu9])VZ`'(7'n!GA>?;-P,BT.-pi:oVET!=86I:smVm6gG.LI;E67-[1fM0.=UhJDp7KGF>!,[+XkYIV"dUEk_!M3c?&kGV)?>r4G-=Y9r_+4SXZ`?p4K'enUuOW^iSG;_uYAIc)(+D2JlZ-Nr\5,_7,31#lWiS"kF%m6Hs?*g;VrTE#3:*8;F^l(1@%*pl6)_uR3Nr4#@?VPnCej6Ci,Q4HcXq]1t$5$:R9Eid&qpbCKI2QD$7=i=mI;^r[]\,?7s')+Lko^2TLE:Bu=?K)!BB8n7O5,V,%/J/,2-I>upc\;Xp^9h3j]<$Ij8@:(N@bToVE0KOZ,%AGBY@o6m-`7X0c^U6&%IlRa0?/peNlb>XG+L"2B&e3H''Ra6e?^K"*G[8):5mlk?Fc;`h,sri*4'8/<0B'XNTYc>epL#!lm>.uk9d4tM-NB)273[C-B)@^e`qa/<++=TRCIceuq51tJ:DZ\q%/3+cZ4Ddr9eQRr-f60[#0MKRSeLC."k<>nkI9*(\Z?Z:ON+:,aGD8%`tC!mgL2.e9%Is=r#j@4F`e&C5fs,*5M2T5uBYT+SmJ2#_fW"Vi+^SB4QmjPB(2IPkQ(IW0oC.97EBg0kGLe'&m=hN+'BmX&?-g&1K[klAFFcASFoMUjno5N[XFN%>U.ZP:EnuB*7"d-[EK-5sh;laa:O(P#oG0Sj#+m7o-LC/NHLimVu/Rf-4D`1a8lrVp^".u!MhB`G&Q*&<2!"YW=1E[C=#AJ1>='26RqP_"&a^Q`A$oL/RQ!L-6**"67G`Y$Wpp52WGdrCP'sGi_3)ZDq>c#F0(kNmV/.Gs1A0AfatX\H!NFN)-Ar<,>r!Q2N,bu%Y;'nOHmATu0>rd[Sg`IfTISjm*&70-S740r=bA>0=?HGniXa-Do:=+,T=*bajm`4umud6&/)UB+s^UdK,0gjoB6qUgQBffJRSrG\TS,Ub_`4o(\%m;:9'%U0&X[*EYLcV++PcScbQ-r`4$4P=Cj(obP8W%?p*V6m2Z,bh?WL$7:5H<"*e,mhf=pT^&:GXS.:Lg+bV\dluNu"\/]N6gM?2j]:_V[&rP"[jOfQK[_&=MZ.T4]Jul*ksb75F1$kp`%3%_#+n"`(0qX3e#nXRJD)24X2Nqb[\/MB$Q;\V]LQbV_:?`Q?,NU>H(f@Fa1kH^2#I`7Uoq(Gj5LW>g'Deau%2oKp4;nu7bq/XpW1TZ$]q#7?6_bJ2-$"=G#BQG;E&#_G0[PVqZBPVrB+>"jPCOJX-;;1`.%Lu(*:KkLA?K;q#UqMNk,MFJ-[5obj:=VZjCZ^N5S8>T$4<./dWg&I$/Pn_?dFpSVIE7d-QcdQN"%;p^q1iVX1k@I,MNKU+RTSYi-1Fq]*(!tYE\l)Q+`D-C;+;Bcn@]5[gBJ]JYNJr%pPE\C\R$&;-DQ/T:eSfRL,d^/6;4Rg7\2$^O]u[GC.YUYju).M]PbaNdf8)S2U(ud/\YF?ou>BlL$0AsJ(uOlHER&/SB>WDolr5.5nN,A_!Wt_3BFi[=PL>e<4hXG=i`9[oR[>7gXX2,Rusi>BX4r6DcAR_!PtEJfrArTZ*YZ`ndBC7G#_1N_!Md,#h&O/tTE),:'M?Pb%Wb8.Z4j-U1k/17pFP(7a@]C@1RR(&tbH^c7*cGM\oOU+?#ZJV"1E'a_aG>jIbec[r,-"@3U2=Ns]AVi5-WCF3C@l#b!gaXlK*M4Td;$&TR4n='<9au2D].PX#joX%@cB.3$mAX**F8Rr1!nU/!;k/J=*f70>>l?8ocdlY]FMRk9s[B$?XHL6>-#_EW9Opn9.of(&52VtVWHqsZ]MV&UrbKAG3U\u.+6i:k[jMRJK%k;E?9=mFB-N/BbD=:EBcWa.%)fM2Y0NZf>RN`Vn;6_pd>#\uZ/-[RVJfk?9MN[hU;mO"/Dj?#3)n23P`Nd\>";pR^Tf)\C7.K>sP"X@fV;2?hV/KP6D;+ij3oGhlABk15L';"DBu$B1m,^3)0,"?0+j.ol^i1U9BIt#_G#@AOFpe*gO#+r"@3TPDoB&C4*.GmV9AmcO2Q"7QkEj/UV^;sb6h8!`["XZ''XOF!OJ!c(V<(@:<5?S<+]2odjL[u"@3TC5uFOQ(=l6k<:\a,j8JPABKtQqI9aa8f%T'ISF*Nf#l>nBe"jN1>7h'QSIt;\S&B5b9mVbK@,sZClehP&fJ2nF5DSU7ri3D/Ecm,Mr]5%HJDtIkNmQ/#,u&jQ%!h'I]6hL5#oH%F?9`lK[dl-$#WBSXo`Sd3CRg4B,<][aM+*qtKPp1`F*7l!3.l8L0H4-Vf'&@Df/a1PQA\gat;0hq-K7e'l@\bF#re^2G`[KnT*cdq?P-EM"jfQC*bQldi2lg0256f-4spMPQ)+rU>FEI.b9q\NDr(]?O#9dh<(B/\T9&9:+)TdS?DuIIZ=9;lDLE)J615UOO3*ZZ4;(_IP'AVuG&kh2_$s1Wp%NubiCdGh>gI(_0Z-0su)kVr8p8_\(7]K+?r59_qKA#&_\eu_`O?GhL+R6,chRT6D_US9P"1??En3h;:LPH\HJ-VFR>r&?T?#?,kL(d.=/5Q&=+nVC#@<)Y,<$47&PV*ok8rl^W[F/'_m#VG-72[B$L?\!Ml*T8sLF_2uIJd,8:C;mn,#-j]/Gg'q6Pl/;Y-%N7$/fdEDf*^*\-EAWrnKNGn+5Y-?S5NlE9?d1_1=o@bb)Z.STjeqfs>P]ej$qGlCQhD9eT_Y@`9;dr$PR"@t?lfJD(_@2)?Y:dhEW)U(:6Bl3T9Ycd&*?CN*+sJH#N)J+()3jIa]V\PLnFT_G$B+Sj9!`gUNC7bW:JJXnL,X6XrTFL5+q_9+U[(9QG&XTPNC*T(#!HX^(\cd3HBmA09<.Vc$>fco!R6R%QkQq>1[C1;p"mapQ=n?4ce:b%`X>K[r7?`+MU)rp>M6!,P6`huV)ju^cR8#Og%f,@8BeTn>A@C-Ao=Ffl0eJDS[n,M>ZpX!9&qS-)-]Dek7Q@Jbq`JYP1:R_R'*&Vctj%#0-9V0I"ak5SKqTC.1kCY]!T0b0ngLdUk^J"t8(%1ECFO6]QoQ7eVAc_2#o?_0YDiGi7DI2P[hHdFSmp*>co()@*$Pmu1md+]E(UIX4DY0/gNF/HkL&OCG%h0!;on@_+Fn6B>b8aeUrH00jDqtcm%gXE:ErB>l1HT*`:4=mS@[$:B+h:f7Ek._#UXBDt-s8MSU"8hi1pEPG(kFc'rE?kEn&dV)t=P30(Bfm,m)nGKfm;iDJs;LaN#FF&D+Q`_+Mgn#@18[OmE*gi:k&ZEJjg%`Ra/&_,pmNdZjFIWFn=aSC"#Zg$GBc\C?8&?$H<^fe),+j_]`"GK*MnUAMj/0h_8[-TQB:-9:'Bu+Ee"TYEPo`W9E-J0=23ijarM=ie.VU'F%((;F.57DXh:]6pm"?"fHNg[LdD1g.1Pj'BnTq)AL\`C'.JL9120kFuF",Gm->@dRg#nQc2?/mc$fPp[iEFo>siAO%2>[s%.m$gBF7N$Od36UO4IDI-d=_N`0+6+%"fbpET]8!eBMPlpnG62bpV=QqKgr$dgVM1ib:o('*[!e2Yab3n'!SXc4WI/0[m#7dQUc$?WriQr-S:Tq=8B5=nYNf?N2^Pl!\3dJ$ek+XD-?ER*Q*^=smiku-?W_]3C$#IR#q.JFs0]@PfZEcHuQoX7($b>ZTUW9dCf/dA(LJV/Xl@O"`bfP;2(^;JW)jnHL(kg!F50.<7X&DCI!?Hj%:L6)ZZ+qJ?Ib-2NL^(:EC:0s7Sf0UuKU8TL48]7sn`#03*,CNLZ\nVF5-WIB(ajh+jVNs%5]q3,aNEk;1SM[m@p'AKPan-)fIXE:\c.1hHZnk\J45.Li\J.6s6p<-$-qi4:`TdJT(JXom(WAG!#jPT`2M7D"[Po[;2=q%D?'Y:?(c:_l*_i2M)S*+4.JmT/(:OTX30U-[?Ksm&6HLporIm'2Eb[qtKK!7[?RfeDG4kCXAldhK&AfSiB!;;ND_NU*I;(r4II7SibO]pS]dqf@Q'&1PXEg0XH/A0."TB3JiTQp@n)oZd1JJU[s!GpAOaBHd#JP3n.LqJsH=]4&(2BPY1%-++=Kf_TJd/;8IEn0;`_$rFGsTm1LH]aJSD8nF[_`C6W5AEcP:X^Snmm>ft-$n'\!T;#ukJ_t%hhq(>9t>eYTBeKu^,ZBE*1%ltpk$1[P7o]6S6T,VP?BP,H=k`I*6Cu(`c^\uiY$(o"fAV+_F=G=c$`tcna)9_EQ1(HS#hs4t$khaI:7IDS?Q\lrBZB!71NncE!aWaTZY+P$ihHF`&[&"G5Z:SpoI&L3q@en>`7=Jr3.LpT:dADZ&?0jRsL5lGgM>YopBd$q=1N?%1Y4JrOg@.gO"*+Y#E"n`\ar;H@r*i'8IA?:!YT&k?)*KL!^=H\l2*>/Yc3^\B=hb+h)Hl'j6q>'hl_BT=R@6d,OHJcHS`?dq0DqY=df=bs$kS#SGVq9JLEU][(KDOn'\>K6,Vb`kX%N:FO*UkJ4%ia6PDS&P"V*;""mW8ndHPaOVbA7P.;a6MT.F9jGF@f:n\PJ#$$NPmS6<0XgIq8(dA+QF(CHgpqWgV\XStOr:i!*H#l^Y"VMI]aB]smcCMF\hTS^6bX)2M+F!;2AR_Dp7";3$g7sEiU#:]M`D+?W-D[oG2b?b`1/Im^2f<2#A_3c+,6T`2M7Y,oAnR4KO5N%ib?\#79UhgWaC``uPoJWE%nOKbVi$4%KqYJ)(B3emGu#3$LJT:k*o+4?:%4d?XD!dn`..;\8)n:TrWP9<1&Tp"*%l=hL,t*^]V/r6nI#os88U,h]0YmHOH>L(/MHc2tHNbLoo-(BjE_NGrb5Q*\orPq,mSP;-.ihdrF-6F[2W\_WpW8B+fh(f5]&Jlj:UN/.`GCs/HI[mllJI2`)1@95S5@PMt`K*MmfY--p!Ls;UlP(WVs7_#c'()7R,@A1GBW5$-rO$4b[J*tjn7r_BfP$#5lL(0f<8Nd)n+RNd?DnSc-GDs,pdh`[Ol$_@U14iE-uXj/"lm)KDOn'\?c+ZRl_F4&!E]hN;amVl:sL/e__U,&!MbtJ/11og,/5G*7Wl+Z[1.OP#_LSJ:N)ep8p0PIT!/P>@c=sK(]Z`.Ve-A*m84,l7Y/r^M\_JlL4+E[iec%i\/,(@N&O$IQf]9F%uV`l#bD,KHc'ZG5YKLEKDn*:k(Pt=]nnb5(2.toJrH0\3Bk%RFRqE1OhS[m=f10IdC0r7`.k:X[)h2#PH].E)$;]C:1B[c6UoL0RC9Ep<8qp\T4jP^Yo+g&6k)#[dWO/q=8),11g^TD[/;,Im:=n6P`AUoP*WaE!^&@8tgu)%se-M2."F="mRa$W5!5'C[1As/R-=uI`(AD-:a(9jre.B/uZMq*^&ZC[;26qOdWTPN?(0NqqrDh:k(RNgc9HR#c\uQo3&%l>5c!^f`b)hX8n^>)@iqcCB`3pE_q8A#T)"JUr3E"T*^Q!61Xd?)*`!YQVugXq?mgRaIki#0#@)Kn46;HG&"0`!qj#I4FHpc;&PO'bBEIP$%9QHi?ihHn@j>In8_*s'r\n.T`2M7/u?cG,%s77LU4Okh#N^$d@[QL!A[7_]s,p6]%=HE0KJ0R0,&ta!J+pop6ZJ?T3S=riZ:l98D[RkMEm*56&8g7"h`[l1Q8ki9nF&)*`!YpOVm;l#3aH4eUPOC^/&*b'#-YN>aMQg_7P;B1ea:S[gjNAd^-fSMFmln"%5ZE$7B8Yi7stJ6L[Tqri.5M%b]VBL\a=4aP1\0l95T-&925^0S`n_K*)/Zo^=.?M%"mU_>\VEM>1Tt_TT'S>D&7_4*I]j\(\E=1[,U\LZeE$2K;be]:f.d_b,E2!WiQ8(f4J]8J"!oj+7kc@U^Oh"!O&=f0]EnFGYR"j2R+M1OJi^R5oPFKQA!lq1^XFpslEHGqg5Jr\>79ZZg=)B$>"n`?7mH3-!<\J^CSeV$5s,hrid21jVG!KNi8U1S,`@hsc_(qNAdG@(g`QNc!m2e@K\jKhNiZhR+:o;[&rhl.)j-S#s!%ZDc]a"ALPbc[Y`:@1JpI@0PpL3NVk>l(Eb>*n6<)SRn6IA(id)lB%Y]_UqJZ^R"97%of2H$/P\HO`9m-2ShJ*;gINL)8;'L8q36IhEd&cCP#TM#'YQ(ZSSm`Ra[AYCW6&]@A#VuQI*[f0Hpc__6spZM:X>(dr/cP?[KPkK3UP1#(Jh!EY)pF0K(8l(`JYFN3PS%)0Du'LN>t-PQ\BIl\A%s&*]_[!o_368Amdl385S%S+Me)0^"]!'B"2jZH2uV>R,ELF*o4DIIoVd@e6d5mJ)(BSd9dIBY*"iTh1#Hc>*`G>k1?ZJtmh$CL:?fi'irVQ?b[[$q1fACPY(\7:hJ0u9V'aIDoa[,lJ,MYV86NR?7,9f)WEn(LLX2!Ve+ec`:nqI8P0E(+pgtZ/K9k=RZ?U@Fb4i`R',?1;n^n;b)]$#mWMD&OO&;DbG%1WjT#ft6VkXiAZJbi"LlE;/c(A\t>]>26K6//kefBIC)gWXg5QasA@jbafIZEs?b;N%4IZ=W!H"iOh.]GE/)8A7Pl$5_$Z2CbW$hlAI1/^%r?V^Af8X_crFK"c]f\F6?1KU\f@dWdC[*S%o:/$hNaLhR$0j/okj+*M#g^S=H[6`@)6OiHCP:+OjR5=;It*Pr-^D%R:k-SQrH0@?7=U:GfZV0RgmBf_JUg7c\Yf@X(Xo.+GF.#uAJ]Cc%HYKdTYD_+%RtbEjW*5l\_4Ri9IIme8m>I*WZ(jf&mcR+=2'pVl260bUC"!.]rRoK[6=siURU'9-n#6/G_s75rmTmG*[WfheUX;nbDqJ;&"a(Pp\7<_J=:"RYS6:^i29OIp:N=L6:I"OB,h&="5\S4OZ+(gHEoc^uBMF/drLi^Gmb$L^K!k^F00--+(LHgdp^,_gnj7X`q7mX9f-#>[*ac!QkO:Sjl#[^o>aRO"3nTkNblXK-4)b&Z)i*US:"\>&gMZrnY$\dVi(&)jH!%BPYtYT0%DN8Qfd7[eea@%GT6uVG3URGXsWLSkt#rIH10H#F?0\B*3ZQXV'(gMKbS`57Lp*5,m*\Za\?`OPl7Y/r^M\_*kqA-hS_^nj:\*%]:CiM)2f<_\Y0>j,Iqre6L(57kD@lTi/eJ[>c8WiVK)/-WrVQ?,JjW)sk7+1&*T!Z>dIqKOQ:e"0]+J=$*(HQB,J<$P;5!oOKDOn'\=ig&l07G`e9/5gSPLrQo0hB:SL&`SYV1[mLMgE);$Upho+]D\#X\Kc'$H3ds*+]X`+*QT;hbhUepDf'NS4QQ4L^2o7HFpBc9,Mmk(5icoV.e-4u@Iu@jC*lRJ<(k&)9'rn44as#kh/?$=#U/ItFdl.pP/inMGhgb)X&=o!XP*(k]B])/Hh2e5YZY.SEloG@#?ZJtmh$B@thkHhh:bKVD_4qu2A?]7>jsG$%lS#JWjU1S73+;HMl!/N_jIlL\ak="5a^%b2'C_au)F.ME?NT>#'a0T_3J2rE]93TqQQ4L^2o9/!pB_S&FsWjAKE_YbqYORokpL@(`f'h.ARu$B2mAK8%.j5`RJ>?d`^Z;Nj(&YbDju.DhYVtH@jO;*:94NT(jZ9[cgSUHQ5bILrfVp1lUJCirhcNgJVXk$,L=Z+USFQnaVZ]-X4Q\#c(,679-1Rehp3,(H,i/'Z(V*)%^d%O.uUe>^(P\G_hJZ_-;ZVc00,uGDM0P+Dgl"6F-Sl81\10Cqq5W;A;h?'"\tXK_(&%o]_MGLhfHk/3tTp!eqo7(l6oC4h^q@!Te62`)7p",1BAc7n;jj95_p".B&jmqNgA;i2?XfJL4Fa4"T%\2Y9a,_52l&Gi<[hZ8RXW(PP",#G@huA3/Z_7;\KDOn'\?c)L(DjF+hc3q#"Q2q&T?tjqX+Nt$8SqSEhGKp5&5[j\iV'BX6.F"<]8:f/nn`PtH9/ZB=T?oQjSBf:)M\*HqWep,ZMs:EZ,<&UY7YpGHtk,i)<5"P03u.WIX?2SI1YY6qL4\"`0CB_j&aAMtF9pq4OJ6npon&^t$8RDr.uI(5[\GJHHQ.&rG&cdsLiU74uD?SmFpJ*-%QiP*;%7of&Dd$tl8Y>S,Cl2o9/!pZ./EI`0(+?j,>i:S4Ye8oF4>]D_m/;GpW`_?pa+(U%,f;1+PX62e3f^:o'?W);V']=gmg,8-!WD!dI!!/mcaf`Y_rHJ#fTL#5%B1l;HQ34aIeY(HX`,CdJ$-jYE;/"Y-TG=BL#Y^/M?@P3;;s8"QO_.SG%^apbp=q;a[!).&`qr7S=N]"/D:Gi,R.#P:4_#7UBNj2T-#plBQMqWgV\T`44u\dq%#JCR+cE:.oPD9=',.aOsOG*4,;3-!epaa^pn(:Jd('BF*8@h/Z?F%KWF>j<1\6)XX3=lR%"?uNK\GIfsuq<(.]_3cRt0j-$JA=iT`J\H3OT'?Rlh2H*88PaIf6:LZe)9/k2h'DTG::Qh$B@q?\LhOGgR]g%o:(*_WWW]4'/Ohl+C9SiZe6rK^tTr@'fG)DP_$^4"eD44IUrJsH>PM!h;s^N=8rWiN/JNZFTIFXhK!e7'*]C*o-P'`,e[FcO^ES%+LXlC45Sc'V'DZiN2jE!eSWRaMPEoQTl%8N^UM"*/F&R/K>s#(]j-VgS9t6-cc+m4mfuH7B9oY#ir@$AH>gR7U(Gn0H;q#Zgd0h<*dT'."8_7>F^^Mi4pIZM*_BqrtCtK*D_aq&hn:A=fHS%IDueXL+4%UUc3[15"iOBueopTPV6%lRu?NqX^18DKMto3Il.HZG+'0):nRp_ZoZ>(Vh0,HhAlMYeoSYUP9#I_5-%o]Y1uOmb[!"bc'(WdA'2,'@.CI$1\TB*]ROm6:-9%g!5LHF?87RF6DF!5JDPI1P;1$l/2MaX>O/_p",12V8$I2&@Y0=DP2:r8_kR8i=gXP]qI3F56]fU#laPWKaZZTbsh8k!BR(9_hJ=-:D-![\jgip.,\P8d4XMV)c#QS+tTgJor[8RJ)>]"L(?Li`kclDf@8:Y))R.sO"iW/++Fhhc/7-VIJ5LL9nj-!X=Q#KP"i#CrH0@;l7^V;K*lfJK`hR%n:jkd#;6UKSNm+pMpYd%It=Ph42!d>_hkKc*>R8=eYu\d"`jPNUEqlV.&_dkbou>2J,XN2+pX_p5CMf2X+8Oci\RK.4#RUd6Id\tV[o"(;GN5c,HZC.DOp17A&8pJX"XfgTAI7/:Rq4ZHgcCYq<+6^s8MmiS'2Q@W[jDhJ*64.7unW-*ZF>(l,cWGOZ,#d*WS7%WuT-s7/_6Qg7c9o-`GA<+[E*eb@n&U^W"12X:DHgd0m"UX.>][Q=-Q(Y*5O$IJEg=N]"e=,tiWBf++0%b8'E86#AR-7?GR(#c!GNIC!@7oCAZVXdq1`>5RH5bo7uX'XV?5g[-?_-V.'2$+GE=:!@UQ4aW\V+`A1H?T5jhoJ\0P&0AmSc+Jo%'A(]?i/;aDfUe*c`8NTqF&7?(,[tb(QS.@1#*3TFlI?Bg!$P'29ljpk,+jI!7X)6t29sBC8P.$k;560#_9PflFAK;Sqf_/U_(M\$DM3B$0;r3%BP>QF^&/en"nhWhrVIbf4rMdOIHXG(:77j*l(";!>>Tee@\TX>YP2KIfk%(PY&,3UKJKgb"]Og\eB(Wac'#G13aqr20/a$q14cr#-0I]S:k.:,GL><@J,j7uDiGk-m$k^\E'aF+(+r]S^6f0`5L@aVqXs.oABYD1?U1[B^-u>r7Co)r3ih4,LT5*)*L-Y+8.,g;GO:T^rE4&]QFMkLC1g_hTS:aIDRb.EG0;f:dEs0gUA3rl0[EmOX$sY>@G;Y'B@je&l!mfVG3Tg]la.s#<=%a_-MZp"4sY\b>!>%$.N<@_PQl@*XCcEQTc2ohb9V$0n._,R7tW0OfWOsr<7?l-aO0*".eLshgWaChFsUAQC!m2IIk^VJ,mHI%e0-34(aFPX*)L][l;WEDt`E_SnI9e-]B"j9uJEP;6)j)nA(DgUR6JQjLa,,Sf$o8Wq@/Ho&-?c'06e[hHM*^cGOG1lgN.CUGhF**_W""B]KJAJap9;Fi=0GrX"5pme[$W&=2IH-NO7T4Dmh_U;#;(nFJtgm&,5b!K?:GuV^76:3Q(uuWMpqWF<^`uO%sV0ft>u]+5INpIe9m8-dlful\;@K:b>?enes<*ic]sZX=U"Q6\0gV!]32%9rVQ3uJhf52eB#\d?_j(p,NFO>`;`Vq::'Zae?BV2Pg4L\0Qh[Sibgk>$DYH>kd-Q'J+7Muk".%h7VO61+%P*oIud:55s9dX5!rDC^8j9g;FCQgFO\10':BLc']@JS3;4Bi.(jE5s]?PL!\2^J:MY"`^(X'/:51\O$=trSkCBn^`h$.[qp&?"jWZ##KE\$3=pQpoKRbMpCcQM463.u!q_lm@::=Tfad;u[;4($HbC"U,&3qXjrS[TS_Z6\6JPF`ch-f:fRIoZj!hGI\n*rl`N5nDHT@@:=;$24*%X-m6j_^nDGfjfRK(bXHe[3T1(b]Q8jZ%f48L1'*lk#;+;+T`IuPC?<6,B9/%!`30UjenXaTg:+$_];i`!UY^ZPX.8sVZ$?GLR#Ukn83#hSODto^uSoLUcD[-d95@aQ^YJ0oI]PO9IPq*-D[K7?+YD?2`I)`R3Dc"&-P91"@3S%5nF/b&-P91"@3S%5nF/b&-P91"@3S%5nF/b&-P91"@3S%5nF/b&-P91"@3S%5nF/b&-P91"@3S%5nF/b&-P91"@3S%5nF/b&-P91"@3S%5nF/b&-P91"@3S%5nF/b&-P91"@3S%5nF/b&-P91"@3S%5nF/b&-P91"@3S%5nF/b&-P91"@3S%5nF/b&-P91"@3S%5nF/b&-P91"@3S%5nF/b&-P91"@3S%5nF/b&-P91"@3S%5nF/b&-P91"@3S%5nF/b&-P91"@:bdrr[^3AS(~> +endstream +endobj +7 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 5 0 R +/Annots 8 0 R +>> +endobj +8 0 obj +[ +9 0 R +10 0 R +12 0 R +14 0 R +16 0 R +18 0 R +20 0 R +22 0 R +24 0 R +26 0 R +28 0 R +] +endobj +9 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 360.934 317.602 472.804 306.602 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A << /URI (http://www.breach.com) +/S /URI >> +/H /I +>> +endobj +10 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 120.0 231.744 174.384 220.744 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 11 0 R +/H /I +>> +endobj +12 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 216.344 196.815 205.344 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 13 0 R +/H /I +>> +endobj +14 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 200.944 292.141 189.944 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 15 0 R +/H /I +>> +endobj +16 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 185.544 290.931 174.544 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 17 0 R +/H /I +>> +endobj +18 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 170.144 189.5 159.144 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 19 0 R +/H /I +>> +endobj +20 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 154.744 228.286 143.744 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 21 0 R +/H /I +>> +endobj +22 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 139.344 220.333 128.344 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 23 0 R +/H /I +>> +endobj +24 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 123.944 142.453 112.944 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 25 0 R +/H /I +>> +endobj +26 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 108.544 139.384 97.544 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 27 0 R +/H /I +>> +endobj +28 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 120.0 93.144 240.164 82.144 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 29 0 R +/H /I +>> +endobj +30 0 obj +<< /Length 1915 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gb"0WcZ@f"'F4+hIt`s*@3%qJr8ZEpe*0WkAeT'O4h)W52dfKmB/fj=D$"KG@B=]$gC!ct0)^l(KAK;YMu86V3>l(,EJIGY30X/g3/[f[8G/]P*)uB\,^)O.F=&O$O0d^b7K/[3^X&HXHq)o,$U!jI\J6!'6WUmJ&-P914@r#\XiasHM:-J.:M97!=tkT]GJ/F@*6MO9;fGY5jQs<[MG;!^bR0IIoc#W,,?hd^=t'`/+D;'C8e5KU8I<8TNVBjDA%!hLjYA8_R8nn2"lu74W4I8!2UMQMSb'[QgG+54'RYtmB5&N;O?F;H'77Igk_>f[Sq(<7d>fHa:Ggso:IcSq*:;.CjGLP`&]GngsN1rGcLKV!+&-P91CpR27oN61qTe;2tU0NPV\.e2(g9/N0UH1/kl8)NV"V:gQ@ppm'#KEi>_kum/BC0`*(@SRuRYe3'9[*.6(9JY]5nLE0j:L%Pg\3#W=t[DO:$CmF/Qt7BJfo:>CfRdf<69A!1nFGC-"C5W/0ap]McL@?+:'"lHPNTCW^dhJ`G1Y"@l`kdg;dm.O1-MA+:*Q`"+0-VcIICA0&L$494:HfN9_-Z'EesM_:)dBV+8OimZX!^qC8?!,^HZZb3(&"7p?Z.&-P;g%4_VR&,+Xo`DSfF=`ILg7G1g!!ahS>U/6@_#V&u>&S"ien\K\A>p8fM+\$2/G8,G!:LR*;5S+'Z,SU'[J$9eNH!5EAmi^$`>8.&K"@;NI+WWBqF+*K,hpOS^=qF!WUlP`-SFTI/GEd%Z-LpaZr$9$:oC-'tq$hW[3G;-$.i[!E8d61?;TX'#1kd^:"9eQQSX4_2u0Q5!oeH"_&AI9)cQU+h*?#hkDtR5#A%9^.f/*kLnsqb*=EFSU!.\=nWj7!BT"&7Jfk?5@AVme3>+"Yo;#V,`[>-].Re]k71fMc&-Q?G.=>X%n;226i.I-C;Eg?2d:_Jq`K[VCXWI[3&H!+da8#.4O86pQKF_XWcdF'poOOOd:4''2lN]]e"RRa#,Z`1jN0F0*F<5hiYs-C+V1TlrJmb(MP%]6K1Q+EX0Yu"MIZqrA9KU!s'YP>udIKR7"@5]5WuctWEb(lC7q5DDOYc$'%$V&L$3CKbi+]E\dZ%&1A:^YK/SJ%.Kj8_:1j1=]4b6$f!'q/Y%JEEYI]2o,S!6*.=$i4D3SgJ,$l284"@;NZfIL`a9PK!cZF5,lfr&B2IC%cHF''+]&-Ti]&hg=PR=IDrVZp&l-7!sA@ccl&sK59k@lEkoLUS@":0V;pWTN\f%Mr6oBBks'M6pTRTN8VW@SA]#_LX',\fqCZ)>!.RZ(c@_W__N#)e'5Jfo:`GrUc4:/JLfg0%?=eAbUtC_-_8&:>uL.&HA[K3[;pi68:9lWX*rHk+ms +endstream +endobj +31 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 30 0 R +/Annots 32 0 R +>> +endobj +32 0 obj +[ +33 0 R +35 0 R +37 0 R +39 0 R +41 0 R +43 0 R +45 0 R +47 0 R +49 0 R +51 0 R +53 0 R +55 0 R +57 0 R +59 0 R +61 0 R +63 0 R +65 0 R +67 0 R +69 0 R +71 0 R +73 0 R +75 0 R +77 0 R +79 0 R +81 0 R +83 0 R +85 0 R +87 0 R +89 0 R +91 0 R +93 0 R +95 0 R +97 0 R +99 0 R +101 0 R +103 0 R +105 0 R +107 0 R +109 0 R +111 0 R +113 0 R +115 0 R +] +endobj +33 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 717.25 139.373 706.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 34 0 R +/H /I +>> +endobj +35 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 701.85 182.779 690.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 36 0 R +/H /I +>> +endobj +37 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 120.0 686.45 169.5 675.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 38 0 R +/H /I +>> +endobj +39 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 120.0 671.05 229.681 660.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 40 0 R +/H /I +>> +endobj +41 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 655.65 155.4 644.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 42 0 R +/H /I +>> +endobj +43 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 640.25 228.0 629.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 44 0 R +/H /I +>> +endobj +45 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 624.85 188.4 613.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 46 0 R +/H /I +>> +endobj +47 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 609.45 168.6 598.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 48 0 R +/H /I +>> +endobj +49 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 594.05 175.2 583.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 50 0 R +/H /I +>> +endobj +51 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 578.65 214.8 567.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 52 0 R +/H /I +>> +endobj +53 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 563.25 221.4 552.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 54 0 R +/H /I +>> +endobj +55 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 547.85 201.6 536.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 56 0 R +/H /I +>> +endobj +57 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 532.45 261.0 521.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 58 0 R +/H /I +>> +endobj +59 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 517.05 234.6 506.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 60 0 R +/H /I +>> +endobj +61 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 501.65 195.0 490.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 62 0 R +/H /I +>> +endobj +63 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 486.25 370.285 475.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 64 0 R +/H /I +>> +endobj +65 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 470.85 175.2 459.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 66 0 R +/H /I +>> +endobj +67 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 455.45 234.6 444.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 68 0 R +/H /I +>> +endobj +69 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 440.05 221.4 429.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 70 0 R +/H /I +>> +endobj +71 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 424.65 195.0 413.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 72 0 R +/H /I +>> +endobj +73 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 409.25 162.0 398.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 74 0 R +/H /I +>> +endobj +75 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 393.85 168.6 382.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 76 0 R +/H /I +>> +endobj +77 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 378.45 201.6 367.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 78 0 R +/H /I +>> +endobj +79 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 363.05 201.6 352.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 80 0 R +/H /I +>> +endobj +81 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 347.65 188.4 336.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 82 0 R +/H /I +>> +endobj +83 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 332.25 188.4 321.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 84 0 R +/H /I +>> +endobj +85 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 316.85 155.4 305.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 86 0 R +/H /I +>> +endobj +87 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 301.45 181.8 290.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 88 0 R +/H /I +>> +endobj +89 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 286.05 221.4 275.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 90 0 R +/H /I +>> +endobj +91 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 270.65 221.4 259.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 92 0 R +/H /I +>> +endobj +93 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 255.25 228.0 244.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 94 0 R +/H /I +>> +endobj +95 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 239.85 241.2 228.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 96 0 R +/H /I +>> +endobj +97 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 224.45 228.0 213.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 98 0 R +/H /I +>> +endobj +99 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 209.05 221.4 198.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 100 0 R +/H /I +>> +endobj +101 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 193.65 267.6 182.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 102 0 R +/H /I +>> +endobj +103 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 178.25 274.2 167.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 104 0 R +/H /I +>> +endobj +105 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 162.85 228.0 151.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 106 0 R +/H /I +>> +endobj +107 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 147.45 267.6 136.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 108 0 R +/H /I +>> +endobj +109 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 132.05 247.8 121.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 110 0 R +/H /I +>> +endobj +111 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 116.65 287.4 105.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 112 0 R +/H /I +>> +endobj +113 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 101.25 234.6 90.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 114 0 R +/H /I +>> +endobj +115 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 85.85 142.2 74.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 116 0 R +/H /I +>> +endobj +117 0 obj +<< /Length 1897 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gb"0W9iL%B(^KOlT-?cg9X`D'Gr^IGAQOs&_6)C5Mdi>jW)@"):6".['2Uc)h8E"Of]'Z9b7Ecmks"as:-V9"DZ"Yl=H6l)/&#g2CYE_YP(#Dli23]',d9Go=n/omcX't=URNdeSq!$ICd"5JjhCDk(&sk369JN4^7768?>o::T.%*1RXT5a"@3THAbs>W/osrGrifc8Nu%*,HLD'nB%hPQcDS!ofi%;6O%Kj"4pZ`_BF&[),V&E,oBefdUI\]E^<>)EHW%HR@!]@L;ZMCl#j0">XUG;ug#@LuTX1(f5)^u@)`.dB#_F.L[FT]mgQ&`!pW(Bl\Lr:I`GHcU[242KO/5N^f5eSH?!ZfppV@!;"W,rMC3DiR"CH:OAb=B4mU/$mX^uRdSh9))%orh`04N9rJ05-3gj86eY,@:]3&9mEjL\+^ZfukE^.G>/A.%u6blJ*%i(%0m]alUEHf>a",ie4Pi@HF)+s@$$bb1Y^+:*R,Sol5Spho%uG-JV_N$]:=R/R)fd\,!?+:*SfK!iJW!,cP/UP+%QHS:Q.<'CC-a?#_F0)rbO2@/Jkk-)A8uIoM#Ie7#9p5)nB.Q(Ja%),*OQ&\F8+2n+bD2_1Ed8Jj5_:r2GY5!E\I8<>j1f9Q!c8,&@@9#(ds')B1<#YE$F@L!+5AR-.hum6IU[Vq5Lo;54:\&-V==JBQFcH"@E>D)+'Y2F#,;C8`6\K&GtULNkR=\q(a'*9i1%%ue[AafS5FDkIm-J:UG&,2QDDpjgAqU#UP8l&+:*EQk(9]*Y6]3i;sa_4kdY!n%N>2B_OsbY+:*SW]47ta-B;iha["@;N%0Xonc?.Fq>=mruI:0>))F+mq5d+CVq"Mp/=>,gZseO-W6^#Le!rH&7@uGDZFOCCM1H#_F14B&mo/ll?u;cMHXLZp69#B]pQEJfpFnX[o6mlcmKpnJU(8?S=oXijkji\&N3XC<[#j.P57)(2aBu!]C8(]sXIG5[f$Odq1#_F0)mMKa$\`^"/Pb[qdq;Y@Bob)n3%>#].Jd/M]._AB^l>0Aoqtu1.G8jb;RJJ4ioLC/73);i'@nW_&Zpc,]d5@S$Gbo\C5f]HaaBj#)s]-5nJF%a9a=@LH);Zi]''$m[q]>(c5n;"@3US1"OHfa*1OY`C]t%,j`RhIWuo'mJ(a*Rg/ETC4g*u"@3TH_5-RVlJq(bj+EQbE-U5u.Z_g]Ka%u-"@3US!NICYUb^&F:jj=o,hk.4)eHX7u#_F2oJk%'k1lEoa`:?-N$)9'LGkk&PUrG-UMgB+@IqF(g]#S7-T?b)bk5TOaCos>f2m=TX#7aYAlfa$W"Y$o[>J05-sWl&4;,4'[5:CBr\ma7HF>62.T$Q*qt66G&=FErglcafMgPH+l<@lo!ge@CpkcqGrEsk:5Pn$lV)2Jfk?]R0uE/QYg0dpspS=[,GTBMS8?Y=Y9&fFqFEaZ%\H6la$%nUD9h:b*ca<_:/E7EkgNc-@Ing8S7;CI4IB2h7K>sc0di5'Zj"9aSAr +endstream +endobj +118 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 117 0 R +/Annots 119 0 R +>> +endobj +119 0 obj +[ +120 0 R +122 0 R +124 0 R +126 0 R +128 0 R +130 0 R +132 0 R +134 0 R +136 0 R +138 0 R +140 0 R +142 0 R +144 0 R +146 0 R +148 0 R +150 0 R +152 0 R +154 0 R +156 0 R +158 0 R +160 0 R +162 0 R +164 0 R +166 0 R +168 0 R +170 0 R +172 0 R +174 0 R +176 0 R +178 0 R +180 0 R +182 0 R +184 0 R +186 0 R +188 0 R +190 0 R +192 0 R +194 0 R +196 0 R +198 0 R +200 0 R +202 0 R +] +endobj +120 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 717.25 214.8 706.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 121 0 R +/H /I +>> +endobj +122 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 701.85 181.8 690.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 123 0 R +/H /I +>> +endobj +124 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 686.45 208.2 675.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 125 0 R +/H /I +>> +endobj +126 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 671.05 214.8 660.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 127 0 R +/H /I +>> +endobj +128 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 655.65 251.144 644.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 129 0 R +/H /I +>> +endobj +130 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 640.25 247.8 629.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 131 0 R +/H /I +>> +endobj +132 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 624.85 214.8 613.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 133 0 R +/H /I +>> +endobj +134 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 609.45 155.4 598.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 135 0 R +/H /I +>> +endobj +136 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 594.05 175.2 583.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 137 0 R +/H /I +>> +endobj +138 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 578.65 208.2 567.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 139 0 R +/H /I +>> +endobj +140 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 563.25 214.8 552.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 141 0 R +/H /I +>> +endobj +142 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 547.85 168.6 536.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 143 0 R +/H /I +>> +endobj +144 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 120.0 532.45 200.355 521.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 145 0 R +/H /I +>> +endobj +146 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 517.05 198.641 506.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 147 0 R +/H /I +>> +endobj +148 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 501.65 186.442 490.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 149 0 R +/H /I +>> +endobj +150 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 486.25 205.362 475.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 151 0 R +/H /I +>> +endobj +152 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 470.85 193.163 459.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 153 0 R +/H /I +>> +endobj +154 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 455.45 161.692 444.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 155 0 R +/H /I +>> +endobj +156 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 120.0 440.05 162.152 429.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 157 0 R +/H /I +>> +endobj +158 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 424.65 122.4 413.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 159 0 R +/H /I +>> +endobj +160 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 409.25 214.8 398.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 161 0 R +/H /I +>> +endobj +162 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 393.85 162.0 382.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 163 0 R +/H /I +>> +endobj +164 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 378.45 148.8 367.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 165 0 R +/H /I +>> +endobj +166 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 363.05 188.4 352.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 167 0 R +/H /I +>> +endobj +168 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 347.65 155.4 336.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 169 0 R +/H /I +>> +endobj +170 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 332.25 195.0 321.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 171 0 R +/H /I +>> +endobj +172 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 316.85 155.4 305.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 173 0 R +/H /I +>> +endobj +174 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 301.45 115.8 290.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 175 0 R +/H /I +>> +endobj +176 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 286.05 129.0 275.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 177 0 R +/H /I +>> +endobj +178 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 270.65 221.4 259.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 179 0 R +/H /I +>> +endobj +180 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 255.25 168.6 244.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 181 0 R +/H /I +>> +endobj +182 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 239.85 168.6 228.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 183 0 R +/H /I +>> +endobj +184 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 224.45 188.4 213.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 185 0 R +/H /I +>> +endobj +186 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 209.05 115.8 198.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 187 0 R +/H /I +>> +endobj +188 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 193.65 201.6 182.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 189 0 R +/H /I +>> +endobj +190 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 178.25 168.6 167.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 191 0 R +/H /I +>> +endobj +192 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 162.85 201.6 151.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 193 0 R +/H /I +>> +endobj +194 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 147.45 175.2 136.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 195 0 R +/H /I +>> +endobj +196 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 132.05 247.8 121.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 197 0 R +/H /I +>> +endobj +198 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 116.65 241.2 105.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 199 0 R +/H /I +>> +endobj +200 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 101.25 280.8 90.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 201 0 R +/H /I +>> +endobj +202 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 85.85 155.4 74.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 203 0 R +/H /I +>> +endobj +204 0 obj +<< /Length 1655 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gb"0Wc#9@H(ru0YrsFdU6g;Ad@ua;HS%+H;"1YD1XfU((=]K4GC=GE=^Ft&X14[Q+'WoF4YC-17Gn;ceq:Rk4>j%mNho:]>\\cI\7`+s\nf1MS4=?/H^F9c,8h)4ge+rga_b-hflRYhEMq]cF=""$A-k=!+^D)!(;6P)FSF:j_'=-#IqiHa6sqd1ehO+WM1#Sh`6!eA>Uqe$M7N6GIs\M^AKl#f#MJ.Qk%[IrmhZca1%he@ph+#I8"u+GAq$+cBJ_Nm-qY_b+S;qKe=h`FQ.+<\U64eJ?C0KFl"%9FBmLh9eSf']4=#D\T9P=u:O2+bXJo,HQLBYR89?"*>>[2bET#9P83f'p%\"(/4d^&AhAB8g#US<&7P*gC%V1g#<72IL(k/!C@(UHu6?k+5Yo5P_^%\j%gJspF[\QNl7AGVL6?j7c'NU?42N[)_^ItH+f:r1hX[V9*&41&Cj92L9.:8rDT%kUcSXo=D[7)kO+b[(D;FI'I+oQ#NI$Mu<++IHCZtSq?63o5pK9FGWc0ftAAF"@.Y&hojV:_LKJ.P%lW`0S%\^M[*-AtQA567TXC=2MoKFh>(+aG>kBT\9:\k*[J?KCF!]su>U3hP_D3J^*;!?m-"\"9VFoi)7(;dN[(o>bG.NTId!3\#ohBGr"Hn6B#R0Jkl=LR#CHVX=>RV+S-a1B8SOn.h.]ptG-6?W-O+&\E#kMrk%,#jkc2rSU3K[*QDg]=/,Kat9%`#U+kR_Ec%0\rTuXa]Ie_P0mp#U+k67jG=[SWU%oA\1+;8S?4Q0+d%@&?HRM1]\.S#Z$^8OY!!mLK*O.I]#Q5R)Kh8!/(p#;l**Zat3mS<4SR-5'o3qlZEu&*C:%j\&L_5-iJ(p`CoKma_KMpA\"(@Me2rU#\!1tLc^g;Mos9YLSU:be(-$e]12j&$8!/YKFl!.i1M>/?=R'RWm?qoZd,;M6O4k5ei4rJ[SIjFn![?i3pj=jU/GgT"@*594B8C0@I0H0kta?G:SuUJo;Z2pd%\?D#U-h\%SF#\1j24PPH=)Zd6>[r6Al$Y+b]=d==./r3g37W`_MMAOtDkSmnPXEd%\?D#U-h\%SAK@0Qq3p/=RrD[M0*K]uZq!6O4igYJie9.Ullia?E;PG +endstream +endobj +205 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 204 0 R +/Annots 206 0 R +>> +endobj +206 0 obj +[ +207 0 R +209 0 R +211 0 R +213 0 R +215 0 R +217 0 R +219 0 R +221 0 R +223 0 R +225 0 R +227 0 R +229 0 R +231 0 R +233 0 R +235 0 R +237 0 R +239 0 R +241 0 R +243 0 R +245 0 R +247 0 R +249 0 R +251 0 R +253 0 R +255 0 R +257 0 R +259 0 R +261 0 R +263 0 R +265 0 R +267 0 R +269 0 R +271 0 R +273 0 R +275 0 R +277 0 R +279 0 R +281 0 R +283 0 R +285 0 R +287 0 R +289 0 R +] +endobj +207 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 717.25 175.2 706.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 208 0 R +/H /I +>> +endobj +209 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 701.85 168.6 690.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 210 0 R +/H /I +>> +endobj +211 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 686.45 168.6 675.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 212 0 R +/H /I +>> +endobj +213 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 671.05 168.6 660.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 214 0 R +/H /I +>> +endobj +215 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 655.65 168.6 644.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 216 0 R +/H /I +>> +endobj +217 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 640.25 208.2 629.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 218 0 R +/H /I +>> +endobj +219 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 624.85 247.8 613.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 220 0 R +/H /I +>> +endobj +221 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 609.45 274.2 598.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 222 0 R +/H /I +>> +endobj +223 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 594.05 201.6 583.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 224 0 R +/H /I +>> +endobj +225 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 578.65 175.2 567.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 226 0 R +/H /I +>> +endobj +227 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 563.25 195.0 552.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 228 0 R +/H /I +>> +endobj +229 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 547.85 234.6 536.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 230 0 R +/H /I +>> +endobj +231 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 532.45 201.6 521.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 232 0 R +/H /I +>> +endobj +233 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 517.05 195.0 506.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 234 0 R +/H /I +>> +endobj +235 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 501.65 234.6 490.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 236 0 R +/H /I +>> +endobj +237 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 486.25 175.2 475.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 238 0 R +/H /I +>> +endobj +239 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 470.85 188.4 459.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 240 0 R +/H /I +>> +endobj +241 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 455.45 201.6 444.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 242 0 R +/H /I +>> +endobj +243 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 440.05 168.6 429.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 244 0 R +/H /I +>> +endobj +245 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 424.65 195.0 413.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 246 0 R +/H /I +>> +endobj +247 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 409.25 181.8 398.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 248 0 R +/H /I +>> +endobj +249 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 393.85 247.8 382.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 250 0 R +/H /I +>> +endobj +251 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 378.45 234.6 367.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 252 0 R +/H /I +>> +endobj +253 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 363.05 201.6 352.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 254 0 R +/H /I +>> +endobj +255 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 347.65 241.2 336.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 256 0 R +/H /I +>> +endobj +257 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 332.25 208.2 321.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 258 0 R +/H /I +>> +endobj +259 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 316.85 195.0 305.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 260 0 R +/H /I +>> +endobj +261 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 301.45 122.4 290.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 262 0 R +/H /I +>> +endobj +263 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 286.05 195.0 275.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 264 0 R +/H /I +>> +endobj +265 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 270.65 195.0 259.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 266 0 R +/H /I +>> +endobj +267 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 255.25 162.0 244.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 268 0 R +/H /I +>> +endobj +269 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 239.85 201.6 228.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 270 0 R +/H /I +>> +endobj +271 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 224.45 168.6 213.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 272 0 R +/H /I +>> +endobj +273 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 209.05 162.0 198.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 274 0 R +/H /I +>> +endobj +275 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 193.65 195.0 182.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 276 0 R +/H /I +>> +endobj +277 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 178.25 168.6 167.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 278 0 R +/H /I +>> +endobj +279 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 162.85 168.6 151.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 280 0 R +/H /I +>> +endobj +281 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 147.45 168.6 136.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 282 0 R +/H /I +>> +endobj +283 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 132.05 142.2 121.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 284 0 R +/H /I +>> +endobj +285 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 116.65 155.4 105.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 286 0 R +/H /I +>> +endobj +287 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 101.25 122.4 90.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 288 0 R +/H /I +>> +endobj +289 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 85.85 148.8 74.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 290 0 R +/H /I +>> +endobj +291 0 obj +<< /Length 1718 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gb"0W95if\'SbR0^V\0)d2q0ub?R0Y)'r"3O@f1O'[ai%7UXZ3oM#;^YsCsHS]GtGl)7.f@eCiRo'sSh$6REG_qn0Ra+eH#Q8+p%/E=0O)clL7NAr?C$a&%ih9ZukN'I&k-YLPDEo'$,^Mj$e%"Bj$rQ!?A1->!kFlpF.c>h(T.:/SH+bUE@+sY9Q"#hVBfT5P;5DcR(1tAB'm*4?NAcR##Xn8u'ZTKFl#g<6ED"2>q8rp,h?3>bt<\&4-Y2G:M^N(R]Fm0/&K`p:QWj2!Q&I#U/P0V7^o@g0i4Vn\M-s>Ej/r7]f#`+bVV9,1-m9;`gV7K+:gAEg]D!6O4ig18RN`=sMG#V5^#H9j).Vp!7F'1P?<+pd7n)m/8=D_aBb,al)6i.I]L4?DCBT&4-Z]lVK$E6X,Ki>pY72kNC)m],=YL<,'iBKFgK&SP"1lqdSihaNJ%0qKk!-:'Q@Mi;0h\91*e^NaMefND9P.&AATGQZT_0P3uI^C?FR0C")@fZ0DK22%:^^&ABk_PNT>IG!'J$BJms'a`=d+X_5hYr&2=fbhhDE)jg$S`ESqsDSFQNW_WmDe;)J;f5Fqd=g8g[pcQ^J^cP<3bF>kQ8JPD$8r^E;&43l?jn`FpqRVS"lh^pq!%.9)d(mqJ.P'BL8hO*nj7?:5L%6D]C[&LCccXAL^-C*K"il+qiY.,drg`QYFr1KFgHu;^i>2>DuKSf8Fp;X_6sKJ/Z+DA7o#NdpU05:=&8.ZHKE&4-Z7;^j@e9+5FVe*M6@D;G$$;PR+H&4-Z]lVK$EI:%r7ba8@,X77TV^TCQde#7Bp+bW[h'T$76,^Pan=]sPTXZHPb$8cK963n`^@oUTl`tO(`feR>Jh)\=]2!PuG#U.t`.Rgc\MohlugqnP)bL?&[o53FL8Z>2H6O4jbKIV9.`3,IZWoVRX/8P3^8#9Ca1B8SOn-,""N5T,Jh.SZMInRMQ=nm9NDVU8rWRkn75D0S74X2=n`V@P5Er%^RD2Aoh.FkAF#U+ki:aqI<:eXZ$oB;6W[Ht=)P%ur?+$p7,Srr%oihl`*>qEaf+7A=`]I@bcY?n/)o+44ohZ/q)bRVRm^c'%W^L^';U,Hu[8^l=.4qjjPo=cU+bXe^W"`:+-)Lk6=7_H5l)^+`e2i6o67>b]&q+*q1d"7eAN"=2^WD`ZFUoXKE$qRulB(l?(u1([Z>ns'S>l5;no+l#(A'A1F2pSDL?\%T$$RPHFdnniV;BZ>%&=Jg#<;Ie/PX`l`=]?\#E+P\V~> +endstream +endobj +292 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 291 0 R +/Annots 293 0 R +>> +endobj +293 0 obj +[ +294 0 R +296 0 R +298 0 R +300 0 R +302 0 R +304 0 R +306 0 R +308 0 R +310 0 R +312 0 R +314 0 R +316 0 R +318 0 R +320 0 R +322 0 R +324 0 R +326 0 R +328 0 R +330 0 R +332 0 R +334 0 R +336 0 R +338 0 R +340 0 R +342 0 R +344 0 R +346 0 R +348 0 R +350 0 R +352 0 R +354 0 R +356 0 R +358 0 R +360 0 R +362 0 R +364 0 R +366 0 R +368 0 R +370 0 R +372 0 R +374 0 R +376 0 R +] +endobj +294 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 717.25 162.0 706.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 295 0 R +/H /I +>> +endobj +296 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 701.85 155.4 690.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 297 0 R +/H /I +>> +endobj +298 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 686.45 148.8 675.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 299 0 R +/H /I +>> +endobj +300 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 671.05 148.8 660.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 301 0 R +/H /I +>> +endobj +302 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 655.65 148.8 644.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 303 0 R +/H /I +>> +endobj +304 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 640.25 155.4 629.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 305 0 R +/H /I +>> +endobj +306 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 624.85 155.4 613.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 307 0 R +/H /I +>> +endobj +308 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 609.45 109.2 598.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 309 0 R +/H /I +>> +endobj +310 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 594.05 135.6 583.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 311 0 R +/H /I +>> +endobj +312 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 578.65 148.8 567.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 313 0 R +/H /I +>> +endobj +314 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 563.25 221.4 552.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 315 0 R +/H /I +>> +endobj +316 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 547.85 115.8 536.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 317 0 R +/H /I +>> +endobj +318 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 120.0 532.45 232.123 521.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 319 0 R +/H /I +>> +endobj +320 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 517.05 175.2 506.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 321 0 R +/H /I +>> +endobj +322 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 501.65 175.2 490.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 323 0 R +/H /I +>> +endobj +324 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 486.25 214.8 475.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 325 0 R +/H /I +>> +endobj +326 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 470.85 143.036 459.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 327 0 R +/H /I +>> +endobj +328 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 455.45 195.0 444.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 329 0 R +/H /I +>> +endobj +330 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 440.05 155.4 429.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 331 0 R +/H /I +>> +endobj +332 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 424.65 155.4 413.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 333 0 R +/H /I +>> +endobj +334 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 409.25 201.6 398.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 335 0 R +/H /I +>> +endobj +336 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 393.85 148.8 382.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 337 0 R +/H /I +>> +endobj +338 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 378.45 135.6 367.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 339 0 R +/H /I +>> +endobj +340 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 363.05 155.4 352.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 341 0 R +/H /I +>> +endobj +342 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 347.65 115.8 336.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 343 0 R +/H /I +>> +endobj +344 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 332.25 122.4 321.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 345 0 R +/H /I +>> +endobj +346 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 316.85 181.8 305.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 347 0 R +/H /I +>> +endobj +348 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 301.45 201.6 290.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 349 0 R +/H /I +>> +endobj +350 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 286.05 188.4 275.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 351 0 R +/H /I +>> +endobj +352 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 270.65 181.8 259.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 353 0 R +/H /I +>> +endobj +354 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 255.25 188.4 244.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 355 0 R +/H /I +>> +endobj +356 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 239.85 168.6 228.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 357 0 R +/H /I +>> +endobj +358 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 224.45 201.6 213.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 359 0 R +/H /I +>> +endobj +360 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 209.05 195.0 198.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 361 0 R +/H /I +>> +endobj +362 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 193.65 175.2 182.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 363 0 R +/H /I +>> +endobj +364 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 178.25 155.4 167.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 365 0 R +/H /I +>> +endobj +366 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 162.85 175.2 151.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 367 0 R +/H /I +>> +endobj +368 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 147.45 155.4 136.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 369 0 R +/H /I +>> +endobj +370 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 132.05 122.4 121.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 371 0 R +/H /I +>> +endobj +372 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 116.65 148.8 105.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 373 0 R +/H /I +>> +endobj +374 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 101.25 155.4 90.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 375 0 R +/H /I +>> +endobj +376 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 85.85 122.4 74.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 377 0 R +/H /I +>> +endobj +378 0 obj +<< /Length 1700 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gb"0W:N+uG(ru0Y?\OO-@2^GTqK$J(%E!];f&a@-T\<'iel<#t,.,1-5@XViTfWd,Tb.U%Cm'HaW_?B,r9i/>B32Q&%W,P":O]8X-#[HncFKSBF%+q@`bslHOXRG>8)uqE[[f/$3n/]o#=WBq2*]T7RV@#fC'o@[Y>S<%_KIImmGRNi?)$;sup?b%u0#W`\*_?FAVWr]XBH#8N(hV^2AO%3^B9#09;4q)!s"+tepJgpX*5N)d/[LJM@?#pFs5Sfb@sG6+5U=7_fiNglp"qFQ3>\qKFgHe+IuJ,]r=*um;[#X?+%Sa1NU+.nnCrdNC*spKMTQU@@H8#^hNbHWZ1sNf.@<-D$V;<0L.[u/A8#6&j%2C*k$-XI(5O+U`c>-+bUED(WIbHY)CMa:i/ntcYT7=W!K>;#U+ljioie=nj[eofKl["BfiZ(#'3^cF4"9LBk9Qc6O4jJ#VHH7XmL5ZVVANXoqbk):tH7F#iWbMM/;R=CaJE^Q2,%CrlB75!pU[j#U-i?/rK!pfc_m;XfX\Bq-[K'b5uE!63n`VksT"CNC6Xt0r91PQ\C9b^-A9^+bUEDmtscT?BrYC2UtMbXEV!p-64/?EDdKIit+N_iD\,1e(bn>H!pr^4HEo7gu_&4.3VSQ&@sW@UY'T@K?(h3mpi],?a$A>"UjqeX7BF1SmhR!brW?#U+S(>a4Ds@Ag.%Wi:cb2fH:\]8^kh/I\S'#U+jSJ529(hB^:?*Fu`WZGQbWc0UJ%AMGbHkR2nP6MQ&,MTY;lc@)_*2dcrp`cO#iOt&3bLk*2D#U-jF?XfGWR1&mbgpanm2eW%&5PU1f^'=oe%-PYham<%)hV=L$*bOTc%qBT,<<74P+bUDu:F@fl2_RVZ>XgZi^7N%#TTX"`5^c!*+b\1Z,tXR?R<+eR%/h&8HVtMRh[i*[iUbDf>3/K4>WAJhAh_Krh-P:sldc3g2hV`/pcMfGZs#Pd/S;Mlk!iMQ93SeOTY;S&&AmVhU84'N1Y;90DS6uKSl>jB21uN-G]@gL>C.SV1!Oim7)/;m';3pKC\^%uU=p<#QF:aU1^ebEHf=7Yg'S);J:J+j)IgMhZ8B<&;m,L?\/2qOo_c.^g:hGqh7g-0g"R>U*N'XstJ*^9iXjEM)q +endstream +endobj +379 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 378 0 R +/Annots 380 0 R +>> +endobj +380 0 obj +[ +381 0 R +383 0 R +385 0 R +387 0 R +389 0 R +391 0 R +393 0 R +395 0 R +397 0 R +399 0 R +401 0 R +403 0 R +405 0 R +407 0 R +409 0 R +411 0 R +413 0 R +415 0 R +417 0 R +419 0 R +421 0 R +423 0 R +425 0 R +427 0 R +429 0 R +431 0 R +433 0 R +435 0 R +437 0 R +439 0 R +441 0 R +443 0 R +445 0 R +447 0 R +449 0 R +451 0 R +453 0 R +455 0 R +457 0 R +459 0 R +461 0 R +463 0 R +] +endobj +381 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 120.0 717.25 154.221 706.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 382 0 R +/H /I +>> +endobj +383 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 701.85 129.0 690.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 384 0 R +/H /I +>> +endobj +385 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 686.45 127.768 675.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 386 0 R +/H /I +>> +endobj +387 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 671.05 148.8 660.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 388 0 R +/H /I +>> +endobj +389 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 655.65 129.0 644.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 390 0 R +/H /I +>> +endobj +391 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 640.25 142.2 629.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 392 0 R +/H /I +>> +endobj +393 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 624.85 129.0 613.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 394 0 R +/H /I +>> +endobj +395 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 609.45 115.8 598.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 396 0 R +/H /I +>> +endobj +397 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 594.05 122.4 583.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 398 0 R +/H /I +>> +endobj +399 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 578.65 175.2 567.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 400 0 R +/H /I +>> +endobj +401 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 563.25 122.4 552.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 402 0 R +/H /I +>> +endobj +403 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 547.85 122.4 536.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 404 0 R +/H /I +>> +endobj +405 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 532.45 155.4 521.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 406 0 R +/H /I +>> +endobj +407 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 517.05 109.2 506.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 408 0 R +/H /I +>> +endobj +409 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 501.65 142.2 490.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 410 0 R +/H /I +>> +endobj +411 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 486.25 115.8 475.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 412 0 R +/H /I +>> +endobj +413 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 470.85 142.2 459.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 414 0 R +/H /I +>> +endobj +415 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 455.45 115.8 444.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 416 0 R +/H /I +>> +endobj +417 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 440.05 162.0 429.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 418 0 R +/H /I +>> +endobj +419 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 424.65 162.0 413.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 420 0 R +/H /I +>> +endobj +421 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 409.25 129.0 398.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 422 0 R +/H /I +>> +endobj +423 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 393.85 122.4 382.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 424 0 R +/H /I +>> +endobj +425 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 378.45 129.0 367.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 426 0 R +/H /I +>> +endobj +427 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 363.05 129.0 352.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 428 0 R +/H /I +>> +endobj +429 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 347.65 131.431 336.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 430 0 R +/H /I +>> +endobj +431 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 332.25 129.0 321.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 432 0 R +/H /I +>> +endobj +433 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 316.85 148.8 305.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 434 0 R +/H /I +>> +endobj +435 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 301.45 115.8 290.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 436 0 R +/H /I +>> +endobj +437 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 286.05 168.6 275.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 438 0 R +/H /I +>> +endobj +439 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 270.65 195.0 259.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 440 0 R +/H /I +>> +endobj +441 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 255.25 234.6 244.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 442 0 R +/H /I +>> +endobj +443 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 239.85 241.2 228.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 444 0 R +/H /I +>> +endobj +445 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 224.45 148.8 213.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 446 0 R +/H /I +>> +endobj +447 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 209.05 135.6 198.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 448 0 R +/H /I +>> +endobj +449 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 193.65 135.6 182.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 450 0 R +/H /I +>> +endobj +451 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 178.25 135.6 167.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 452 0 R +/H /I +>> +endobj +453 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 162.85 135.6 151.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 454 0 R +/H /I +>> +endobj +455 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 147.45 122.4 136.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 456 0 R +/H /I +>> +endobj +457 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 132.05 155.4 121.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 458 0 R +/H /I +>> +endobj +459 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 116.65 135.6 105.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 460 0 R +/H /I +>> +endobj +461 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 101.25 102.6 90.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 462 0 R +/H /I +>> +endobj +463 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 85.85 115.8 74.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 464 0 R +/H /I +>> +endobj +465 0 obj +<< /Length 1317 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gb"0W9lle)'Sl4l4pB,S@1(f5gX_3EdnW&C@s,@r\fg3/Ah&@`E,0t#,,Oi6U&d!t8T2OWD>_9kL8+p%"%VQe55Xb#[TqF-XSHo!=K@j*3VCS'ih0Tn3jB]_d$emShqpP7f(naVqSSd%:fmIrGJGhj#0b.@:/47qg)Zlk#56J,o2fHLkmXXO*+@pa<-F6[!>@VLa1Y5Ye.APs7S*QQd;rc;?oI&$Oh&41X3Cd_@sH?pEXEI)jhTa\fZNfPX_;6@-OpKLZ]p751fI^dUqhB@O`:5u#H0+bRA9WthEX!I#GP3RsCPsLs.#U+laF&ZJgaEEWdVt.gb3TB57CfVG'3J7r1GWnXZV==-$NV_.kPcjAUDc"ak63uPG3%F:N:_*W0e8X&!f/KX@#U+k?;J_#74;ddPX66'TWq`hIrd=#=*TV`lc&Aeh8W&tS84^;#O%plPZX`%%^&4-Z]Uc9jj"/1LnG#d5qJC)3#ppNd'C)]JF+Z,:?<;$Mp=b_50m&srj/Wr`^]N"0EP4q/jdrRsegn;+V63uPK0W<=/r,*@aS%fnibXJSZT]RDN&7,?,-(,_;_4P5#4f"-RPOsQ3lud(Ql5r=uiVsKM@PDgBV58:G2$W^_+bUDU*M,gUp+o6mFS%Q/I?Ko8IO"jk:N(-C[n4?S.Vh'AATfkJboV5GXOh<:H1u`lGYmX'R8knAefeinG^c<\kIk'!;ROt%ae+ahak[5u/aC$*l +endstream +endobj +466 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 465 0 R +/Annots 467 0 R +>> +endobj +467 0 obj +[ +468 0 R +470 0 R +472 0 R +474 0 R +476 0 R +478 0 R +480 0 R +482 0 R +484 0 R +486 0 R +488 0 R +490 0 R +492 0 R +494 0 R +496 0 R +498 0 R +500 0 R +502 0 R +504 0 R +506 0 R +508 0 R +510 0 R +512 0 R +514 0 R +516 0 R +518 0 R +520 0 R +522 0 R +] +endobj +468 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 717.25 129.0 706.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 469 0 R +/H /I +>> +endobj +470 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 120.0 701.85 163.373 690.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 471 0 R +/H /I +>> +endobj +472 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 686.45 162.0 675.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 473 0 R +/H /I +>> +endobj +474 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 671.05 148.8 660.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 475 0 R +/H /I +>> +endobj +476 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 655.65 148.8 644.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 477 0 R +/H /I +>> +endobj +478 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 640.25 109.2 629.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 479 0 R +/H /I +>> +endobj +480 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 624.85 109.2 613.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 481 0 R +/H /I +>> +endobj +482 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 609.45 155.4 598.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 483 0 R +/H /I +>> +endobj +484 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 594.05 109.2 583.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 485 0 R +/H /I +>> +endobj +486 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 578.65 168.6 567.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 487 0 R +/H /I +>> +endobj +488 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 563.25 109.2 552.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 489 0 R +/H /I +>> +endobj +490 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 547.85 109.2 536.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 491 0 R +/H /I +>> +endobj +492 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 532.45 109.2 521.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 493 0 R +/H /I +>> +endobj +494 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 517.05 162.0 506.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 495 0 R +/H /I +>> +endobj +496 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 501.65 115.8 490.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 497 0 R +/H /I +>> +endobj +498 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 486.25 109.2 475.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 499 0 R +/H /I +>> +endobj +500 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 470.85 129.0 459.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 501 0 R +/H /I +>> +endobj +502 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 455.45 208.2 444.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 503 0 R +/H /I +>> +endobj +504 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 440.05 168.6 429.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 505 0 R +/H /I +>> +endobj +506 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 424.65 188.4 413.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 507 0 R +/H /I +>> +endobj +508 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 409.25 221.4 398.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 509 0 R +/H /I +>> +endobj +510 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 393.85 228.0 382.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 511 0 R +/H /I +>> +endobj +512 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 378.45 148.8 367.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 513 0 R +/H /I +>> +endobj +514 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 363.05 135.6 352.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 515 0 R +/H /I +>> +endobj +516 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 120.0 347.65 197.902 336.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 517 0 R +/H /I +>> +endobj +518 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 120.0 332.25 199.134 321.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 519 0 R +/H /I +>> +endobj +520 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 120.0 316.85 216.239 305.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 521 0 R +/H /I +>> +endobj +522 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 301.45 191.007 290.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 523 0 R +/H /I +>> +endobj +524 0 obj +<< /Length 3055 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gat%&=``Z4&Ur?8R$UcdX!F-$cC).a`NI;(3m)ck>HVc`0I167&[)@'Bd^YZ9jE[4.'HQqRJq._)LYQA+)\giZ!8!D/70Al2u2H\ZWuS\[p3_W^c)'a[b^9cLN`3kgP8PI^)edVqX32!hi#BJY^!i`0(!,_E*;8Nb3_5oQWq)m6XTl1X&04PICH^>MeU/4;#$O=cPM%hn6ouu`U&F&4:0,:=OSD`q=`;7+$[N`&G[UD"f_Kh9;K#lT;ILd^HA^A?qA1D,-DfXCZujem%*@$YH+*?HG=NJ8IC@JrbJgTtE'i=V,#,8"Gf-/!F%;m0SlmG*RB+D"`snfkY!uZ7F)g0`OA<:uTOO.X1Y79qFLYmXU-#8W$7ZF+ck<6(STun\_RHHC:.Ab@GR_Q4JO$t5VeoN[dSn;V)PfkNe=fUm^6a(XDHJb*VsLT\pIGons15UCji:X)PM;kO`k!memIG*l7rZ+g."Sbr2WZJ1Mm]NSKq-;6?oc4mG^dL=RKjM0nF&P.C/>a@p/Mgg.jGB%k&b4r4P=eburp0=_ht;`Qj>!PC;+)(t>G<'U&\nE92t/cGLctY62Fedp+@"_OK\ZIi63Z=FUpbkUG?[k@=YN#=7Zm,=X'f]$sVg<;\R2Y@^Y)Ab(]TGDS4:.`'Zk]_3&OD!/c\*0#O9cotar5t#")R7qAn$cQM$DZkDZ3s49Om;[+/Tqh7qU__M50R6.ng0Q'6qKEE7f-`@(2F,V[Am);mF3cj$JqI6P1"u,%QHN[N?Ueq#6L<@VJt"hGp00aR!jHuK=pBhA,5@?pD$$@`@X?pVWUV/%$q;*GFN^#oQ-`9`d>"#p+XZGB;mo$@2']@@\?4OZbTp]m-!9lLfTqHMB>FlPplAbl"E5QmQ]BFqk0BMAH?E[+!$j0L.mXSAL9Af-PiTLYLZF9?`F,/E!LuqQ!6h-8XI@J%];#URDhr5C6uT1sT/l94)>O&K%6gi!_$^iV.j,rp'I1i!P).[_1Q'g1,$n@DZ?B$)nG?ablJ(AblUQGk,OZ^!E(Z=2KSq3]25P!0Ot0U^VjZc2-!5'3;(LKP:qUFJBL%0`/lNEmamabtPCtXg>-L^O`)M0j^s_DHsUZqO)fr*)/eHf)?I55-'5PJEks/skTCHn512F+4+\g\BSBl[*ph#Tb)FS2!pq3F:'_.E@Y4#0eK)!=:kBWiK`^-pa?IqCNn\ki$0:/(,XJM`";6XR!4cVb,N&[[GKP1::dI*k8!([aOJRM$VE%r-&s?'D;iU2N`K"u43k5PH=!BM@4aE,mhn+>6T#P`-5h7]/;H)\[kD.QcTR[XQ(_pqcD%IM(2I:Y9EZ([-L/kLlC;N_F.f.<@Snc`RDqf:raiW4VC6t!i^Yq6WY7:<*;<`GTh.pL"O%`WA5>iO<4%R>6ZQ7;iqqr\(lR:\SO;OrR"[q,9>(AXka_!S:8R"0'44:uc@+5quOcR&"`i+A$7'MI,pSSbVN*7"Tk=RCq_hH.FSN(qDOZXg2a_ZC:@?JsFe(iXX4_KP6c'sZ$mjZrg^Y>THENY1n;*H"o[Npn6f(CV1]OOHZlp`kHG-8i$$CJ71'fj%5B/"!tjA)93ajI1V$Aj:]%>nRMhQM7UOS8k@D^4m?;u2@B6)As&(VEXB6))GaM,#l5\Gfuk312*PI<_9KdW1?@%,i$5ZosHH'kB,7og/!b%DYqA*i/Ce<$MB"=sd1JWZT'NAeb6#q@K@'pD+ngEPA5]H3qUhGmVJ(jfABQPm"VI@)![VjH62Ie]1@u:\+NNZm$jOkl/f(*E#sI9Qg_bC63]QS*XW,o&s(kK*'bn6\;9uqUr'?.,^4*.M6%FKD=9t^.GT:]P;)D9"S,)L]h)V54-E`&C#<,2>pJEpf;"F9,TKuc/3q;6f>g)AltsiTF9$WEZC:&,jb/mnR&'a1QF">;:K1DaSt>HHG@?E21+U^FJ64f:(_^lRh"_@UTA7;sqS/uAG'T9E_FOGkgftRE_@kj`_p'"hY8!jGfrjm^Bf_OVrGIa1l\4DXe'1*q^-;bJ9aP%/?GYDSIeG*aA5ql9Z//lerA\)OGB(1dJT[=n;DpG6X9:/Q-^s4l"H>%bMtIE-bT6-D5;tK,;Z~> +endstream +endobj +525 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 524 0 R +>> +endobj +526 0 obj +<< /Length 2962 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gat%&9p=T/YI#m0#e#j:%Cm\^T]`G1Yi(]37KEcJZp/XGmE"kXU+c#T.fMToVf/cL/_SGAYn@p'OL\LuLair2Bf7_MVl*>A6h;>i1@0jHLqZ56fPT&dQC%E/N?jU3$m1POKCdYaJ&6:j6-4LUFIll]Id#d.)p#G->#O&Fm'rh%1/mtk2I?'uGa/2*MXR;$rSbEfd%DK.C"Ao&R8YIMkF[h,b&Asn9T2kK:f4,?bHQWFSe9(GRdHqI7Lm%ie.nAsYX,[22eO\_?d%]J0o@DQ1ZX'd>*!!]2ZZk/?[9[WjA&bc;$[G?@]1E.(,LM$B@p^T*f;_E(YP1^K']RG$=_^u%k9'oW2:jlP"I6sqp!!Sm3qdZ:at)[>D`.m-[5XShl@F0.Np@u"hJ;.n*p$6/U5^@TIpRGDiB<@[%<8+-MbXJb^:/VUPPb7$P:s$g18k(H+,\%53&$%NaX/qOak,3l;qZeNB_aT,BW%[bk3Mp%7kD??-R!b;16PEe:2UcEQCD^$FiJ\7du/?4?-35C2/[ulIS:@A[_eCIK;Q_3=cmOFJ:KFgrBR'5jH,-u_asq>8:J@?LG2efDMQEb6b!c84f[u"ANK5JD.d@DF"`&g8PS"*BlqT_03Z%:*TQOI;[,G2YA@dSV5GXq:T+]'U@R,Cun,JNOdPIk*rA\_]9pOhs/=p%FdU1=T%4n:$hN;.FW%ZMJ&+,1#_M8Z#ZZ4b7)l'23'BMTe$>953r>DAR%M-XG%i"N"k@Y.RWp>UXjpY?DZ`Q0ZTph?i[UfY/=dBUVQE)4&Vb!^&6sg;;^@9f7$NAA@>a3h%0H#TE`qr%A*RR;8EFTtBDU]12'CqE-.b@hfX\lR&/QdmIJJ/G\Oq`pGC*a*s#q1BVrMI4!r61uQc^YL0agh\]]G+qpM4-cKR3e$u,uOHU:$pFo?H2sZ9,,Q?dGTjQ3N*b'Ac\Q!ei-h84$6=ZG[jRXC+8uf'[uj$O)UT9&^^#uf=0YjP=Ob)e_J]k)H=dHK7,V2o_kVjSLH?c_A+mChgd)q*,lpkEW0Q0\]6p=86O@QZVU4nrF$m'9d,k87/jn^n-5WaZ#bVbc/6;*9<53R>^hdP9-B8C(H?+mg\MOeBIYf0ANo@pI(g-$o-Tns]bq'8U?=22D'+oE>V8E@a-fWN&He.#CpN[[](e=]nqkWA)*t^=,Y!=.ojBqB:iDg'B\kuFA?(a3T';pjlbQVjBFHNXZZ+Ff^$T1[85kVHbJ1_EG_8+"(^0I.I4FhoA`^Dfj]UT'O32:;I/DoNXdYAJ;>W?:/I;>I#&NK9KNL!9`38IiP\;c=Ni$p:Pp3:h!.bfhli79Up^G,%11nK(h[lgt$*?HU9(8QI2F(2D`nhDe=[#3YXSXID"$n9+]%e5*(QA^*7RquUa$ek,R@tEk;0uaTR+>&&ToZ1MaVt)\nQ':(,@c]GUVLToF/#J!J"ZsK71s>pK=^*2%4E)%6p]ggOu__18`ti_-@.,`._71GV&)Z@]B*pA8n`LUol>R88iYPrLcQ1=a@$Euc3X1ufnq/gOFL:7_"!QKA24enf%.oN^kF@DZYerqMX#M\3l"U=eVs/h"*N^hK?q6mCP($ut@!fmm=3kCp62rd.@*TtN4NgZ]\G0&P?k)YN8*Fn-nnC:nrQ3jd!$BBa3"h4_\;J'M>M%]$]*l,T_7,'^XKeM'>TM:##Z4IYX7KIbd7s$YMUM6d+n!XG\MW5A'`J,S3R!C)p]KOPfk?*sm:ue!9GLU52^-8IA.B/M`NCddQK](MkQb#1SoR#.b$>FEU[#,+#N$JY:WcP/DY]7O]3o1l6XfSJ[Er0'J*>LZa>D%YOP&92hXAE5qL(MjiH@DUoa9Pu*Pk'Snc4FPja%g"2=[V$NYcQ!7-inadpRaFPnEMlC\J(lj"FbqN19>Y4#:*q"eZIJUSslR':aNnJ;::R^AQ5WPMgHUN3uWWnJ!ld`J6>/;77LB>gEdB]jU/$%;(C+/"i6&g]DL/E+3/-,@AU$/__#Rm>jEc&:9\YL2*-BY^Y..C(\$i']hS5OFMHD-LS.@Fu]H-&1],)O'\^aU&])mLol:tMBe*FA(gNC;6BjYa&%]NoB7)51S/3^q1^0A$+"h-\W\5+$6;VHd`679OK5h/9iT2qk"hMrWVXn)!HL_+f[+f-PgVNrM=p>SjFW(bfk(4$Q'7Q8R(m;Sd#ZjGY!R]+gol\\Ret'ME\BY8?L[4qDgVV>gT5+sQC~> +endstream +endobj +527 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 526 0 R +>> +endobj +528 0 obj +<< /Length 1120 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +GasJR>Ar7S(l%MX.s.0\%AOR_q6F.mX[ARgZ\&upL4YP$RtsIY,ZV>R^6C$`qL%F+%k!O+\;'*#sm5o/K-*%Iu0sg,e`DQ"j1*B<*PYfWEi`[?23D'6:JB@R,)e#/Xeu&U$dOfe"7Iq^V>Kh+3#gN;BFYMRRlSi)bK;ek.O:RNg-0b>H6$.]8p;]nsP`c@DE2,>o;ufh'UqI$[[F&:3\XQ5OL0H^7__lVof3DSOGQUnPIc.=@p'g_tZhuj7O=Ea`:+R+^0ZeaHcBGaZ%(Onl/OQ>@(/5Lcu-AIm--"`(ls$_YggXLZQt'7=m92,Y_jFqHRY=V`7D+^7&b_r=&UQqqqLt:$^=@hR?9-7$-(qHH1Fi&S"0=N%g"Wd>#:*[VGYE6c(ru(bb3`U(sIOV@Tji=YZa!HYP4#@qaR\*b/lbIsb`6^-G8UAD!-3nhc-5CI^oRU6Xh1s$'02Ap-M/eN!^BKXrUe16W;68MsRFbOTa%-ENIVd%6GaZZh[.sI4V[[%$"'ptKubN"8mPssA,B\<:Qs2"@nhgI0WR:QNSP8XQB[Vh8\5l)B(C`ElMpj%`k&q?N9;`_PAVe(#R?Ls]@C8hl`IWK`Au)Ijcrn+Gn?fk?JEB8a@r=:b23P#IkfmK/HnUPR%2FqfjiKelDltdn1bd<]bE+_;iBskF4os2hebMuJDEEhc.#?S)^:ne$\hRD^J!kTgA7/<; +endstream +endobj +529 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 528 0 R +>> +endobj +530 0 obj +<< /Length 1621 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +GatU4968iG&AJ$CnEA*KYkSuTMpld2c=EB>lL`Hq!)]DBRK=0'PbNZbV*GYqLlU6Sj:L^6`F<3LYk6u@k2GJ[8i!].9cq!rg/9R/g8e"Y#@@[+\$"hL:]YhcS\`DU,G[qkRJK_X1R,R$57+/^pnt^S973@(;^8O%.U",&*A9QHFi1T.nD]&0KikmsggmFC])\&jO*!o#N`c;3M8Q(_2R?8j_qAL+Uag4)[UY?:\b>N2E_N9m^?F*i')9+_^R]a?A@*hA\@Gbc4g;J"`7DlU*@N18u\Ck:Yoo8bHK49G8qn16dDukAJAe5#DI0l+M)@J.%8=p_#+>5;JkiPEiTj+TF)^GWuF)%9Ad5J>K*!6kq8)l\pX1Zn1[Hm]3p?*sM9gZHAO:>6`Mcjb'jcCn3F7h:ItRCH/DB5Q:-hp!OE/4hTDjL!sU,"4uL+t[g@T!`3i8:b?s[t5O.+?I:KXG19:(`g29P+Mk2!JZV?/"!&H%Lg:D^'bA%^2h$a)E;8P&U\8b4:H*FS.dphReQEA.Ukp7XrPP=*k+%"mP3.H.6[t@n_lpi(`&R*h5/I>_ugbOA9`Y!B%R64\mpjcD4AB)mI-mJ8VbepZ[&"cZbk+;%K't);?:o+5PBcA@2jfkQ*'9rO!U?IWM1%m"-"=r7rDP]4))Hbqd>h=6>Zrg6Z">L#iXo9qJ1I2YV7t2"$_nN(\)IZ52Z,7cR1B**Q)gJTp=e)K`40%q:)mED.O4r.*)E1#8+UXPO/B&2,"6F$l/8nYll+I;h9MmPukD84bs:IREum@SoYd$3FcN;k^1R6I;&JrgO&[9B?]?-_o(_\,($lJ@ksk65/83=)_S@D\3/FTYG02Eo$TdjQ12:/_a$1CKXqI)g9**`$c?EXS#Mdd2%D0rp&XZj:-6'L\Y0+IC=0Oe:[,F>OUT#HErkjj(jJ"AYof!9FSIE>!qrG6$Sr,hWQBjeUJPWM$gDq;:KU7TJC115>XSk6q+?qNZU5A[f2iJfS!Ie(ARoUh=I#PLs-IJeLLJD))*XkLaRg!J.sG5Vu*p83HI-nt(M;qM$KFRB*3)Z,I'i@'"e@J][?%:gm,Jc**V'&#Wsg7;tlmF?&L+U)+ordO@qB^'jji\GYp&Oa85G,+&(QYRpQ>1ZGpXpcBfSonsk-^DDnpWRlMk@FCIQg^0%?:Ne`$3&(5Y2R@KBURi8HZ0ehJbJt2(pABp+/+T!hb`h$4$*CZFn>"k#DiiEQe?u/5g^mWW[0b>H)+QlgjHh]>YSWRn6RJf#.cfDe%)[]b;!@f]PrXT@1?./q"=YX77Z*82u:o9]]e7 +endstream +endobj +531 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 530 0 R +/Annots 532 0 R +>> +endobj +532 0 obj +[ +533 0 R +] +endobj +533 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 162.768 523.2 352.815 512.2 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A << /URI (http://www.modsecurity.org/projects/rules/) +/S /URI >> +/H /I +>> +endobj +534 0 obj +<< /Length 1978 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gasaqfl#h.'Re;/kV3+XZq+pPTFXcE.8lrtketpcBSlg8;)T"h<(&0qqt28CR#<8g#[i1fJ&366JF@?4/)T)f6-kmId#4$^7;2na..K3Bn*fSS9!kBF8]u@$j8J"TI[/-N#N,aR0-+ilSlVug3,4j,94OdU0Egnk(]qec7oih%7PV[jN^E1QJN'';i6AU48\?MnXoiH`2W_uJA39)!p0HpqZ-PM?h9cGZ`'7o[#0/<(B;RG(0$L`1Tc)b2Lom1l6("U$"[9_#^iGlrfr-*jUPc.OP%UfD,J(lS*I4On47Z!>YXm)JJc$3M!OO`OH2bLXfLn`LZhsm%:mqBO3m8h!c93*Ep1*L!UZd@sU&UJ$I3r054<5"fSkdt2r,(275+#akC[>OeQmI)'Fe`N0b"t#Z>]hVKB,q=j8]"'#df+7"Q4/<9L&p.If7,+rD:*JqUd=(gWhOdn]iR?k[8*r,hQ3IDV^SatiSW].m1Vif9MdD^7!I:HX%E!*B!]]^mh;>1u^iDo'@2k*?+H-J4;#6n?c;S-gU`i85_:]FmK7!$jrl!o3akC0jC\$NY^?"&8n]"GEmB`I6%koE-b?8VEU`aY[%'bk]gkm$0KV>+2F'l'S\gD2FR.TM8_#f^LN=4!dPU>ft#?sHe%?%K*cF4c5`+M5?Z%F'BHNSl&8!H_Xk3(">9>@'q8iB/E@EGCA<`C/o?:2EclM%@6NUn3KUol,7I<5?9p0_:3)1un,L.PqLZGjLfd#uO:qfl@g8_)F$&ci]A310C`S!)M/-:HIp4G,OD+.?XQSk6#TC&T1>QmPQ&VBtn8Q-+@hi9To;2[Lor`Gn[*RpV*T@s7+J%M;l;AtkqIq^?5[Mo3LiX+[9i=o+@C@c*bA$M64Z'>qQBiT)0%Bcf&.1,t:@S&Y2kc136FLlTdjQ!e/nD0F#AYn&/Zn1h:^CPB:%h[*W/$\jn*IZm!hoO_"Bp#)Dj=M+(Q=pp"_k7_HZ^]JY6N-2^aY;pThr9$:"*o**6?,'UKD/go\O(bL#r/H="QgB,,emRlc(9WL=Ko/(nH(J/*3Yu[]r&sCLFtN$8cI&>)55((<2m-KbZu&o(b*5]m0-45K=0[dncsu%;24HPYV1__;*R%J3N)I!@3p1KD<_7ol+H0h>LnXsn(GIeHD`-OWkhqZ&Bd6RaU)ifC:Uj3r(5OU[A.;]_/"1O_GOc8F0-guDd@Xsc4@14W=F5'S'^1i^GnUe"CVjN[2l_7Tf'ZZal?Qu$.EX_.FSGl;l1;IOO!7"W+j6YLMauD-BpVSA]<"tbciZG.8]ela:8NUho(4JW9\,YVDaJRA7L\I]%Qm7N":p!YStN9Xidd>+'Ro\I!GTS2D`&!1"BHB1o4!Kqa?C4["5X6sA#gI/bmc~> +endstream +endobj +535 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 534 0 R +/Annots 536 0 R +>> +endobj +536 0 obj +[ +537 0 R +538 0 R +539 0 R +540 0 R +541 0 R +] +endobj +537 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 118.0 579.65 212.094 568.65 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A << /URI (http://apr.apache.org/) +/S /URI >> +/H /I +>> +endobj +538 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 118.0 544.45 210.268 533.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A << /URI (http://www.pcre.org/) +/S /URI >> +/H /I +>> +endobj +539 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 118.0 509.25 268.964 498.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A << /URI (http://xmlsoft.org/downloads.html) +/S /URI >> +/H /I +>> +endobj +540 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 118.0 456.45 271.087 445.45 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A << /URI (http://www.lua.org/download.html) +/S /URI >> +/H /I +>> +endobj +541 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 118.0 355.25 232.279 344.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A << /URI (http://curl.haxx.se/libcurl/) +/S /URI >> +/H /I +>> +endobj +542 0 obj +<< /Length 2167 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +GauHM=``=U&:XAWi1nah0QE8s>EUqFhYil7Om`I&Lq(JRJ_rZh.[@J+qsEaX4&)t,i3h-$9"ocUEk&:7D;La)g?2)YEL06Cgk#8l4\MT.a";BgS2%YZ!'*\pITi&k]/4)C@K>Nq4Q/FT.+uFVGbL$>]/r6b#a!Vm3$G+p^kAWSZ;GgX:laC!=>]J=]NV-N0+uhS(@:Q>W(iIL-R"]RXVTW,hYB8e=81.Z23,moEqCOL652uQI5m?:Ke?7,@5jcVQU+HE_/15e=L;*]&Q%r=&'fX++E?g'X;['o`()e,hIqE(cf&d=r_g7tuh-%&'gX2/C6*Wcmb=OEED&[I43X4-7Q@ZM=;+9n.<=)MIKSS"Id@I>ts_+BsK@d1/Thq`M>cXTI`!XC5O6jZS6*<(gImINS64#;B$"HMYhD_VFXXnWD2\Rd0u9@iaH5aC"#bA(AF;^>fZsQSQE![c#P!$"`27>e"m_XoO=dFS0CP$Xo">CD1]9U?J8V5<"Fh3Zt7E,Ns7ke:u!Y)Qg\j1?X6qh'fP>%Jq^mSgQa-:'Q"Wu]@&\I&#&/QLL/?tlltY4G)BP3@9Q[mB#I"EJCj!=i7%@o'4?_AT?Cd$kbFUJ2A:ge'+dI/.p5`qB/=!aTK%5&BrPZeMFp<=f.BBfPs1iL)n79SR"94pi4<.9J[SLG;SY4V*JdNEf]G86%!`N;JJE(F2&em!f63717fIL0bc#4phYWR(eCEg9.T%Jt,sE>CA4IT<<*@BZ3+&=\>:/.lath6m3@8Q\'Q`AO#'Pr3Vu[MV`h5:-dZ8JJqG1>1`Z'Y[a4R^=j)8kGS"Pk_#;bX?29Um#\,O]g[K"_m'kYa"L!j`*k+CDQU=89l:\rucjm:7QXn^V@P]bEgomHp*@Gau0TjXZc*71CE-[;:B[EL1&JML*>eW@heigFlhs/3Fa27Y2_J(XG[=[_m*l_el7Yq"5XGXa%2DF-+a,c#j;95QVoH+!fa/Gh"//T!cs%:Q'@XZbP=`HL";p:n;+*7fff1d9N#+s2&k(H25_a.d?CAchf6.N,ObY)hk;ga:\V;XD%*r84%h[97`01^B+]Mj!qEGLsmpctt)#2MMfKjMMFTouZqVa4q;MI]1-X%eZ0*p>7"3(A7I?n"*l&$26@LU+D[8j'G2eGUU*/`CE8H:BQi/7$FdmK,c[2canIkUlO;:C$Ck5b,~> +endstream +endobj +543 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 542 0 R +>> +endobj +544 0 obj +<< /Length 2171 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gasb\D/\/e&:hOY=8:M_+BJ,Lg&'?eFmH7??0boIQD'rt8gZ$G)Ca@]^E4b"j;k"m6\)uHLcc`>a5`;cpK'THYPu3B=7t)r%)Q!cm=K/>-F*CfWaC@\WiJ@e?Mj,Q9bbO(mI&hBX!gkj?VSe?Q"mR]OOAKr;0hr6WfS>dB0n29,C'r'ZH/Yl(=n#9BEtuTijEU*AlS(!oC#*_(fMg1\`Xrjd7WJlR^r*P_H;.?U8KNjeNSO*]#mY-pqe>cK_bI?paY\%cn6'\U0X=>Bg)^pp3[^+IB-g#b0cV..#pGt`Dkf7LVek3DNe!Z$b\4\=-ir8omFQ!ZJ/$oZ\DXW:j2-DWg?G(Lc-gD1G93Q8-S4So!s#eJ^i#VB\G&'`+rQY/L)8j1ag#)kh^0"NQM@bh_41]Hg=6GP\_$SlJpX7h-#qu%H1eLW9'gfq*<]+Bo\d,4!TsI*D%:?ZA+jld"X`@[F.enD4Ts>!!4!Zh+S&jCZlqU*)en1lG@7i]BDe/)WUes-q.0&D17Jb=aY.MKaW.aT=+[%uR02&mP;43nS)0Z]OGWKDaa,uo-3uj5jqX]bmIdS:TkXnu4V`&7p,]M.@M!-3W"8%G'k_6Ba*G=OZ$Z4_B?RD[7?hV?4@ucCp%lQ%j16aol^C!&)FncYWRXFCVPq'7$?W[&JpM+2dm.U1`ke].4-X763YFW6TG,r?d#7V!u)e,GY*$l#HZ:-2e[:YD,%c$,&<*K-p?4FreO.B'=S'MA`,bNZ;WBe0M1&V1uD^35^U5peW6!'UTCChOq*$_8`[\5`Z:B0$Hn;IB=\UU[-*cg^#`J&CARolpYS2ESGX>itc/">*SG1T-4eB&rgTm=M^AgYi-@_C\#_4kbio)dE9Kh;Y!U>Hd&#?o\"dH@9g"g*R!?qiTFKK9J&;foa8NQ6YYR)OkVZe5*@GM]LgU6p*t1tuH)>"FTJj9YqcIU`\16a9T!D*,M*=NH8Hc)\6E*UrYDV\)nF@'n(ZEXiKQ/%1A+R;c"BIDgK!B7?X;,ElYf^9'Q)R)H'4ebke-.0!6ZR!Y"fCbN=3Z=GFepi0^8!pJ#A;bhDtSpXPM]ts+4$RK.+6EJ%uPQSlV<0G^!X$[-Wg!cHS'+]qJUH\#lFf`o[7b!?@/Pa'/\XL(]>u&@@nc`K@.l!9+T733deB:f#1C:nhiWO*EEC&s*!#>#"S+X\RdPG^"AB>_3VBV3t2r7=A8.@MkY"%=AEC]=so^=l3"%"C5/uEU7Ie5/*]QBc'5fMs%oo\+SV,mEI2=!d.:9D)6=F>:OdflWp#th"#q74_UFm%D"J;B#+mu`CZ:/gLkI$[bM3[XtEAu.oGRgr.~> +endstream +endobj +545 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 544 0 R +/Annots 546 0 R +>> +endobj +546 0 obj +[ +547 0 R +550 0 R +] +endobj +547 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 564.156 395.95 576.377 384.95 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 549 0 R +/H /I +>> +endobj +548 0 obj +<< +/Type /FileSpec +/F (http://www.modsecurity.org/documentation/ModSecurity-Migration-Matrix.pdf) +>> +endobj +549 0 obj +<< +/S /GoToR +/F 548 0 R +/D [ 0 /XYZ null null null ] +>> +endobj +550 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 90.0 380.55 433.728 369.55 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 552 0 R +/H /I +>> +endobj +551 0 obj +<< +/Type /FileSpec +/F (http://www.modsecurity.org/documentation/ModSecurity-Migration-Matrix.pdf) +>> +endobj +552 0 obj +<< +/S /GoToR +/F 551 0 R +/D [ 0 /XYZ null null null ] +>> +endobj +553 0 obj +<< /Length 2881 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gatm=h/D%-&qA57+V\$$"VO;^*sM'UBiA7HgYQi-m`Y<#cn]GO.na2s`:Y2>J%q+:MB#fcqlo9O3^8fa_r5u_oWYj:q\V;A86ff4^2fdhQ05[HcZ9^@YW.P4&uX#akPTf-^+.`^e((he^tZhb?OtgR^^RlSAi6nA)qm+i2F/2^>#te+qb'9@(4doJVd/857*kGF]B.+JX7=/2Ebt-:17/S(;0"q)'CL<]P*;Geroa+>.q/QX*K%[phDo#Z.:l$ho,Oqg<$Wplk3+IAi/^g(^D=BK/dnSF'<$\aY;O.CkWI-2LK)<&t0`S/$4*I=i0V$1q+:8jON+=bf_s8VTZFcU"VZ8'DDdmOMkR\NURmjgQ!'L*%ZTjZbW2hDf<=WOX86mL*TX>J$*hVeE7hhDD9&AAq`Kd,giu`:UKMKF&nM9`e^?2QfTSIZ'L;`WTrN&R)%$=Fs?&!cWlXDRHIh]2CF/##\(5S#b`#>JU>oVB!eZMm$6*+`1#:%oa)6`ZB;$r5[3LQKCq)fom\o^+cJ!_P1>Yu_rPQM$8XR:buR9*=RYecAX7#PfY:)Z.^G)H?g>Y"X=RSH\-)r?*C!PeIL*s=/6?=fGXGj8NlhrjCq"j$p?8%TXP3dcj4=f'07)J(jcHF)UcDL-Ddo8S!7\-f^2oS"9B6K)*Z!A=uC^IGpW^tUNf/(q(8e>DdN'1gn=-S&XMUl!7rUFV.!C[9[eY[,mb7JH=,$mL`-hC/\8m-E+&i^kfuLq\k=bdg0EP]Dq71LHVU!M1Ra"@+V%?`Hi8p,&A/ND9QuJDJnV*Jj]j&$[LK$ce(nD&KpkJQA8,k=/.EW0Gfsc2Bh97lb>`kMBtA1bD'-^Ue$O)E['hrn\'#YeF,eI24E#foIj>6R"C3dJ^e@IJmm?XE'$]@sQ6se,$SaqK!LtAA_QDPQX_uoY[*reQ4P>IJ)pV_noRn`'0%Qt=PGY3V#$:B9F=uK;<`!3GqiW`l0e)1I.9_tX-Qd)HpDu"!L*&5IU*"G_&_U11mHOBqnKG-D^"D6=9L.O/V;F@m"A/fHP"26;&1ELEg8G#Y:]NK(>F6c86tH+#E1)j*CR2rE&(,6`g:j&\*O0sK=sMjH\MiMMu",l;46pG:Q(YO(6CoO2VsOnu<0@W6rW&;,V=D_W^["APp2WfaPK)OS7#d(BpA+dKDl,&=,kQTbRUSGJ1cCA/jq+QphP)%D)Hcg^j]aKUFPIO4gn!u?lSVFu*:G:J[&Le`SkccI)+J/U0^O6H.jkm-EMAPF!r@g6Y?U?H>q#)3?Oo[.FgnLK50i`K-?C->)P8Ie*\\`laR\?M')LBjgYP>nU8Y@WOl9;;D^a%iE4(NG-dQD1>[R""q1.4cD@b@SeE>2,+a0MQ!0rHlQP,`?UGSTDV,-9g9S0)E.$-i/!m#+N;q;_/"E%PhghNi_!f'qNE2HT0rf0E26CeHn#P5*+T8hu<`/e4i)NLd?4ZdQf7RdkHS$'1/eSY<1]B#EoMAZ#qO\D!I.raUuP=l>R,RMjQSb5T"AJ[,)lb\hs:CXIZ@)#V9LoeIGK@t9\Jd?\6pQi5*J*#Rn1lO*rrfq0;?oj,h24XeRP^BSr0)N=*dg.<*dIH,uhOV2'SX/R]\`18'^C#I'bYoeCUK^ojBJ>c$l&iTGJ(oC`f'[BAtk'(-2e#]ZiW/c\Bo#s)fZgTj!GT%E'"Pld!VqG\AIg&6:k9PeJ\AXV^Gn=.NY[gn`5DJb06:cJkW>rgJN&Cc'_! +endstream +endobj +554 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 553 0 R +>> +endobj +555 0 obj +<< /Length 2018 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gatm<=c_;q&:XAW&FrYBJX@ro3]7Mfk3@N[B\)QU+s'*[kh/G"9GOd/#^ke97Z9-BrM>Il4tUeJ=Q\^]37Qso1M5D@@Dj&KA*!A!CbK\l(\7!bK6lYLA,!$:mc:W(Nf[?'do7&DbZ;DNcJA1IH"6*Q]/g.1/5qp>su[p'!).I>,WT\pUk5mo"Q-TF15NB#HFJ3V$n:;]@jJ1XE0)2,;RG?V1T65[_($[k9%6:b>I.`n;[=RR;q,U?1nROZI[ZTSOG<['=I8`HG:'&*!7DE_TAP)[WJPk/hYBNJq@JP;77EL#'0i-Jo.VK,#O]YJ`D$WR6ROn0-Mj=P=M%C#=+@*b=aS)/";lG-e/Qs$1R`dD-"`*1l^-TKES`?\!`D3LR;#LX+C'n.8N/76UZ=]44@3(AQ0rLdZX;N.4Hdg1hXbX:fsKhM#N-R/D358n#\.Y@'k9kKGr,I:0m:=im%'YMOg!"+('EI5epP,>"708E2[Q&.]eE*5IBoueT>d@d0<@gm^HpSVhRJp&+)Sp4?!8gg?pZHc>DARR>R4$?<<[egDatQI\?>5)lD;7D)$mK*55,"$q&82d?JLKoodf;i]Hi+>o\@m+B*OrqsdFXQ[+IC$o.V7Zu)3kn)%]#Hk-DQs'TZddbF*Bb=co,!r?$=[^M-PG!0aUZ`o2Q0`fD9.l%&rQ`S=c9GIr8GNZS]o:2Ji"]>e\;ik:l++kTnpGB0ke'kf+=He/3O1A8;JuFW8N)q;e0)MaE0'%laO^f2!&b5rAtA\,e!$X`+;a&Igim94p9\IIb$s3,kE"Kr9Vp!+K(JN2+339SI*f!g!4b%pj_.et"YujSZU38,XO+jk#%m,B1bFWHVh:^!IL*2th-]^Nf_K?c*WrAA[FU(?Q,h,ROs*>hr-A]+Mn9GulFufLZl:/>XhLZY5NuZD*>6DK4>%mX"/pPt-FgCo4UiX5Q19m^[(ZXYIV4%mG!#_@nX1;JkC"ILkTkO?ZurE?rNL["_kct8)`M*X_G$f>Bh^3@5sHI2Q]:3sgPG^'A83LX[F@(JG%+kj%mm<$ndXJu:Ij)JWHG)1T'Frn;WemYqH+?3PG`>$mC@.l/mB2,gM#nM@a.hsZ>,"SI5<[k!8VIqq+R)I3QC_5oJF5m7R69Uc#D[5f]h8=C6A[FWun\L]uroL+,.L,/n>M1/ZouYf_s1fPVJP0G2M\.N-Y)t_^!t&K)Hg%aHML?N4]a;0@E-F4GG8/;6oPm&(E2mgurFUf3.qds!FAV~> +endstream +endobj +556 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 555 0 R +>> +endobj +557 0 obj +<< /Length 2326 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +GatU5=`<=Y&:XAW&Fu%c)d8Io*IZ+;`>7:K[[S$\R\F2#g(kfhXs>B1@"8*76rE$lnrYNpP53$>kMgGmr;(k#Io!%6;rW/ubF.h$B%6G2O*X@t=Q0R=-*_[/nc$9%,4`A%U1f%AWuLLLn,=,2N]fuLYNDU2%mZXS`(q&cpf94s?#87^<^2S6m#X"p8][:B].>GZgj$:/lScIpf>8)'hQEtVo#S*G0.K?Z:'j:RSN<3A(8W/:[>SN-BaMQ@X-S5mMIhQ:N0,C0*&cQ?\$=g45OT;T[rU?K=C,J#-mbkLoA*K^fp7r`Il)O!:5Y?gBIq!S9T->pl?Oh"?I&A4kA(+:W_nA2M^/`\$1nh%CRL*X.4WO7T@^^fVZJ.5,Ed`pn+:=CGQ)7oP'GJ/QeR_E:_pi]MRi/TrRk[_(7W,<;q0(&J<,*kLCr[$CIe:$&(m_EcNL/^o)oU7uNN',]\lTj49GQRWCKX9?0f$<\5D!WGtCb3NdRFoI:=;80a>?UDL>dVraNY6D-$gXX&?jj4nFA\/F/dd$eU>[F%#pg-F/2SgojB9HlKfhCH^_7*7-q>,cQd/a>G(B+Z1=5Mo)*h/<>mNs]@d+jZl@P@hCq^fcZDG::2r%R"R]'/O@-E4f64OShD1*Mk)4d*J#`N)2+VcMNP0J^S(!Hc1980q5e[C23bL9%X3<]_%-"s2Q:J0CSI4;blRYWeuef`L$OZL"29$pS!8+:RgrRnH/;Z66Jg#h7NYAQKhD1>:gTOZq2/*B$6qDL?XmqetV\/>=tPSl#I]o8NCF@MCS\1+s!-;=e[>%,DBcC>h>$I[e$bmi.7FA;=0#'JMkICc^Ea>^[PqT\a2mX\k.CcF[.fKkC"^W.,8M5%>Hl3&!AC@RnD%ATPa;eN.2`=#hVPo3!LUV*F%g0Zk1#BWl(kC;$%S*Dt(PJo_&Z0dNnSnQ_k(mt(joN:e"+_Si,h%PHYCQ]-l&pT_O@1?6ot,;gJ@I3L#^#aW(i(cA#Tu=pJ&loU#@V6-SN'XKu\j`'aL"CkeS"RUQaklN4<6K>48p"(`>Icb:6jn=LZ`1P)qBghA)TEbTl2sY^B^1aK85Zd-;G!=*Lg`IMj!1j-H>mmUjEo-(sBMN`9)@!2[0Vu]bg%:bD%e$$[.=4B'1Ysqd%&oJAT:f\*bR10YHR<.Eh3/p35#l)6]k1[a^b&ts\E`.>."j8^P7Y&_$7sGa6EM3r>coV<>7&]QT8"BAQFB9ljfLM3?RUP1O1i1I@S))qhrqAYpI^s<,Y3N3$o%j#HEh;IiHd$>:!n&sZr+fLq'_Ssk1(LTHE'rS-P-/+"p\dCX,o-=F-K$=_O-',M7)'nj4JKJ1fTJWL)5_HUB1&&bZiVV.<;Z05WoNS"hfh_3@Lo32TaRdpM`J.Ek8I^UR8u%?n4_'_aR![16G_'/h)R#$Y;[WP-!@U\s6Ul.;M3^%5]I3ok"I474CH.p.N[7eJn1LV=V[V)ePSL::a-ah>(ue_RD%?m.d`"YKdIY*T;6MI_:KCG<$tD+!aP[ih.2SB_g0(Ih=Lmn7j9qb>QY6XD@Bm]#gG?,e>(0=9O#BQ%j`&FjL#;&)_)qcgP +endstream +endobj +558 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 557 0 R +>> +endobj +559 0 obj +<< /Length 1957 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gb"/'997gc&AIV:&9@=C=g"^4E_Di(D:&Q%j7H4c"]qR<,-pEoe8AO`a*70KW0+deDHc\Z/oo']jpXbtH%#R)IW>7^:OfC4H5O1a92)pk:4MA9II;`$\+n@D.30K_jm#MA(e7YOe4OGdZU4+h578-OnZT_am^hp_btEhZsZe&Z.:>i[@R7fnqRa.uqI1Th643YZiGHG#M0.A2TKn>VX\jrs72&D>IBIcC6_9*ED;g`p4/=Cj=@'PGVT4!bR-%c.G$"7Rj`?B5pXKtG)IEhoFZcPNGMS,m7bfn?(1aC=,IU,5%K9N#ca?Ss8J(a#]]6J+4\&n^Z)Vqe!5QW"%bqAs5sW8$,MJ"qfoem:[o+ah_S>H5I?sui5qf6s?tHl5)Oi^I8SDV/H)3su>o3ai86@XbSCAj7p]%f+-T=q[5MH%>W.qHJSG]Yda;W]iCu;P(*f85>&qB&:4&M;=;GFrdPAaRnl*tZqR\=dBqtr9p*E[C3e1'WX^6r>UDPq1)SqKM,?5,:EI1gmaH`N's/mcf#kBrm)8TOIap"Ruk&Y9/s;A;FI-iH/mL7];(SO/F$fFRB1B[\C6#l8KCO5A-)%+\X[5@LKdHj=?6"agH<@OhkAbk/W`&!%:,R`H-U@cH/Pmh9n]<)&<$Y)O&]q2?>'eY?E'f:E,D93%3&?*GcZ+Z@u]Uq;V#W+Rlu(kpbfn<9\C.RY^3=VUKY&2.A@94<:2laP7%Ir)e[ZZ&o_D81c(hi'bjN[fRYNZtHkaYV9;mIlfV0Fq$7lN7Z`)%o7qIliu+nS/A!^"1AW)b!$A`G1dkl1a1a=qbDR$BUi?e^5X&%,2*^=Obi1HSZ'ge^qL0'JB.@J(JLH3isIJ]ZrOPU(b?die2f7q%ppE:4MD;H**e4'.hpYFS$K.M!ks2=g6&`+>"^?\fq]FW$e-K6^hrdVR6#]nUK:\)4B!8^5,o/V3()(Iof4HB4pP82*o_jMU#-]Vp?`;KTDk!t!5;&el*ApuQ>jqhY8qqQOqN'=jl:^Y](aWF+O1(r]r<-KW'*QK#P]Dk&j+G.$Z-*+[12LO:I_bA\,0LC)0%##oYa$I@ +endstream +endobj +560 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 559 0 R +>> +endobj +561 0 obj +<< /Length 2740 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +GatU5969,Q%_h+-ppTFe%O6gVmOd6dApSW5Wje1__bT@08@5K;>B9&WM?!N@U*p)M/DE%I9DFnT5nNqo:nO>_DBHcMlS<,C]Y&8#X"/DQ^n85X4U8dD8Q`p+`Ue9Ca7[oqBZ0d45:le=4T>J7aXB+U"T_:m/2RUH^X#_nlfnDbJL"rSH*WoE?Qh"Ap0)'B6MbFn#0'h9Lb!ssg??BU[:/"[C2/j$FVT(7d/ZtRc?<]t7Pna&%bTJ=f.W>%QLTH`+E)Bg82s#nuQ)o1@;-Q]+QFP&/k6nt1'(D948s'O7P(o8?9W`nX-T%H^DSVq>2Jk!(<;s1HBQeh=j:(L7XNpR&k+^b&9e0kLCk93(QFqfL@]pUDD^`kZbs0b);G][GsFY8j2bPaG14Zu<=$(aO/SR;8Q/.=1!c06#!G(UIIERekm[t5Q7RCn(N\Q>?r>%bo'/G@T:YFq^u.s):01-19*83'89Ogp`':LMsplg`'d\F*,1AXitgZpdg2)O\CNc]rHamR]\@5pes1QJU;Z-:;&H._O5V11PiueM88h4:'Gr^`6\g8OV]'Vg&-H2D,;71"sIDn?leuTW?iS>.EY>cl'TJh_1r^qpS(#oC*ODNb9=mG85XMDJ#l5[Gf[d1]N>A7q_7'h"sXFKcNY:9g&SE\jb5"Yp2.fkhe9ihN[pN`Q#.f%4[u+uekoo\k,8`hO8?A;c!`K4S-m6ia9f9<3t*e7TdpIqkF\3'#7$t0C"%qK`NY=+eM\>A/N1t,;Tt"To>;D"V_#-WaZ4NmSG%paR@KlCF]$(=Jp:M_l.QQpT`e=>SL+,`EK;#J',32K%&GuAT\0lV:oY7#FN^[^N2VJ8n>06\hk?1T6(g7_Y$3_Gc;^W)m0W3d:jZYV=0^kkmT_EA#7mBd4fVV,h6rLF'ptZLY%GG-Ejb?U0@dTZ9c58aqP'^9*eQoNN^q8hf=e0]rJh$h+\`6?[-hh=3"OA'Q_Y44Ia,[E3H=ca2OT2$1OAH)Bn$JE.eJn)42^dN[e;"6l$@@oe1IQkXmGlF,u:/c:PB/OD-+'_o[&rA7hXuU]R.aVCiN+)^u*n'/+FKHfWlktBb/%ODj<,,ku57@QIVtr3Ej"K!P3[kn6f-hE0+@)iFK4Ml@!nr76V9d_Q$Z!=j7@3a"'gR"2;2ElS=4(@k;Yq<8[-\%PY)++HlQ]4Y*8WfTYQC?"nr(ANG&%9l0Z[[%f+ckgJTIYTf%ORBC-L5q#k6cecNC&gPT9C^WhS"h&d/4pPd7BtTanl0^,2Rh-lm08B?6q)W^U$4j%nOH,,\;FjY'7SnQBk:/5PLahYp!dYs4&*&'lcu>B]T[+<D#AT#SgOpfq]Xs/'A'q28&j+R"siri$QlU5aNHP%"VHN4;"!)IWVm0tg]E.f@Z6`?ZqAZN+g5rO"*.8lehbZMWh,H,ASpMbco*/kGb,H/^?$3EX1QK1e`'\K-h+:NlO-G[f->08>$otVQjlo/'A^Hf;HN+,?rhA8R'@U;WWc3H4\7kd?fiitO_A/(]&3omJnV:Zl?2nlOh?3V4)YV9VqmoPXgOK8]5J+DE'E+@JAVn?b&cLsZ(ue_GIt.)m=@N0l)8CED>)Te[7)Dlg^D[.Wp!1fm>*T#ZH/p;C<^M_C[opKQLTlBe9s]CHmgS>qMJC<`7>aDOjL[_3UgHp?p8+aB.UG-'ND#Nlol$`lQP;;'h."%:7)%o_82$(i2`aN<8?GoRN66qRi"m"#@`rE49~> +endstream +endobj +562 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 561 0 R +>> +endobj +563 0 obj +<< /Length 2061 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gatm=>Ar7S'RnB3csmEiZ7&SZ^'n_FD-5E5&oSW6ZiD]*[SU+)74PHqrqK?b,kB<>jg7I,_#2DtG^+Hc+6aTbMoDk*=X^QrCUq/uXN^pS*:\fcckT[H\@*I`eoGDO\@eZ[k.8s_WB$B0Z*3Zhe](N,7]Lj'lGe+$qht)#*:_nsAP=2gfh9Ie\R\hE@8c'_uo/XRNqV'?Z\]\$G]*Q8!V7em/O8Z%o!L[u7WBZh/RL-=e/e%M$OJ5"Jr8Y_u)9PUVcF@>-kcp%E*W)6TGb7[PPZti9@)4U.%\4,bo2G[cE[DoHFWZO[N$bRt_C:LE[GCf&`4Q;i#PkpL#,SOZ4&RF9nZ-6KAkE@?MF`?&'7h1MU%AQBqiCa%6!P5u>N3]^LaUE+4)4`HGe7g2QTDf'l-tC,0(CHlT0Hgegg^(#rTA*6O?==OU!.'5\fh>1IJ=P_D96L?Bs`V/:)ifO!J>_R:K,$AaL93Rg=ub$(a`Hn3H?8=J'ciRtmfBMRk#^G[Ea?LAtY.%A[@aj@@&!T#pVQjXn6(d*qbR/G"h8BU=h_n>`6Vg,9P&0EfI>)4XgN$1_,*m/^*tjiVf(n`_95@PGYKsa,;g&#^$T>TrnD_W6S'=M7GrSK!k-+:.La$NUF%JG#S6o4lgKVeD8M`kAt/^2LWpS"^P)\D\p&koT!7RB7tg`mRrT7_fQcpRBs5.occ%&OtT?pOt@E$%9rJf3+m/[D!_*/edOC+_jW_>.ZF+(edSA"@EkA_W:5*9CBehBZ"D==oG[3Yef<=%n=^3Vi0T5!Mk^gm9lh[2[>(cA)3WrnJE0+5r,O=h2Z0:^Hj\6Db"3OC/t-g,QqVT\p68)/j^$ZKqF8smF"W<#!`r@j/n:Vh$oO@pWhEL"j?nk?L:XOjC#e&tYTOqSl\q$-DP4$4*-62_4^Appe,$fEc5J%@Z%3Gj`s(9dTVWKAg:(LhdR%!o5(Nq[RHgnYldJSEZQ5UN#.Pin`Y5uLX:%P`Yg<([,,B"s)PF%9#4?01,t5gslm_ja(/4:?%3'Ps66t%3!6Ka%L+.)o3mNgJ0MZhh\Hutsp7)Fn@^q#ce#_HG=IfftdRZFVHTo^,B8uA9!7nlKYrcs+"'hbR86*u=qbo*>BiUWW>eB>cb_04k1nKQ%7Tk4Ql5tleT6^&2@q9r#%qPbHRbAkPbMg!mD@.5U:K(:hZcA@acSH.Yr"_Nr[18'7(&GYRhpOP1q6u\/=.;!9kkBQ(]ah!/0lPnq0=8Whnh^S.SO50ds6.j+F$T"1P(D='qX8Zt"*3ReN!QJoq2Ue%$l"ZhEi=EYNjW?mn3^IXMZAcfRaY?8M&.l_feEOX\kB33UTa7K\ESK0(rkM-U0s,O6RBHQ?@;!d8s)?3?u_nV()PjfN\"%BXI<>YMn^lN/Ci$.A@k#@F5%BL4B/1eGE(M]_C8cphRS*.6MH5;`RV!8C\JcG1h0QO1BMB>_MYem:>=\e/ad,fr`r$.qB+@b0qS~> +endstream +endobj +564 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 563 0 R +>> +endobj +565 0 obj +<< /Length 2392 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gat%%968iG&AJ$CBQC(.j3T(Hp<@T?c?,pYgShg83C"i8YpB\kKHe%W+5\A8!a(8AimEIl`%IAQm0h;ro>V'EoI8OZrkRZr'UUaDJ;])@k/$h^qok-"a$6q(lC'-GCC^^)_Ioa\&1"6.9s*(=7<>s"!n=\6i;q$&WW.n-;KcXIqF=4N1:\s$C''(`+=drOa[2:PneDde\AB!/2'H'l"pJIGO!k7fr+n8)qdbY$X0Vb;sT%9:iI7S:.eP%;SAg0RDeegi$pJq]3?T;+\m"7?Tb)erf7FF6o+^0LUI.:GC/h`FRfoKd/??ooj:`+$EX\f8R+4_^4\^p^>>`>12(TP[1,=n1'10-3l#PFi^0[8-i'\4=k;n:<=VJ9mer7hH1`/SY\MofOPS+MTh\077[D.]cVhN]+;QFf[/jQs^P@ZJ?';;Tq?W+Kn886Br(g>]An'Ig@A"-(_?K$`5)eo!Yi\[(So1&B8Qr0QS!PX!VqKDY]a2AGX;YW]pOa>Sut;^SR;W>>'^#8GmCIP!J"n_oN(9LNY=qUg:1ck?ho7qKrB1."aB--/qmt2@k8#5OFl(6M,NGp!krG8G\$=1[anrfKqq'4&@eb!.&XfANK_F#IaSe']R\B#h76Dk!LSVP,BbOJh^,ull#ZaZBBB)SrfaBJl+UI^0Cc_hg?7KPD0C*Nr8,g14)6IaOiAhNo,Zt^k;Q,ceuZPXU76m$pJ:dXb>q-ObOcJuGemc!*TCcer0K#&fXX*fIKVe_^mZ<_mk8TR@ZT_+/bnc#2F1$L,R^j+IG_(YD<%N@cMq:H]9N$i5S?OgY0S?mi`9LUgLXt%oprJoo\A1kW5%.k0*[8'8;:+]008tqFjr/:W=kbeYC/?IQt0\"Zk2q;S0X^4M9jHsnC:X8&%C#J,CP=WY_5%f5[WpaYb>/S`0!QPD;IE]mtR5EY9%;-)t_!Q\EfouD[[Blc7/ZF2Ik"5!$PJ[_aOH/(5a'i.MKfWk*jO7)lF_el;#5N%#ZmA\"4,m^:GbH@U5YNpdaF]BC739o0Q^FIT2QU>e[MY$_Dt$tU;2e=S3el,B8KH)La3'ZWOUVZS))I#`F:Mb.Hl?J!\#VZ=L+s%HjS[,lAl3Rri9g]A"Ra90T\$Hg#,ge,p#t\*5!Rmn1i-2j4O.VC`&k4RJLKK0i`kW:WpU()5.V&0@IH<%ADA@0;0XqCK]^,nMS.M"tYM%#4@Y$+h?VI9bt5?@mRX@QHskN`-TK@`G'9>Ic.8_/!-O(SurE(!G&/?,:8Vb3o1Jg#oL?t^:TLbiA%(l$hGMZCY>`356Mh0Oi8?X^o'(.o,-`l(O+hIJTE86PYkp1TpUr;1(i3N9)@#jGdl0S%B.UGuC]hdc4a-91.d$UDoSDjh*j6D'$i>`Mlpq?;!W^=fu-[k(iQ?SH!O=9]#jotJF.l$SSu!42=VC!MPhe`qF#]IatYSm=$=A"?W>Zd7%)RYm)iL$cTW0h^Jef>I4YDa/]]OGImAjqBJj6A,/Z,pJKhkP);s#^n/EE\+-:0[%M:1o-fla#);Q%WfmW/q$\5odb1HEEZ7oljk,r_&$qmcij:\,!>7LNNWeSn/5`S3R#b(-BmpP9^pi>dY-4D5;(i](4G=S!+WMGl+2(-';&9VMbUM6,I.;cd695+-iJ[2#4T&!aYL?A(KTB!8t7$KDt[54E`$D>(jG]*M+OAL1G%\ZegK4)1*S!6r7K)>i98I:F^X12f2'^<680g[IB(r_c[T9dAPJ'0g#GSnAEQJj?QZqWc\5pIf;!$p5.mYVnE>\tP&+!F?BdB%PqmRL(sB>?:_sgV*S:%%@:HC'[l4d*LGXqE7''bfQCY7aqAG/>VV~> +endstream +endobj +566 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 565 0 R +>> +endobj +567 0 obj +<< /Length 2658 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gatm=>ArO[(4OT50FB@m!#\8#DUuHpB2\(IOCYf[]sLL2ck9orYt::FOpS?WILd`-jInI%/@rnqc6o1ka`F;n?X;IbO=nD3"H-9&&M,gVi?EfeE"ULu^b!Pu(1iESIdtVCk?$?@05n$0^FiQ:"3,_!*1;rmQKK;.0A^WT;U#H?Y82')^^.Ze3O!+Be#8b1qfYo,O+ZB_<,cJERSsh?`SQ&PqnnGH7%/31s&$*3T=$9Vl]M[7q20=..RFY2[o)YIgfC<*:66k0Z8P"-[]FFWoM]]paG`oAZYFdQ/B-Bt=L&9HY^+j]J2EY9BQrlK:7Pap9g"sf1;bXVtq3j4EqenmV?".(=#L#DXK]kVdTH]6pH6qND-XL=jXX,,elA2K2[QPF.-X#\&0-.:S[6aLDPG&4k09M-N"?UC(D"UeMC@TV+`@B6N.>;f_Z[R20X4n!oQe=LC)b+aI1?oucKFrhH_3/J:[ER)WJr1#B9mmM$Z16$fTA'?_W!.SR0_D%jsSjFMIEc2qC5N6C9J52&WK?;8pMVkd,ND[6#H"mg8hL_Fi=-ArUsC]nHQc0eo.G3-;/0Hg$sK-F4I=+/[6+]D.?.n6e*)n[EshF[a'2qSQoDJF#dSYd/1X`c_NZ\(3N&UYUD=I$OpR_Zsk0E#+j\Dd&&;.es@ChM-#;GS)OiPYB:CRfrdq`9o[cSDhA[qQ*qUJZiRX&+]MNtn(-2m^r'FCZX#<%:#I*Z>KD6Jdrk_bG#kX[Z!M)u2gfWg#m?BN?6V:=?OF`6q#f?FXLV5p;ESF:^Y*g3]Q/$8M?C&R?F9AnP+5WD*h6]G)R\]iTLqH5f%WblLlXNlrE*TD;$Rm)fSYq8K,T#O:bW:%QJ4;qc(R&1(6UZ(^Cf!4fYr6BQ(j-@TZZN'BXgn4X*C#1eXcP#b'Z!Pjc=;7ZD)8`$9>h/77N3,+;faH7M2#&dl]Hp<=FO8DE*R)No"!3Yl"%f-42`(qp^L.1>;4*5:0`7X;pS0'Y1Nf(!DTgFfktQA[Gn+[h)C8d#]3k=,@^3ZB=h(l9*q>KD!Zh=MhmkEGPht+oUm%Ir45iD+$eZW'Vf!0tLo*HS%Jh^PV(1;PX:3M_[GZ,qo7+">/ilqi^GNb&V\k?s?k=d+)pr540\KoOhKdLD=&`$T.aWVmhZjg8a9qOpGT^!I9$ZoHs:8l2V)?H$ic-/_04rqiQMibtP:,ZWpdZ2eDU^93l;#4D8lDE3iR5kb/S5>:]VKcTG=`En)T?/`kcLRcPg7CpR<<*2Z;TWoob;YbCuinH4&36bNTiXAoO.DK.*Y+keW@[\a5hE3'*2H?5>&bBeC=#q\a.%*V2bEA8&VjYW)'aI\afjYm#R>=n9?S!kRo^+R$M%VZ"tg-UU"V!*lJr7%:.Ob!BU,/T&]PU/5'?bbO3sjtq,D`G$Mh?3p-lA)f@%%ZDDaUIK;EOt98n3uABC9#<`>()o8U=(biU,)B1/*+*OY8QI6")gW[L@u=FH\p^`,pMh,/ib4Y,-sHeo529jo;,?VpEaSq/r"buK:QK\m:S;d@MfTNY'Q]gl1(C#2;_rh>a4JH%hETeDHFU`'?i>0JmdBf2hrH0UZi0fH$/b40lf6N>B=CASWs;/.-Z?#eGuL9g/i4Vp5d?RL2cpn)6bNEbDO!loB^4PN819>/@l?sF>qNgkYRS^:0[qOW2BAFm\1gOQ;-Rc^nV3XT-NMtg4G4nKe-Bs7Pc-]*SndTNG1sE&YT"`n'Snnn#;h?=fqGRIU5Y;j5(L.4098%QP(`l1F#?uOjg7!@=L86QPA!45M[N9D7]S6lAkjVVeblKa=Q%8kE_&p7)2#T1"")@:59NZ9g2WMgpW=f%R+oN&W%F<6C%6QseaN^@nI1b;6@Y$E9%S*^Es3bGoY1^0mURA2d0sm&YB5Q>0rYF1d%CZ/oo^HLVbSV&>71TnnDRSQm(FS*9(4i_"SuT7^UgL(T-EqQr0,rcjWpT2?6FHRm>c!NO53.2EKG.!lbDf=aQ$1R0+=WA!mCZ`Y150f[=LI&9)o__Ns:KJ6Wk3G*iH5,0Q%Eg$<9kM(bGKIlu7s+6-]VJb9lqZlqhLT3,5IV3K=1D9``T2/`AZ^*bEpJDdFQN*;D:L-8p3o@(mroeg]mNO-="(Glk%.8,G#Y;8JHr42IrSm^>1U05Y!>AZQ4$Q?1m*Qn9Ui^D6O1aIu/.+b\QE>F5RP4hUis;_?0gBMB'GqgioB61=>"S_tW3Ck_~> +endstream +endobj +568 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 567 0 R +>> +endobj +569 0 obj +<< /Length 1402 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +GatmJ7^$H_;\=(++s28EC)\5CSi3Rljo`jKo2#QjgaAO*@Mj:B!5B9Y\LH`[D7-Mb+a:-TDD!*tBt2m3W?B`$l4/lentIDjf>#leq5>p8`nP4_tXc@RT2YK&0i>2h\TIY!,ggHZXXomMs4q6$S1`;qANVeN&sI6A/_Po3;pH:cRg+7u6QZ[rN^o>ZOuNp%2Q.WSa:0`qE74TY$0")(7TO,nPkq;>?W=]SAsfh$,fuX^cK\kKCo#?2`B6GN0o5cT9:6[b!bPK]/[CD#>;*GOggP^*>a2'hbro=,AaWSfFimugfQ&i83iXj'cJiNXPNXuYS,?H10'+J@/?<'(,KoVml]Bha1S$KS378KXoV"Y"MH6:k3SMY6/E:0n(8-h:YGh_o76#:VpO6"d1?n@5.g#WsQ+gbSN&9;88TlNaUOo";D?#bg_B;R]9_#Op[OdU[gKK$mNp9i2j0bC$gV;(MW#]srnbR$Xp\]9mJP32]5?o+=!YZ)n<._i5(lkp=mDH1i*g[IZHuA.Q1JV`<@nH>:EkPG)i&lmKf\Mb'=dA!at:lA,H(-<9.khm@`Q>[cZo593I&@FGB9RhWhjV,In0g[aM!PL\RO1=68)RPTMofn$O#%SbM@j9Z4mT?XqXf3Q,:n!jJ!UO)+]b!aBqf?1fh95_1:8[e>kN02@Csi02o$!i/H$)L#'mi~> +endstream +endobj +570 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 569 0 R +>> +endobj +571 0 obj +<< /Length 2173 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +GatU4997gc&AJ$CkdUZ+>#HOj0t.UT'J5Ij:#0-E*k2u&'@f^8*o7b'O72:(N\&@['RNr'4>ZnI3)@:n/KR([%](dtl#S9?Igs?S&e[+lAh&j\EPX"'>EW0rY^O`$p":$*qJR+5QeG?k)Wj\P*m3d$QaW'D,+LUc%EhXrMjIb(]T7U!dMG@VW*h4a!&-]plBs7BN:\hY!'PR,`U[cYsDUg:)!=3t,eQbSbY2]hVbBlZbo5(Od6Dn#il0D([(*n@+a!8eC5/iu)4?QrbRKjtfgT\usZe&%A\NrWge73g;IZ6!c^DHZ]9%9?+G)XupZU\a+c%9).Ds;=?:Up>HNc0MOiINc$C-p5:hKL4_^Z`%E]kVG4O8%98[>IV#cjN=eKu6O3G)9(dHD`E@,>cQdosh&0&qlq[Ln6p'abV;2NocjSd(:-&\a.Hq:>^<&n1l%K$cU%&7W&0qg6X9IjBVW`=-po#2hmWpkO6u*;g4/O=^t*L2csS]>LpI.49ZfCPH\0-9dR=V(6Y'NHlXcVO2@R>OD31BK$Z?tgJHQ9lipEI^P+.piX2``AYIYja4@.QSu_`=r_)k-W`TXeso7WGL-u^A#d-J0`&B5-t(R;4Y!$KT^a7GMnkMXKuZMEFdbq,?A*"STK]MTVVWA_Jhl0S/ktPC(LU#[aGRAO'Rs]10+2p\25,$l=-=MIhgucX\EojrqF#(rcM2!\5BHdXK@^";=?+9%BD#NRHk63"AlH&,FC[BFDE\1cK>9mT0@l_O%>M[f$nDjOO*.Tjn=VIq(S)h=U/T\LFGYiNM+;_(WgmC54C=Ig-sOSl*E)D1#&g*%F>1WlQLoIQ_(/5U/P"c%_aI?d1[rm]'Up3,I\<7/qG@f-qN&=ULWKXUXXDCq;M\"%t#KDd=T(dh(_;,X*F0fPGt6TM+EN)/%3t)or\9D4,Pe'u&pBf7K%e&D]ldHHW1i_%.A`ZNEq.EEaZX2$lG3<'PTsfklnWhJC!RG$!J[fs5VJ6="m66B01M;AO2eOO[?8U0[)k<&XXmH(hKY0/*CX:qr6G3n\&n\H-;m4"AR:OBr;mTQ=sm_bG%8c!1.A`ek7n9c"IQQ_,(V42D#Qc)2:s!pa"n;`t6VV[qrGchrQPS[Qfg3WIHY:)M';UL$-.\Da@W[*0PcRMC'JQC^t=:Br]_rd3Ld3<&%'6VAN2Lcfj':Z^!t^+(eO_'Ss1==emU^+$X#:?A("0dUl>lOHfN'L.T:\Y/_FLEjJMjc=69Z"iUUld>#?T!u'#<'P%3f102hNQ>+h+-=?s1hZA]!/10_GKKE!laRE[G1Re:FC[4#q~> +endstream +endobj +572 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 571 0 R +>> +endobj +573 0 obj +<< /Length 2450 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gatm=969.'&\e-Dk\-l1nGSg1GeB5VC1_5oHT-`Q*Zu(0OWb#`$!LA0IXE&]i$DOsUiI,4U)T(]j6LUHror^GVlN%cgs,7:F-4(+]F75u0_"&1$bq"n.Bi_jF`5TaZN,\,k;f00NTU??<)1oU%F!ILRp!ED+[8LU:X/%rCQ<+UZaoZPn`@>**#FuPL#AJ"edgnUo>g"Xn$W7rLU-Xk$7j,9r._2m`X?EX%5[$(6s1)IB)W24/T#]i(!bu9DU4OR;\ZaX/FuF'#?'Qdjr^Kq8E&c'fZQ#QhDF?Y+=6"l#p0/n[j5.scRe)Q)=j!<>,88k:H9l>jZrt9akTR7]k>5j5WNUQ\f5uYDoMXkaX\0?UnQ,dT36(^29!WeDRu8R(b:U)^,dhB0te"9R&q=cQ137.)J:IW_AH_f+,o`U(di+u\t3bSdMQ(Hfr`7!2Vo?;:N0_B]HWYr\n:gg?8V:).j-*,n@!&hIEfumUuf9MV;c\H*T8:mP)e`i36i:]TnX<"Z4LLDcLG1!Fkjp_n2oK*<:Qj"fhC#aq$+s^nK8lO1N^QlCn`1@Id"u5r[VDa)#HL?&)/mklM4n?-q[>L/XAS^+n'+m!pRV599DK07Zf9,dZt]I6*A!A8']hRJR),^Wd3'rETis^Jc?^/VB]@/Ll&nmT1%<4E7nQ*j_S5d>L.=F%.g#m9`A)/Bq1(mh\?jmR@8SE5$hJT9LWWsHd#W:Fr;t(&Yp=Dl=51N]M.=baSh+j_ki0M>ndO;.HdH3\X/Y?!YnE?Ua'_Bg74>Bq1WfDSFrTm,Mu9k'qZt=Iof.V7Xc\+r&?rUk*[,+r7]N+5WNW*/04qUPX8#bB&N=pp4Q\^Ur-d;$@s^[9Ok7g`T6i_Ke(e_8_)VPl5,?dD1I#/<]RH6$iZE_@&*WM8Q^j37nlo$`H&RMS%]M4nIEEq=taDel"]0D?Z=an3C/Ge3@2?`s8fj#lF]E2WTBVhSI)n'M03Cr$W)2=_atH(PO!e/egStQiKk)*JFe@?$YhlT%V#L>:/Pd=+j5h7ghOr'b9!]5CDDX_*C9VkjiX!YN>3a.=ZZsXNF-?\PF]c!1J:'XH>=^:A"\5e`i`hMEWQlmk--.Y'9JX#>/m?Ml_?RCM,8!@JdcbQP/A8bU3BNP#,luS.+QL$I>lG0[);JJCX]Cbo[Xr#iCS.JiYmN>5/s[lCN`Xtem?cEQ7O,5o2ZAHKEW@+m>m+$hs`_g"mL6MjNu@@qLbpT@]1VM787]2)Z2P&#Oa;H+]3%c+c>Q;%CN_^)\SJIP/r%H1u5Qa]s?/H(JJVW?#Gs[/_P#)5)Chn;sRMN$H\#@2H;9*h&'h);s\'>:-[=hink:`-MY4"pVCkCq`UCK@/9TJ'(/G.S3N<`/nE*gbtP6i`ISpo/K4h6ce1Wna"0RGE4Q\Q4=qXM;&k7.S)Mpg;qkB@aIE^i=B9P_VQ)Zd<1TMqk''laQpUOhH-2\W`K4_]$<_&R%]rIf+^t&*EbCQakAbQ*>l[6r*ghdta.T-L0keX<$g$n'?6>Qq^HU,):D1OO9c-5V"^RDhYE/%\!Y>*(#]muF_"++^;30%a'RgbRaR]A'E7K9_lE;%3EBE1VU`"0.!jEk3qWCF6J[kiC6KG9RplX"s?P=u]mf~> +endstream +endobj +574 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 573 0 R +/Annots 575 0 R +>> +endobj +575 0 obj +[ +576 0 R +577 0 R +578 0 R +579 0 R +] +endobj +576 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 598.352 640.416 610.573 629.416 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A << /URI (http://blog.modsecurity.org/2008/07/modsecurity-tri.html) +/S /URI >> +/H /I +>> +endobj +577 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 90.0 625.016 334.761 614.016 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A << /URI (http://blog.modsecurity.org/2008/07/modsecurity-tri.html) +/S /URI >> +/H /I +>> +endobj +578 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 481.534 157.816 540.494 146.816 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A << /URI (http://www.apachesecurity.net/tools/) +/S /URI >> +/H /I +>> +endobj +579 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 120.0 142.416 174.692 131.416 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A << /URI (http://www.apachesecurity.net/tools/) +/S /URI >> +/H /I +>> +endobj +580 0 obj +<< /Length 2262 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +GatU4D/\1;(B0n4@2-VF!!t5LU0dc^H>pH==P>;tLC7AE%BMtP6=eN@W29dmj*)b@VF\I5>Do68,P1CbLZ_Z%5$a-)OqG^T)a,c*][?9OO$*2q8(dP9N4fqE5s0HsO8a>`^K`4qR>f0>0/'9`6E5pG&SGj-Ks!m(,UNdE3#Q!sX/]JBHte/VhY^tg;jeGd>H`q,>1-;(RVsc/'7R2dfm`_F$t[Y4:;#uSo8QNcA>&SNBU_IHLYM*bipNEC#dAH1H6^U'@#m+ANt)DP+D5,.\E-aD2WQ.e&Gc%VBqACs/YaG?$b3#+E`%55*b6BrQcqqM*U=kLE-pF:].Kmhb5%=,f:SU.Flfp&VthhmQgQ"L27g+t\nAE)$;p"5[ahD@@P_;g_+!a\S+mR>&[=:Cm'-@#E/(n&;0.joQ(eWr$%D8c1jTt==TKtKD4CWIHUS(\:dn/iRb2MuV;(2b'a*9HmQ=.0fep9PJk6!_8#FDm\MLM%b]P@Ro.s8:g]C,:X1.d$'M/=sPR&'674;TY=U_e&)70`bBh7]\,^S2H)Q/$bKO?u:C,Ye+.m*T5STle=>':Y3+@,dq0_=k$5*>>9hdsbf43gZqC-9HqT4s(BtSNi!>iu9e_@6A0b.p+\.+7B/W5MB6WLlZ7GMt;2q=;e(O-+j5a.XjNVcQL#Mqe"AiWl2!>YPIFfP.[`t<0Rn6@JKBDiQ]erIH+$"*u@JKY`V3AX@,>(6M@H`%J/+pTVeN6V;oQg$Mp;O,G=#aFr`[HL6Uc!kQgKp4UH!Ml!l=prXhK=rV]]?Y5?^WIpFqS,bX6&Dt];!Vsh#Z"fg77$9Lr89a8$mse4;LG6\k]SjD>p*75"97NG1nj3*mkfTlk4D>589:7%"8Q>QPZ8B94qIM56T*H"N,Z%JC:7/"4*iP5JYWKOh]_D-]iDO]sjM\/p1e0op17V1nCuSmUpHTi4k>62R(TI]:mC*Mjh+',WiD&p:HAJF3\2GS(n3^el6F?Tf>DY;7'LInDC)GH+j(AFRM^sgSd(&\>7e6bE7e0g7Hj7%''E+'O,L?Mb7R`P3F=')k>13_Ht,^r9X"?qHAM:c@W$egE<;l)c`u-/,u%-b0d=!QQrp??]KG:]bG2bHNVoikcYe0iDt"=dV%4"2S]kPRp,%D>Y.dGSJ,bP(4!/5oT]hk(tq?!T45Y:3QXn'aPeHf6W*H%/+#1br78g)d`d66CLmT2GCqH"bZn;]Gi>Kl%Or7^M9H0GHjjRFnUYNCC"7sU!%FA.I1>kYs'.=(#D9>RCWWT9i76d>=r@+[Uc6`%c*FHia/Kr,oQ/;W(N"KS`O9)pESW:[ENKn[WX#`52U-FR4lu"mI_s^;cKtM_>>Ed=erQLCKEd*$WeS,\EU%&@P:-p1K7kQX_^&tDOVRgU(mE/K_LjXB$q1G,duoGDq;UHX""dX9ls\cc7"k5)XPaSHIN`n=[NFTPhOgE-E=eQ8J,L@%DmO4i?YVgr5B'gm_agW-Ou"/H@I;_Y[lR3X&gP%%f.G+[Wl0f-<\qQB]tKI\nU7:d"%6-!#A;PFdPPS2)tBGf+[Wu,O$jWA]EF~> +endstream +endobj +581 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 580 0 R +>> +endobj +582 0 obj +<< /Length 2120 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +GatU599\*g%)226E-'.`Y["j`\KstYe'945GMUPdRN?.![aiHnUIQ=(qgp"@&rbCb2T`r57"?BcJ02>*QWLY?ahme/[off:]Z'$U?[2(t?hf0W@-Zi!%F`::\+o._0@k:]DdL.[r4?)1#+G(X3GBc\8\tc!"XGGOUm-8-1es=s!V*S?)n'BRadSr5hEJY/#HaKUNq]O@"a&$oeK.1O4kEC.N!OW"b3pe\+XZnPe5^LR5.Qfl$l;j(^Uf3Qd)qu0i^d[^)0L38".c+;U;/bj],#2i_RjbrGfF]HUWK^GUg0F<>Tb$b\C3>,EGpWPagt9EY4`G)66*cih6A0/6L&=_a_=51&=7iC]dMlYmRQ\r1M\!8T&`i_YEe!d(?ETJ:t_49j/q93,,$R-]VE9H>p::HoAMlDeT4>IbE-nb8'QQIN0KY[s*2C+)5KF,6?R?[!3R2E,`"/!X5O@PJVl0c[-moMDPr_Nad,q4o>#+S3?`/^cK1ON_N[g8Qgs,bb\bAq'V:7W+J/MpUd.HaP.<$),#oTC?-h>#5WShaG(hY:QS[pBhRD7d<5euYdiZ)*4rk;rSA7Vr:P:`\]Dn'TYV'jcp=.Q*I9H^,Y)ctNraOQ)As=>Cm^tTdN(u`*$^oM>@q<)5%-u6_ZD1]D%EADD8jO)dK*FdaM+e;`nJGqejV:fHKa1=4n$Z!N6VYl&2ucfpf4/ORN2<.D,1n9[N*>b:fc'=DdJbdBog`m*#c6hphSQknl0sd][l8Haq&aS\uWHG,/1%]So5,c@:Y5+\S.uZ62ib_0Rg^6X#gQZ2c:AoRs,8Uj!\&$Xb3b++(Re-8'VUoFl1\p??T(<.GMB1Y%P:?9RE;dL0>dc&TZgao%Rbqp4rYQK7fs]n(M3O!E,_K@F$"+,#263W~> +endstream +endobj +583 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 582 0 R +>> +endobj +584 0 obj +<< /Length 1846 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gatmk-LQCn*ZY`']oDJ'[qGJg(1kYA_2UPjH+!hN0QN:9]p7mi=%JVrRSsu#(8\CN]]0_Y%slXo&B4_bEQ8rfhUE$tXYrmESQ0F&E/,Z*jB+>$Z]oHq=;!k7+#j(a2KF4A*Z'guE?aD=U/A>Vh^H)]RqZ0a5e&NcF=j73c)[i8n3c9JGg)YQN0YY]D)X_2,p)*Z>#P^2<[SpHaTP8efRb6S(bal"gHq^/UuVqn>@'\TM:YlmJdAEs$:$XU'=Jf0\aE`dEj$::*0Dl=NQ31t6Sn(G+%U+WU)V8VP*V2_r6i6/DG6bo80f>0BhT&;OH?D%\-FH*6W#Yj<@`cOjKXNd\k&kR![$9#YG"5b:b0iOh-P4EKR9o&K=9"d33[D:X=HQ6OF6'S2+3+VX:([%>15#-!%@pt4f(?_O.qf"!_S:Te1BYX)cVf>8$ZK>[c5/FlO?,FZ9-\>89b1!q9:udk68WQm7UXdEUV)JG,25rAZm7.<^`+RlLq_6h7?V#o=EA\[SN\^CC.Z*5/t7;&s=_8>ClQre]Kd+Yj?*11$OEuS\pQbGIes'iO[n.e$]BGN5bk-?sNi%^\[T)$FCfs2u&(br*o\XW+[\ll-G\3u]40!%Rb!2,UgLmh61X0j19fD7a0o"7]PN*!,*!RL*6V?%EP_\XpjS$cI:J3f`eb8-1$5'VYA%-Fo6>Ts28M)JYO,K6YtlBL!p#+HjSb@MY/n!c.M-ooTd;2-RYns]!3GCk"PAmXl'O?Q1:W'*Z;)$9[)H:$ZK_pAhBgQ_eT)&=^<>psol=$e$A9!LsaE%!L0J%l2=uH`.]Ei9!q.*"K^t;ZMV>CRG_qes(G@aSobL$YWX_J-`GaApJH4iRt7-$&#J6.#c2u",@F-'fKhQ.dc43Y/P`o9@g(QfY%5MY.FqKsf@Im(F>E[^'3&"91aX[c9bA=:igN(9\kUn*X#6'_0NU^>dBJ<(HO(Nh&SaG+5#MQ.Xf/Oh:M$H>eE\BG$S!#2X\cfq=`5Z!lPJ\hRpLm7-g,AGm3)#-BDZ\C:hcUV3\?Ob_\m0qaqS[XN`n*P&\f%%Lu3_^4Z;&BLl.AEc67WS4em!>AZZn7 +endstream +endobj +585 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 584 0 R +>> +endobj +586 0 obj +<< /Length 2211 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +GatU5>Ar7S'RnB3&?pqd5f8K/I;eeIG$UT1CYTB:3Y\kngK\=;eKq3hlZXUP,*/JN:5/h$cR57k&'n7Hc-K_/%NJ)tlc`FCY-U?^Sfglc9W?V3bb4dFNk=7R"0`RKZ+ofOEs*c;8hJSV?J,7#+:n7=dB1(Y$rZ8.HYqZm#S4;'&rQm^[n`DZ8ed2F@k]lR#_gjF^,ZV-=1$K*A<_ka98\Q>g&R;LU8fDa.a!#TH85##/9aY`(*L2k+'2U@J[=tEVmR]%k9e._kAPSeY;Q>95b05YqodO7RCV3p&6jlg@k?BQg4dn*mOM/1Q%c-0-B$?*jB(*hBc5\Zri30j$co!QPaV%`l":'=l/Grt(TQ'Gf[+%sEu+Y7&hpLdX1`4@CC(W'K4$=O$Qe*gc#Cb]$%=)!3n3"/8+naB$&Q!D2jRo8(Qofu$FKqqkkG9[hQ=cRS^Wtd9@VCr7=T>d\b4E#-rM4biB?Jq@FmoeKuW6Wf/%&OWbUqnpd4h\TOp7CA>U:,)9)'Ls_$hBj)1Do>32;O!9Xic`83amI`n9j2X_AS[R[:36RNpJ+sN,oG6>JKL#174`8W>;dA>=OgC"/iPe=m*(q%l`F?bd6.=1Le[B^Y?3/S-J9Ia+F-r[^DBqGH/78l*a5k$QU1s'\1h4Z8#f@`rc,>BTPR3(_FXgmY4et_Oc=DPu8G1#i!FUS*+!YmP+p4?T$T@GnBo7(O=%Ed[t#Ke3?tNWTr@$!SYYq&rV.5?<;!%e"j,I[3lESIN?+a/oO\@!S/JtAZ>@V[$,mpFFt_>ije0WMLkm+Q=c5-A?[2TV&3m(%Rpe.>c:l!<*E^0:L(?ZqtAl*D5]3*VON6m=A<8I9.W!_T!sJ,dTUc([H$IkUo@VAh+$Q)paYH*Wu7PDb$h^\F44&H3\U"smQ>om6Xl'lFD;1DAlf\88pKnfLU^)^kFh%-ZMoZ&%e27dS?U:a^2$($Z0PX_R)cE:g@](3a7[ske$-s)IN1a!L93VaJ9krIBKZJ;^tRfWB^]pFm5*$1?!B@k:^n0ud[''O#$[,l`qd)XS'7E8Y"E`tr3\#a"20u"YRSB]g+X'2Z9`T?O\NPX:q&;cU3*pf!*.&EdYrq`,d9!rGukuK5h.JNct[28aO+.3k[#QY#:..gNhig8DWpJW60WsjaH))CgHtOKDLc/L1f1r#)e:[4Z57AI:G(9)0oNKVe=unL61UZ]0\=?8;lb0,G!Z7W'0"RJL`8nPiJ)fb]$Q(D)L.@@IZ/E58^F`]2t_2nj]0\CI];O4Q/ebj9(eP/f:mH+hWPOCYX2ihD:%59Hhc%j#KH-#@5)DK'e#5!#1WIBP$']-Y`3!??mW$T$;_U@7cjESRTN03o*hek1'U"ag,a(Gt0m/MRQ7:K"IoYf$Nj)ug%Jj5JTj"OEtb1+Q/Y^liT@(UN/P'@[6\pj2?\EXA!55H3Ri]:Z7BGparHp^ANVgUq0So;L1n_]EGMm8*(DJbdiBXA^UqN]Z)/2K=\Ab)dYfqhKP4\`SYoql'@cb>s\,_=&sEn8.32eTLuDU_Zr]FTKF=@2qI3@/kbB>:"^k$:5",e +endstream +endobj +587 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 586 0 R +>> +endobj +588 0 obj +<< /Length 2568 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gat%%h2g=#&V&]Q69nm95f/?Rf"K&ip5iU)Oj!T)'MWS?A_LU'M^g$lER@"b,Dd*p>1qb??Tc*b$tk!oO^%Lg=p\&g\oAPaVB`M9##:*%XDgh9WH2l*Hcb-5geaSjZT)U:#U4))#b?OuMUa."XUC\Z##!N#Y((ic(7gX\)9qau2$%B+-C7f8UbZ<1nAP;jO%5%bld$=:2hCQY/ecI-U>j%<9tEn`HC66]pro=8VhGO(Ol,uYeI1sBTKMeDT5nHWWsIX><_I/a*)e*j>eX<4$PCD:>*1SPu*ZX\E&/H;h\H[\u4*&NUQ/EXNuE=`:>G$D55P/'WdUh%<2#(160qc'kU?b96f+-A[]=OP[q&%B$F+\="j$<^`lL;j7qVO6[:FhYC\S1"$5s,F)AUN8!Wq!ml_-L4p_flSigPu.C5RRa6hp.)IM^aQV,E%tQ8CgD)CA0'XiHY.bn9K=QSga,\;Sc):Mc_"9L=hi=m#J>(,`0TjoGAm]N9>%p=Uo/Fgp+`8&9,mQYnZaWjDVW5[oNcZaIZdD/2VfS]g0MnkmI-j`#T^!5B:GH:CuPB2m?6p-]R)J,[pJ$@UM27VPl:;t]g<(o%%%S[J*e\A`MrZ5l33IS,+'>LX8Dc,3F#@?fp]=Dl#;$Md&=-nulQ4KmY6#B:0`PbQHb7[#RI8=l>F%/Fsm83_TRCV%p:cQAnZbg^sMaFX'NoJ"C>FS[86\Ee8(k`AsZ5So!Cmh@3NY.";k>30u[mCQ[guc'_6eBu@9h]3/e-J!.TP!#V%WeTfj`BQMIg?RUP_P9ABW-!XlZ55H')\@FllFf7^&pRA/QgCLdEYeY2!uJrXhkpE0HDjYnNlo*;iq\3CZbk1Lh0H/A/r(.8Lr+is[fiZpe^U[p:`C!>s-9D8:s3k8a9<^+Sj.S>JBf/0*aotLOqsH-42M%1JppPcY<3WAcN9(_YE:2mfbqnF`X)t4]5e%4[=#3=%^U*1o-Xlk^2_fKUQ4:iUkr0kIjH^Ka`=4#kWsh(`)U)#"=Fo(OR9L/hoR[mSguc\l$k-r^@nP]lo:m;C_I=Xgl&J-mq=99us8?6\5DpBO-\-'P@E`-I.QQ7YPfC*EFtukS$*b5e!HghOGJpg#da\2e44:!FK]JrWM+8b$XSCMY3=GfqZIII'_Y2V*%IER\'=)E>_%]Un\`[LJP\PN'*)/]-iNNZENN%nf`%uX06[]J$An_^%Fqo&1J@B;M^fU3ju?-_"p-f]_(+C4%6]/HG7'.PrQXsmJrB/#Y&.uStY;!/b_^L\ua^uiKQ,`#B'6Zs*%+>,eIS'bANQ3$]n[A;)ie"Bla/9Gs9=l[dc.VJ6iPa-daKgqS:r_4+)p/j<\SVCSn.pmXq6Mh?]k!r[c`m?Q$B%pR9;k(8mkM\l%5inOg!)kM_Ae9V\"qCB2#N)@-4aII4m[IU:<+j$'LBtDVeh)oZ4%M8krJ7Gftl8;1GXO5":=Sn*r@]^/6$FXebt!YaR@_~> +endstream +endobj +589 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 588 0 R +>> +endobj +590 0 obj +<< /Length 1710 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gatm<=`<%a&:W67+S'%FnTmtPH*\0n9i9THXVN>MU7eH]7=ZR"*ju7Ea*1(3if6]j;B4mh41fS#*8f!2E],rXagN$2e=)()C->=Z7H)9<`[MH>l4HNGeneprI<,#?YHh9&>%_*jRjW\"rhKI7CAhYeIK`$o'lUM5YI-57gE%`Ddrh.XJM)g.H0hZI?2B7`[Y`QAXMd-=c]U\2V>KIpf$?EPU:_lfp(,U@QmOPe@7!e&^dk2d@!`F3XI!9S6r1j0(sUR\O:]Q(,;rN12:jnc(*b$,1:(jn'.AJ;n_7^#T$-:7(EfMkXcSP%2/:=>M.^l$2ao>jr1G(68($h9K0P,r5D+n@XkZ8UE(!!Hc(T<1qq9CGh1Z>eLdb*ao&ImFO,A?/JoZ%&_W(HmI9inWD^'iYHri_&:04dD[g=@PABY'FlMg`E@?=F;;Q`OT!)**:`b[mUB'%a8:O\p@c5MLo8@'X>g30715YFQ"SI]1rk8sj',3JK;WoA<>b!@>/<^&pZ"5]DE>^$"Y#6il`=?hqFtr:%TiS$KVo@)b/,2TT83Fh3&C:O$u`U%SC0dcY4"]O&b%%djBX;QPrIVmg03rCa]9HOicVGH5JR&-<#Ol##hf](Oj#7B93QK23'"t3K=jVjroL$N>@mu3#l4N]Li+7$,^aUW$727)`<_E;9MG2iiYW_r=R,%,TVIVgkL*.*fD"olO`.8^pm,+,EN#t*JPOR`ZKtb-ZT4T8qodYQ;K^a0Z%)W>5]_-W&ocTrN1sgq-eUs7*E$8pM6/k&k$EueR211$oB3_0=0n]4,VclXJ^)kgtlLJaPb;.4`"HL!@P[IU9'PYeP$B7@?1(@09i'da(^aN4ln[RQ\a"K,lRR,etfhRJ>el=$O4.*M_t\raC8&!NOl__)g22r7KqT(>i/oeH[55EYM+C5`dd9YqLt)&r]JcpE>nV[.Y>+DL1og!CU?k,2Vc!:(q131sqi]a9@I7X@%b=A7_"VsVtt=pdrYUOW]VaSg2.mMAbS[OBc,-gKpa+YPKJpk9nN+u!/p,H@=,Fi5A3bmP0hJS_0S]Q!uF!/Zi~> +endstream +endobj +591 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 590 0 R +>> +endobj +592 0 obj +<< /Length 2172 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gatm^?0-'9RuFug$4*8Mh\Gs'qHGLW,Hi8U:hUm)_6l!e$/*sZn$^`ORpdf@`N!odA>E4Qs:42'WVQq$C('$98$iV2='GL-h'm8h[D#W7"2HcO#q&bB&JfhjP"TD4X[[4$Ab4L_7bCr^_#iG$$e(g+$k_8qV'_dZ%Qj]hXl*i2!CUF/ejI[suZ]4R2qH,g8CAX9QFRrp9OZ^c/nFlliuoXsl'G.S^G`+j\(&EsPo9W*8Zb/2U,R0$tog/j1V;:!Zp[?0s\M"?S48)Wg,S6Xij[<((L3I/jgYC\3@l803QiVU$&Gm'RcO:Bs)h"po*<4X^KYe,'.Lc2t$u34bf#g@0JbbA=)oPRhDZc\"1*.aJ//oQ\o.L_KR`0/<*hHaT4]"N33'\_'mX%dK0hHGI!-,[A=)$I3I#[".@,kYc5Y%-PAo!))jZ*^uXg8jskBL<#'B*rb)=K#"Oe+IH'nW/";Kf8.W*`cs=e7JHs`-Jc]=VRBtNcL.s;;P-c#oN*s`uE7s\nf-bIBIJ*pU:o7(k;ia^*NS#fEWoRCBGjJ>S/8'XSp1Qgu[?_4o^S6cW4dX*M*DaTDf0O+a5q'Rp.'QI2CcXE9q=_Ti>(K7me&4l+^0VU:[MRLObP-feK3tfsQD`ig:/r6-hJ3;^f]MH:_02cBF\g2\nEW6VOD4TXiOdVn!8:8k:\&cW;XI0tc7a=)AJ*Dcs+@(?P;p:'^et+gNV7;NdFEJ^GBogs`FoCf;#[LZ1ne/YJ_fmWbYGZF8lCpU]2iH5C20>,g3-+T=g;:k2!9,ACtk?a0:VL!2n>_\Xb%tj*(aM\9)qm<%$lfk)bU'3-4L+,JneJ(^]hc4?D6^&J>l.F(=Es\P!\IBFPT%LigmR-Jk2^*t4figahZR6@P-WDYY9=iap91[D/l>Xu;q)Esj$^&Ls?ZKp&-'oc6.=I2`.$h.tcZ+>003CVqb-!LMR,9G!&=fEs6=FLH:_asH/U$g@9Q'#1h5q=<602d74Trpkg&#p2`L1M3.)#cLs64B'MUNAqTW^pO/H"5-"[GLRg!Fa#d[Gu'PNZAq4Nb]W8YG-#4[@][GuKD-'4AKFfM^I*5428k)GF_ho\W,GSt6aciTBKE<=TLm6<4:/Dp]O=B/eBnlj8(j%gNLq5M*$fMN<,?EB)3=GQCS<~> +endstream +endobj +593 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 592 0 R +>> +endobj +594 0 obj +<< /Length 2760 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gat%%lYkiB%f`-8@W#'8Z9Y/\rRap%[V<>YoT`+t(72Xc`hQ+aHL-J1R@XBWW.us&nMn-_A7>H_MA/XEPieJ.`E1s;/)P!rC;%7Kq:k=I;U#?U[mnU?KdtSiGaHS5Bj(1sIEr1CVcH8KKR8SFZ'S3*$V1L0$lo6A+:XJ_+,2[E(i(Lab?ic[bskG'KfpQMS=0Ylqd*<8n6H#Hb96Q()8d5>X*'b[teE(Jbhgb9Pn?+^iTieAsg.lDF0@+UuZSW2lU5+GNKs@030S%K9A0c-:e!..#/]gNs(:jqGkol'S(6;C+dmMOLnY&E9kesf@3Jum'`LiWnmG9jtnjH(W6^EaqD?\p()dhZ'-mSHVgK*fMKmo74/G$1JgtWPUdR[^pFY#Fm3]U<>rm-5X@"E(92H_=F+67q[L]rWo6c-,>qRE9+MN/!RCtA>M#Xc"C%"]qq/V?:A6qb+1YoI&aLMsaR">?W*/'1't_@Uq`9oklZ',"PXr5>'ui);GeFeN3(ITrEHgq/0$>Z-dXRV4U#rJKRg?4EI0l=N#h,.B\p2cA9TmO=;IV#B5uDA+J`lpe[hG;Zd1>7`Tap\-J^\"M/(NLiKI&)FQPOf^,=uT:t?eF/=blSp<@k`h/*G"[>algClf6:$QfEX;EW?Wksk/AFZ9r:EKFB"&J:J(^rWXH!Mgu*q1k?RbJD-lT(ckajN5f;ofn'UG0E,!t.0^ke04,K[bgmd(`g38p"s1S6&-a`:SX27V_,2Qj_8Tk.8'&?NN\N-pl3efJ1k-o;?dLPicE1KAFU2F/sbLaq(B_<@__66`+?Hj\\%b.bKih%ZCE57_m\?U6sdlb,blp*hqd'?-"BL)M9Ed`L2c6EPT^KdQ9BU,a*RG4E#:RQ\8jm(fq)8p\#B4q^UAf7#E/3$!K%m+0L^hk5ZatYlR@.1^b*e5LIDU-3QS0;-nsL1/MaguSQ#=jQ`2ENC97XB8fAK,S*!j53e#^Y>.]ecG@e=Spo2r`eTucBE,t#^h6;CVR;([b3S[V(j-b-`jhY#bSg2iUd3:Uj=k^e)R]tT>K!,fS7`;_WQ^ZbRQ3E1eguGoOZ>EjHVA>.Jk3+Q-s5e.NoVND^Xdem=D!\7gn<.s:#.45FSA=3V^2$cpp8MWic0C"#)qET;+15'O-k9%o)VZEEj(@6pCmFN9Hj#5N@2d(/PFM>]DEd.gPBl%SK:Tg=_^EnI6.r[0l;b'#"he'ELG%A5TJ`iAgV)sEcpjmaZnHZ*4BOoZ9l/.&_7T,Z=7_p*B^rF9oE^sS^g[hR1Z_p[[\=CBkl\tC86B`Q92nj6PXQ2@k2-9XC?9dL9XVSjWgnfOY%=MHEHdMl&&[AB:9oHA3DUFf2(Jt&XMK8$i1=q&.[+h1QR7t>kJ[/aGe^gICR3'tdATmK7[p[uXj2=*9)I!rhX?!?b(qA8_-f"nnl#%XJ(<:%e_DDYLm\"*]_o7uR;7bT+7$YV]Lc6oH%69i+jC+1*GBl,W+7T3YmMbHLf+B6@G$dhtPL2djld$lgW#C.bdJo5m^$<"C4"_j'WD'>W&WN)qH5dhdA9FI>]`6tOH:&qEq'(["S)R+,4Mr9JIL8N_!PFIP5hB-&,_&:"TS//GXI\t[FEG_NB@ESp*>@k-bNY6SCYWg#n&"HB4RW'8[/L*uL.X>_U?L3BEn!u5pS9)~> +endstream +endobj +595 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 594 0 R +>> +endobj +596 0 obj +<< /Length 2205 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gat=,D/\/e&H;*)iV(Gm+CXq4^#[Yj2XNPu9q/X0L34>HRBh[lU.`U"%.qU/,`341[cOkEOQmnYNd&Nj,@A\B0AlV)2^$CfQ;*n6EoKh7pubBs&$Ra],REDoCd%a[lt4-MX/(%r^$qa5IQ]4VP#Xga0;ebEB7GL]3d"^[b(t%#Vj7GNUH$tkj1?K)+tj;#B8W&1]IGY'Z2t,LNp0"8^)/ET@lL,QCu$">s0-,#gOQ]KFLC*q*LEKKp9p4=$,2S#Z<4KJ*;D2ZM/W=$@>_14`>&FQ^k7hAS7Hq(CZP/1-M(J+BJk*8D0*>uN)!He7$u%,=UcW@8@@ZA4P;f:5BM_E"BaoB:t9G/:Ac@]MA?AtW'CPAnSd/+]0i&snO_o]c-'W_CKl&`<.I;UphZH@XVG9[FA74nnP,jMYLDbWAB%b^t(LmfaP`gi3*lYm4H!,or7r*Zg/'\o8?++4FB9VctLEqH:7Zc!ZleTL%l`:PDVj80EFjaV^pdMnY2$PBQ3KV/O?W.@#G^?D8.Ko]6EpuYs,?*F7j*uNhW>:r3+%mUW?`[SR*:45X)e\,V5>]Z4kN_B9;o:mU\Wps(TF>E.'496JVn)FnKR&t_6\\X]A?]73_Fa,`QH))KB./9YA)ZN]1P'%T&Nnm;_.TEfmb6TNT0\!DQTQ,,?o),rkppq!@>"?r-Y5:T9:LfSnujKq<>P7@Zkt8n#M('ncqJ;"*N7)7#,&D[u"t./A"UB;)+^]-;=JBqlH5%DMont]p*@N*ER,B&.1QG(T/f6q)uZ?Nkp(>"InSe*,#u(&!0IH"N=1)mQiI%`Qh^6m_]cBF,L^65!CA@LdZ%,e,9s_]qCpDG=SC;2g&%8"G9[H?'XD5iG)j"LkKT$Y@t!HB<#*Flb7JO:i?'e.FAM:iYdqYOU9ioBS>QVNaD46_$(if/F>405]&nlLn4a0b3b3*TqX)e_g>OH4t;K`_:`8TJAsXo.>k#QFi\\>/h"_^D--AC(l\_8^#j(/T.%A2ot`uKkC=W;*H$G!a"=B9q*:7aFK-H_pker7Zn=P;U@g%V:n_nXRoMh&:O-ZLjH2_#j8KK;j^i.m=h>`]A)4S=ionRU$^0NPFj>%j'#o06IU>@/MMf7;A)ne"/*]G5ED=&i_ol#9:$nIoZ&0AE`:64=$^4O:QB9hs29]oinmTN'U4G#iLh,^kX-=[e/PHopJ&I^7Nt)`T:kZ7Y?*b*K[RiA%TQAZ;EU@k>5L#:df@tMBAHVC%rq^Mgk$b:E+AiJO+t>$DTrhk%t.hSe#j1Z&]1IW>/YcsKC6"Tp=L's"HH?p%sghI"3*srM?~> +endstream +endobj +597 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 596 0 R +>> +endobj +598 0 obj +<< /Length 2102 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gau0D95iQS&AII3&38Et]](Pf\Qg:+i7)q=U.JNYm3U&/VH+=,MI]9#Ne%'&%\NVP76:Y[+06K'hQu+`nBG^V\FCSuOmB),1Y:=*YiESBFtdoeaBaA,a.:c;q0_nF/BTqFQflX1BD!3_Z@R)Tnm1='eDqh[6k)ih;l3$L0*oEXbE^:_\s@%EbB!+rX(45eQ!b[?_G(WOZHNeI,VR;F7e%gccCG=RH\bNg\T8NtBdLMoV+J?^PA#jY7O`!J1oi[J6&Mo#`L;5Oms>q+LJj.&eAoWd+p352Vf6j-O#^k*4>pZVF)a`FJddRuB^o3.[!q7+jO]#8/!H>:=X;0G::I"j\OjK$S#ij4?KP[,X4i?>mD51\.^NJsD_N)j+bb4[TP6q2@86B<=Y$'9F]2XjN=_uPTLuen$n5nO=T.Ro;@-A-g!O8'F;K(s(M%_.8nlL.&ubZ:rYFqn6im?p:_fL#,?Z7-Z6[O5gWXABflES#EgJqT-L#Lt$gXqhg%pnk%RjVCbm4-m,2?Cm1(E]9-776B88;5%+Z<*9_h!Y:oh]$;oCN`=#i(We.*L^WS\\gh!C0:;AdaPu/rUTEW1g_995mM(=]jC1*jQNWNV@\Q!j0;@S'Dj8ka+)!?ZIYi#s,F0ZW)8gCR>^#rFNZKc+_J.,UgYP7]-1:gDP_u%u*AA$Y\H4IUJQ]nF;m.Cq/0]\a71+c-q;_L"7)6-KSQA7N4M[0E@9F_SqhjV%DXR;\1@V%meNt9KZ4U]\K2rb[P,O[OhhlYT4h@#&1.Va*XfNcC_/cm+9I0%SX;K*fYj)-TeeKgj5\W-KE5;U`GhN'FH`J`j4:*+P\E>GgHkj`hqN;XNCq\r$%m5M&qCPGb8i"Q\i"?YemuLO!?$S1N4uj4i=;`^kH/t90CfTplHO`$<%S4BTRV.#nV]9KEEH[Y5@qjKY)$LBLM:CbB,D?m0p0]GctL?JD0S%Rq#eEhJ=-&E*]ESglUbO@@lEZ6o$:`ZUr(Q&'15&Zl![[:@^AenBbTD/ogaO-8cLAP&oO(%/iFT:@I*P;Jt=Q!C?^$f\e3gi**^X(l3RTnhB$'&%$SUT_",/s.ID_dc;>b&aqA3f'BZ'e"Hc9iBg*hVKRIIe(8plihd.u;ZXN;6XO?uPW=YdFJ-fKJ7(0.p,&K-r=BW\8q=\b4'PX+,LHPXW;f/@iT$ZgSWLeKPh_%E)K7rjQ[EmZ6;u^&h(U#DW=g;7_-053DA^MqZdB;1N?d>2H`mf2l$l'JD7DWb5_D#6,!B#1E5;>Co\IepiZ$p#iP%@V2H1ftE9b(r!@jZ+9+!%BkFLH-n2YNhW%>7J&L3`%ig%r.I\mUK5cn8"p;_,e1k[<;OACUn_A""C0[>#(Mol@6k:C +endstream +endobj +599 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 598 0 R +/Annots 600 0 R +>> +endobj +600 0 obj +[ +601 0 R +] +endobj +601 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 477.982 200.658 579.732 189.658 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A << /URI (http://httpd.apache.org/docs/2.0/sections.html) +/S /URI >> +/H /I +>> +endobj +602 0 obj +<< /Length 1877 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gb!#\h/B&J&:`#5Jbla=2I6g#JX,YsHd/^>C:Cl7HTLD;%k_i7,Q]M=h=eUu!Dn8Do$ShKYK3W&;K=HjHQ>-;MH[@'n8L**h%@ftrJ!V'F@>4/K,hVI7,W/;ck2Q,-]iV!(l2d9F`O/LRdf((b]`HtaY*62Y:E%.)pQ9=mUnUf2h(4ehd8%8rUCf1`(%M:nDXJ=9iN:;ksLWYN'9dUS]Rg>?hSjPcm@9$Q_/,#3KQ)S;jOt]eQLTbEkMFfH^S2^Pi,*pu^J=E2iR,W@NB>%M<\I-OD;.2GK#mOpFU_n@o;UVAbdl:C/_7jQp0"42W)%Uh?6#!VhgV=tkC*2XL]RK,WNZ$HjdOI\&)g:d%3san8Nd^a%@,^11>`J;rY-HDjFE,jMXkJUAep4JM3I/1lI'>K/%!XZb@_/_/lDZ>UiU_9p@@^,:cUfRX5#+O(kKl/?!Nl%S[qm?`Fk-[hlcZiC)foo3>qRbTp%n%,ji-oEbDX!o@J^0RI]$lL,^5YZ*krG1UF,@;^g?G;0uI3S/>N'hd>oZ+D;4ZtVY8,?K,M$7s1apuOJHB@#Nc;Z3o2om+P'D)@!:hQp^K"diZ0tQ\,k,gp;Ru(H:1S\7I4Y$f+VEn11q:'/ugHqo5_'\=2eb##,$N6o#Vo:p:RMjq?>BeI'?\oE;Kt]_p+9"1,%-]H7,]uW^&qY?"hWEMuDjMXZeoDfQ;'4D82(\*Y!Y>6^Y4489+a*@fQ5(kMA1[]`ORtUORV%XrQt).3Pd72B$OD]3LHP$J5b1]V]$c=r_FH,"(fmICc]9R@bQVWqd-f-ZM=$q'eU_;-gp0P*YL8?e]I!\Mp'#_XY-W\PP;8L)j5;:f:bJqG^krfRi>fWV8fDo,i?u(&F[-k7Kq6ao@E%NL_!(87!-\5eeSSD+#GncS'=[&AolG"DJfTl=R8-&aAr][NKSOSX%a>PI'bk3k%glpV_#$hXoKjt?;+Ls=J&)Bg2d2LC_*;,;E=-JbDQO')?e*N%AqXT*'$\JF$:te^MqpWI?3#"2IL26Wk;j_p3qgqs`,dS@8ha?qU<$(G"R``/>"6;^D#E/rfenu$1(t;5k(WqcmbX7"Rma3^inATs&9!i@$:!p72d_mGCceSYRRJaKc7r;bAj$)9=:2Y@1s9_SOO+dCpOW/caCBOidL!S%/0D^g3e\2l\E`Rg'pdNfqR@bm3h^9R]]2H-@UsR)1(6i*4!sB>&FLlh)^f;E,&:]j1TLI$LkM)-%`Cd!aW2!pA+Qj&R$]DkS\L<-?QJQr+ZIYbKG!E>r/p`]4I(SH5n?P5YL>%WUe~> +endstream +endobj +603 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 602 0 R +>> +endobj +604 0 obj +<< /Length 2068 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gatmga":.E:+1_Ar(ih2qFDel"n&2kJi2jqC"0fCn-?<-Uk"O73pL90eK06[R9V<[f/a@68kgG3T_mA2Tik`DqOcL7MS]k?!G87-0RogGA"*0Ed+\RZ%@!o19Q7=kJh.ErPu]d?K`NDo3"Y=6tj8Z]psmfhClPDDRkm/";^)8s]Cj>]`1"M@]?DGh6u=[%erndt4!HH0/VKkP_]6@QBk6@h6/V.D\!6EFt6PSsGHd:RpaUQ#j2po.c-CEY@H]$t5MEC7(1fE]P&ACnqU4;3"KUWZf]7HVKXq0()jkHpmBUgTE`Z+=ODL/*%,HcWJo?,\\E]-Osk0>?#H6WbGk3lj/ugOa&OSiAUe`Li'$lbW%[cpjVi:&]2+_De]oUM,nH5'Y`G+I&ep\.J`$6dop?P1K:1gQF\&lQg3]9k&s.K5fNt,*is/j/qm`<8ZhXZE)mfJEZ[\AWeJlRVSda+OONGQ7-2[bnr[_M#N>G8)\XaPB8gkGHW3T^M&:[.>uI0_)Bdnm-#g07+1*tQ%p!\NIl]a7#`:crT[K]]'Zao"\\FWkC-,ns1AAegsYeh^SttoN*+O1o0['b6-F0LDS4G7?2dUJ<'bZQGe/=/]K?.)7\:&i$22AnhU%E5i7!.1WQEde(NV8N'*WsAW.gOkUm`_"=2-5T7lsnkgUjfRc./;ml`7cRT0L(NJK7,?=q`@\8F1*>(.EPrpo$cKSE(l[8YKd2Qa_$B0VQ#`XYIV'1?jVDN?qjr;8s-#VFRSB,a^U8'J"][kM`r_=:^,Do&f'$;IpW.1#mb`gGqG`"6oZg`Qip+VP-?$[=9RQ:/+42=$oNt?i'sq&Ej@u1*uqO5L-,U%K_=R7.GZ$0L37hmR]ThO7Gp9S]VX;cMBnnk/n@fC^.$1,!20jV"2,3Zq=Mqd+D&Q=7935NuZ_.!n#E]'7H`&B;GX%VJi$k1EEt5LF0C4B.uu=chP>/)o\@]r7&C0FH)]:^ScJ3BCOYl3Xm@BbLnG^%bNoVTjbm++%D&s!^&'aK@h"%>Z$>%M%WjG-d.pa@7"thM2M9JXQ0&3:i@,3^eAj;#FHn'S;@f(heF\.K\.^'l:sPP:`+N7I'F\erk=o]IGbAb`Ui&d_.]R8po\"7A3jSi4)Y'a8K0CRm'g6gr&FW1ckmt!8*X&Gnk,4K#tT$#gOMg)Ji]KPifa2AdpG/EheW'1DO5.9~> +endstream +endobj +605 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 604 0 R +>> +endobj +606 0 obj +<< /Length 2230 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gat%$>Ar7S'Roe[&A3cF5XLBlW(XQ^Ue=m%8@pKoLB5X@'UuOf8u/>B?";N:hiUH$Ub(7@r1\7'*hN9)kdU0*llE>b7^b0]9l+T._3PNpCgk?gAme+WE!'mI>$im'pn`-#6k5+@#[8,,L(so&`U]`[3:pFFAdL>>]-3T3%)J.@_8p>Y1V..F4kOD=gVu73?O)q:jZmBu\R[-X#3VM9Mn#E-7IiDYfX&/rrj(\$%Qs&I*cbK28g/(?:l+(C(o)'i>r;C.(HZN?8n$.p;'D.p0K>37HuF%?)iH51[h1^5V>8YmFH`t>8M]5B]KE<*SKs.9EBl8H]HBU>lb)%CaI&'8WXhRkd_+H-+5-*F4IISb?k!p7F")5E;d;63hdeGNaoS+gR[h2n>m<)kB8":-%8HikoU&>SX?;][TM2l4L*8pk._9V&7AL"%4,eO9!td3Afa0CH06$orN##<:iFq,oEr:$*b2gO@IS6]EB\M:I`*g>#Pqh*qlfIJ9\/:q.[/%e\%d!-K@TQUNs#?#k[m9?6;X-.0H-b%TOU$[T2EoO4*[2WkDtKr9*\C\/'iPd>A5R/J%/dRsrqTVeA+hD_e*##l5<6XbZK/GenVJ1apC/[u1fNrK5h4-ihLK;l'q?/p)+[._\#CX.BP*_0*d=b#ram=4<0m#:eMPL'l,d%rFOG2VAR\!n[!J#:LOR]$[]lUGmD.*X3pbd@IUf!U+:D1O1AoaL,#SJd^e!!@SKR+n>`sjnJHCo/tpG/fMDPbNrh!g[0/4WF@.Dp$D=%\hf_D<&F9EET1%sPlib1_4J[s2Ao>'CZo6,N3KaP`-bk4;UO1hTuu18!j,PAF-hQN[$3#e@`ZnI[3fbX$PY1MpjAYWi`LFKim(Na&d.;U.-](!kt<"?s]oQ+,Ea4B+L80g;,"$*tqU6F;TSEgP,s/PRsA14Z8$2)0!`%.*K>Y21=[l=:d5Z@32EhCF.V5/#U9U5g3Gtg?[=f"dP&oit;XXa6pe."T-Uif%>]H)*\O4@p0jT$:c.?(hX_9g"c1J*20=r`=iaQJsDSuRHmcB`GE[Xm.NpCGF\8LgWi"2d-TPcf40_BCmdF!=%-4SW/H6,m&QZY#,9QSPWGs,'QRTg)"I7ug.X`L>Lrh`Xt+d93ep(a7\7p:Q0Npi^`6>Elk\[6RkYQ>G5aOQ@cj<@5*"W9/(?QS-@'-BDB^38Y(GY*I1g$sDJ].i/*aN(i9\p5b:5l1@5`MkJ/5t#A<=ZY3J_5!NpSPrN-8oY:7c;tm^H(f5M5"s>\;^HiL^/8us+g1NZ%P;>jfI5fnFtoR^[D2!4_/D4*u$UR;8`,>]JBES!;6$bJ(8oJpod]5%=:\H!G39k$3~> +endstream +endobj +607 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 606 0 R +/Annots 608 0 R +>> +endobj +608 0 obj +[ +609 0 R +610 0 R +] +endobj +609 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 126.16 376.189 212.939 365.189 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A << /URI (http://www.lua.org/) +/S /URI >> +/H /I +>> +endobj +610 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 238.181 360.789 377.21 349.789 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A << /URI (http://www.lua.org/manual/5.1/) +/S /URI >> +/H /I +>> +endobj +611 0 obj +<< /Length 2000 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gatm<968iI%)2U?BQ@fKj3XOWnh&Ol45&:t]8>8`2LAgWg>YL5X!!n+f?Hj6->Q\JH)QWPT1c@.+R.,k?Cmi*2bn0]ZDlb_ST=6'YN9A_Qj3ht;+5_s/#YAT<-])Ic^T2rUCs?XpXK>F;MH!_(=@O%UUf;df77$NIPo![oTe,:OgT[3Dkah7IZ2.sRZ^Q<5R4*/2p0i0_fC(MS"'G#G(30l)Eo?iCYn.C^USPp$m-iVMj."C$;:rBJGDd8FjG-%aQ:Dj![@RC5T%Ti_HKrcD`GCKb_!nuJR9o@-$aED$QBi,^ke'IEs3d@BG_n$,ET[M)Wd.W^Q>]gkrd)h5[&V3%^6tmH1FI=h"FOI5X`Yal&)"D##Ph2ooMZ>85s)U.]A$F;DQQMD^dU@98hfuc@=hM`M#JVNQg-?-uaEU9(b5j3sDg^XK+sC8):d-eV]!/+5%tG924+'jh4aDc*][pfiBL#SlS_1MT.a$6\u_Ka9.;hkbtCrsQ@i1n&A/2A+_mJbjD./ZHd[LX.mi$N8S3eX*=lRu?;dI1M`u_4,GXq:+Kd6/3XAG(!Z@6/;36<"USCjUFV`/4rsj"j!9ce.%KqR.seS#YkfO2\PJtp4sd2@`rjiBOb>srSm+PBu`WXIWlAW%[t5:KqLfu;KnqYdpmPP>:/3>>#r\(V.W-'34^*Z#\4u8A\)UkBEsJY@^K=oF!tE$h$@T6L,uE8\F!%bdg[JVMa1jMA;m;u1La*:t"^>P($>(u^bH%^Vrqe7g^iWN8s"PX"e'>i@r+0=S0)Ca9lQWcfa7SoWgigjLW:S:mcEcKXVmC9NKDPa?bfk&j-L?8c#nh(B75l]^CqM*t7t(4)^q1s!'*m"lM#?D^Ga6"gN(P.]PWr9g;k&)EmSq9HNq`G-@2rk"$F>Q^RY[P?k\2jAGrn!O&]e2_+XTTl,uj-;ApV]?-fqqD\o$S2tMeQ]RI'(TlJm[MZC";P9ekM[bB_oB#>Eb)5qp4Beh&W&-InF(Fg79"D)Wq]!l5C]h_QHGq[GIVFAf-<0YjTNT*(U97V)<)okmjm%46Pn^ACnaYk[$@Ln=B29&LQuqfDHkuqua[5JcI"Kg!\?(D#:JV1`ROLoS.un+jQ>-Z>UA&Gl:?h^2lm"_S\+aZ9=8D9o)=5O'4eq[cEi6EMDglHOdpQW[7IJ#.6eS.F34_r'\`(bWd6V-4S3D`.rihoh/.Vm6N<6\l>spnKQqg@0OZ_8lNoDTK!p^Ea."!UD.G+4nkV]s8UO-;_q8\,eN_L61tc6_f3!)7MeJeIs.%lt.aWT9@gbGu_IrU#9hKKr%s9cp7/"r6GuZH"JoP$3F[46;cdCI+U3kFr>Yf7uJZ^03\N4ihOh<%*,UC]%2BZc*>K8O-Yg%p[%);rF4-Z35"'/ru?2~> +endstream +endobj +612 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 611 0 R +>> +endobj +613 0 obj +<< /Length 1982 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gatm<=c_;q&:WMD+lm>RaDs^Ae<.598^IQ"RQ,_pMh8D%[1HJ]6u%c,5JEnV**Tc$D%RmmIcc"t%HlfQ`Pp*VaJ5!phI:ijHaag@oALea..[IurKP5dln.qfn!>,sE\3R!MVBZMRdoP7bE"`YjGPPW%r^toE:K'+i*h(*dXYf(pGX`qOm#?34$#tOTnC/DFa5rl%-nld)FZ'!!dPNq:YWMMXi72h;M;bXIKAZE:tfI&4^ETg\GZ:_9B=Zp5=?Rq+uQ,N!o^h^W)2CPhSODU:Vor,7Q@pGrM.ZcWSQ#N"qFDoF^fIiu>g`*fK$FqltGb=6VBYF&jr,G($0ZGB1ja+0r][!NUAe/>`\q7kj45<*1lFnCQP6S=BY14C>#8&8=c]2!(El^nYq*iHDgW'4?F:T%(<0r/p!YikA@#:7.LA!Waj2a6b3UC%^Og@6sPF/RboPq:AZ@e_V.Cbt:Kin&(ZIicuFX:6"-3<'KLRT.9aT23=/K7i!*b;\)<"mDhH%g`![s0K^7h!o7#Bs6\cu!E4ZuO0?2OSX=>)Rc7?(iTnT#]akK0?I5A;0i+]`ZRA'q)fU*ZFp)IOqjNG]>3J3-[cO3b$,NE?4kW*pq#IfmM]OB+Uc2cLnMhSUq.uh\u]nTK1FEdTtg_IQ61K8dQ8p;iBVhKth&&H(O"#i6<&HpudrKMK96P0GQG'HY%GXl3K=@+#&I[_2a=;L]W!cBMcBSE*OMTsCoQ"eGiekLrC8=+S34-D#X!it#Dp85]I;g&MXnbC+!>u@K$K`gf7V_)59)Hte%.eh4@\A=`;N^S4o/MM7U$7Yk8@BcT-&-cD&@_XqJ-1LK6/0+cEV9.iLF,Yb>Ko$gno\)d/*1Be^UA'!K8[R;FW'*tG+cJoa2:t_LOaP&7CBOOr4)Vs:n!K-+`hC=OW9[I0;A$(d0i7&6aA"^*ZR4`)`n&U;dekZ5&kZi[Ar!".l9/7f8F-Ro%O3EZ.DrH)(^]2P"Ao_MLpil@$\ehNc?a.37\Gf""([+OeQO#9QP[jV_pi*:fa##QnQoC!We$B;f@hK44k_#^+olF3M;Id_EcQ$&'ioZ#Nr^65S_fkqUPK`,/Zn!5UI(oJh'O'+>r85g?Luu()ZRX?Z,^ePH:Ep*RHHO;pj/1K:c5\j+e5JgHb#@=cB8dg$mV2-+1o, +endstream +endobj +614 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 613 0 R +>> +endobj +615 0 obj +<< /Length 2177 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +GauHLHZ.Xs&HCX[645]Q*>1i;hSClgD7h_FR\Yqt@T^*+QKad+/@qPi2]28EG7l4l&_ZT,@0dG>Icsa7(+Ym9r-[E6?oP58#d:?e:cQCgT/cF7-6>h`LXDoRrh4del5TRAYl57_1L+C4:kd8q!Q']Pg7EroK`<=c<*`=_Q#'AR?C^CEc6u.g&=C,V9:Ao0bqeK\olH=_'l0Tp8H2ttW$2?rmqJbN9XREXVke%+\1U^DZ__`fQH^ah=k]6n%_KY*.."EcqbU8VVmCec&Hm&TM8c>6_+Ek!ce/uV*"aWJ`:[*1hC\rE&dQ>%lScnBd,#c^q4VGW(@8[pc^R'(Anr*plA@>%0DH#Zh([oW.umaB`dn]sVnFlOstK9i.>M=f#sJYWK-"G23):f*O:#)10L;"U44X\A[UbNa7`$C\@4;=oGm;t.GNh5>O8Y%hEWB-m0pN;V$YSMA4AR:H>Y:h[2'`_J`]C>@8)@B?J5>IaQHT$AZ)-SA#=N$F]=qd2Q]E8/_;!$`+954O1`+X"uVO],.j5']#22J]dgT]C)InU22WIOm@*qj*LIS`VSMRi5S#s5kkU^Df+u6n$&BMeKup8qpcp$;lg\`n08+\7mXjc@):j<%.J-G)Im`0Z(=]FoqWKR4@q&/$iCGn;%l.-m\d7kB3>24*j&hhWcL6cPW=Yhrn6fR\'5p]mSoqqG-UcrV];s,KRqgj!MJnD_'/P\QqnOcF3L)t3#'D_Qc;Zp3k4cINcU7T6A^tPFT?Y;K3hJqbpjn3>N+6PJkF4<70f/($&&Y?p9M5/:GOcNF+dJR]1^*G)H;?-B?Ib'c)P+;12A9fi[;+oQ+h&DZBJDNYnl?J%(l!I\i(^ai`odl`+>5%KAk4;24jmJZgU5qi$8_QkdsojDLt?SM`f4?bql?mtbuk:q6/9eYh,0/Z>Wq)U-\<(FO$<'VT7[Y>d0-0>!gaAU^:nf#:n>?SQs%9`4KEBsIV`$n5nBZ??s/s(q)HaK2E?9?2t#F3UUm0+QTF"k"1fT7f.[^I"Y1Wdr9JaU_5Z%7K@8A"G;05L%K!T;/7lco#Ai%;-RF&-iaXce^V`:J^eh9Jb;ZubYB7LJORY\f`EU@IAsi%FKI8Kg@^\_iTa."UplL&H#;8U)^]&G&%E6%K)YM5a56',/SIreOF1uQ!KrXW+2VM.QF^P^JsVe%0un(]0iVFWMd(&f2kn_@C(A^TD4o`YNAGeWJ8UgiB/&6!~> +endstream +endobj +616 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 615 0 R +>> +endobj +617 0 obj +<< /Length 417 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Garo=btc/1&;9LtMERgAN1Jkg>,b%8'gr]FLiP2kVH=1KM&fFM*]p0?KSk0Ibc^?ZZ`>Rc^.El16D8,r$N#>S[>R>5=YHZVal=A@%sSC*Z@FG@V:69tB/Nd+1Y3B4*k`DtOF&Y*qlJ@f_nA*=YD"k_lWHm(CXEH0oZf(j]4hEIu;9,]L89TN*="I<-RLF(gC0..hWJeK&C!.\0FodN_\dEDXuZ2Hm;7%B[hN8IYfC+BUd!=Gc0X%2oj$\@&JDtg(o%"Ap2qfd#"3P)3O.klRMZLB:;>.Q3eiGOt7tLYlmZskRlP,0j%H=cUKW6;4?.oeB`Q#JAfTf@D7CR1G7c(+6!=U3l=G^;3^6=E4TQgj^Zbt<3i2E~> +endstream +endobj +618 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 617 0 R +>> +endobj +619 0 obj +<< /Length 1292 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gat=+968iG&AII3Yaup&)$M>ei^)Jg>&g&Z[Nd5V9[e/u&sCn@8;3l!khgU["t5@O3kB:^fZ1I>h^g.ADlH/FA6[7-`4"51Ct\U$RjV_\_K->0?L,@J&@\(,^%)-bnb1.no:.#XQTa:i<*EL9e9!n/-#og]DZY_hO@r7Lo@`-fnR4/!709D>&aP:GJ5@(tSiGaAIO5(J7[.jjI1+uJ1*?_:IGnW/R:M+3:RLSLLLe(V\n^#-NY.%s)u;`\hVI!Pgl6So$RGUY8"N``M/dATh'ct5_Dg(96kBB_,;Vm:TRtNpVr$"_<>22Tl_2bT=mj7[QNdZcHKY+;G?UKD]\a3JUl`F(O%6>&%SfM90nV5nnkctAD/K=?N('BM7W!gV>-2D+j<[:'in8ACD;pd`M]X5^&PQt%"A:#VNk_,ihJ\6nRnQ"?DO*G(LeSI/:?>1f$qagD.AmSPO[o.gdo2h8EXl`&"]pQ`M9!C%*Y*aTS5A.NVjV>r;2R+sA:YW._\/0uK7G\`Dck"LQ^le\^t:@ms;AOnRgg4Ah,<@_u0jjuB2dfU=H#]uI)'kCFt=*gFjaE90PE7ZpRG8#pndfg-;87=O?nH5nD*)pa?[_"0dojr#YZ*_.k(0L'F-)g'3",=a<+sWtNE+5"NDYb'ShA@`@HLSgVjg4N\sguEPF;(bWUHkMHar@?I7\nEEA.(l:@gFe&!PVkI/-!_E$4b<_Zb'dfh6#57hh6p'Td:@)qW_Ve^Zr&mtT=sX]2<0?Q3o*]m0!7K5PW5;=Hmn'ifJ?'mp5IeR!4%e+>;*4pc*~> +endstream +endobj +620 0 obj +<> +stream +ÿØÿàJFIFxxÿÛC  +   $.' ",#(7),01444'9=82<.342ÿÛC  2!!22222222222222222222222222222222222222222222222222ÿÀð&"ÿÄ + ÿĵ}!1AQa"q2‘¡#B±ÁRÑð$3br‚ +%&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖ×ØÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ + ÿĵw!1AQaq"2B‘¡±Á #3RðbrÑ +$4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖ×ØÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?ë<ákoé2Þ^Þ^4Þs–fþµÑÿ¹Òÿçêûþÿ·øÔ ÿä[—þ»·ó5ÛÐÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãGü+/þ~¯¿ïûvPÿ +çKÿŸ«ïûþßãM‡ZX¿Ò=¿Æ»*d¿ê_ýÓ@Âø´:•·Ÿ,Ëì¥rÇ÷¢Ÿðßýn¯ÿ_ üè   ÿä[—þ»·ó5Û×ð¿þE¹ë»3]½QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEÉÔ¿û¦ŸL—ýKÿºhƒøoþ·Wÿ¯†þtQðßýn¯ÿ_ üè   ÿä[—þ»·ó5Û×ð¿þE¹ë»3]½QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQL”•‰Èê Ñ^;áO뺇ÄÛý*êçu”DìOJö*(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢ŠÉñ&¥u¥hÿh²XM̗VÖÉçPgH²@ œoÎ2:U_'Æóý¡ÿàßüvÈÛþºoþ–Ã]sþOŒ?çûCÿÀ9¿øíOŒ?çûCÿÀ9¿øítP?äøÃþ´?ü›ÿŽÑäøÃþ´?ü›ÿŽ×AEsþOŒ?çûCÿÀ9¿øíOŒ?çûCÿÀ9¿øítP?äøÃþ´?ü›ÿŽÑäøÃþ´?ü›ÿŽ×AEsþOŒ?çûCÿÀ9¿øíOŒ?çûCÿÀ9¿øítP?äøÃþ´?ü›ÿŽÑäøÃþ´?ü›ÿŽ×AEsþOŒ?çûCÿÀ9¿øíOŒ?çûCÿÀ9¿øítP?äøÃþ´?ü›ÿŽÑäøÃþ´?ü›ÿŽ×AEsþOŒ?çûCÿÀ9¿øíOŒ?çûCÿÀ9¿øítP?äøÃþ´?ü›ÿŽÑäøÃþ´?ü›ÿŽ×AEsþOŒ?çûCÿÀ9¿øíOŒ?çûCÿÀ9¿øítP?äøÃþ´?ü›ÿŽÑäøÃþ´?ü›ÿŽ×AEsþOŒ?çûCÿÀ9¿øíOŒ?çûCÿÀ9¿øítP?äøÃþ´?ü›ÿŽÔÞÔu Ù5k]KìÆãO¼û푕b”1$Þã¯jÚ®Ãßòñgý…cÿÒ+Zè(¢Š(¢Š)’ÿ©÷M>™/ú—ÿtÐðßýn¯ÿ_ üè£á¿úÝ_þ¾ùÑ@>ÿÈ·/ýwoæk·®#áü‹rÿ×vþf»z(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š*Þ¥g’9nÁ8«ÕàŸtÍBÄêÙÜÌ©#aÕ VðUí´µ9^e’pÄñ^ùo}mtH‚dŽ»Nkáï®ãœÍċ+u`y5õÁ=ö×ÃÿÚw—2J×#€ç¥zµQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@ÿŒ¿ämÿa]7ÿKa®‚¹ÿÈÛþºoþ–ÃRø¿ÄCÂ~¿×Ø܋EV0‡Ù»,®:úPÝÂx[âe¯ˆü«xŠK²:g™ç[<ۛÇ8ÎqÓµ ¾$¯Ä4ԙt–Óőˆa§ó7ï º1÷Zî覉#2ép2W<Â‡‘"]Ò:¢ôËP¨®:×â¼¾+ñ.qdÐC Û‹‰n¼ÍÞbí p¸ãúž•Ë/ÅÏÍ¢7‰-ü q'‡C\Õ”¶mÎ2=Ç¿zõª*†¬Ùëš%®¯fçì·1 T¸ÚTw èAÈ?JºŽ²(d`Êzr(ÔS<ØĂ?1|Ãü9çò¥óÌò÷®ügnyÇҀE0M߉äûß0ù~¾•STÔËJ»º´€^ÜCM²HˁÀ¶zf€/Q\…Ǐ­´Û?kXÍg¨ks$1Úoä’ÀíÀÀ>ÿ­u‹,nÛREb8<}Ց™UÔ²ýà#ë\_¼{sáMgGÒ¬´'ÕnõO0D‰r! ®8äÎ}GJí¨¯9Ò~)\Iâû_x‹Â÷šÕà?fyf¤Œ3Æ@˜ÈÏ8õÍmøcÆÑø‹XñžöbÐh·Ÿe2´Á„¼°ÝŒ ¿w§=h«¢ ’@’M69c”ŠàuÚs@¢™çGæù^byŸÝÜ3ùR»¬jYØ*Ž¤œ +u›Ô¦ýÃn3»è<üØÆyÍYÓ¼'£iwzÅ͵ ß¬>ûá#YOÍü-ÌÜtæ€Çá÷†´ÛZÊÏO0Ûjш®ãY_¡JŒs‘Õ¡†t¨¼*|4–ì4£nm¼Ÿ1³å‘‚7g=úæ€< PдÍGGøFזÂO¶2ÙÜeØo„H§o¾ÜŽyë]—ˆVËá—Å ]@mô+û§\wl1(ÙÉ碠äœí5ÛêŸ|5«xnÇA¹³“ì6û.ɘ<_FÎ:ã¾#ø{\ñ –àmì4¸º¬·dQ¢í#œõ$væ€4þ ØNþԟð÷ÄúŸtßxÏ]³¼þËËZ[YÂUCä1Îrp9®CCð–âO|OŸV‚Kƒk{1…<æTF&S»Œ·Ê95ïՉ§øKFÒçÖ&µ¶e}bC%é2±óîÎ2~_¼zb€Œ·ióÝýœÎÌçv'€þÞ»é¾x2kÉ&:|É ²y’ZGu"ÀíêP~+cÄ>ð÷‰àµP± +Öcm´¶ìbxG)\`p8é@WÍêÚßÅú& ±Yè’1X­#Ô£¹k êË" ÙÇ÷½>µØé~ ðÚxOMÑÔ´«)L¶þ{‰A}ÌrqÃ`³ ŠŸGðN èwzFŸeåÛ^+ –gf’mÀ‚YÉÉàŸ¦x­ D°ðæo¤é‘¬íÁ¡rÄe‹O'’hÌ> +¨_|@U(ÕpíóË^¿Xº…4]êW:]³C.¥7ŸrLŒÛß$ädœ}ãÒ¶¨®Ãßòñgý…cÿÒ+Zè+Ÿð÷ü‡€<Çþg‡=?Z?áFxsÓõ¯N¢€<Çþg‡=?Z?áFxsÓõ¯N£êq@cÿ +3ޟ­ð£<9éúק}( 1ÿ…áÏO֏øQžôýkÓ¨ 1ÿ…áÏO֏øQžôýkÓ¨ 1ÿ…áÏO֏øQžôýk ñgSÃ:ޟ§•É»8ÖDþd)'÷†hÌÿáFxsÓõ£þg‡=?Zôê(ÌáFxsÓõ£þg‡=?Zôê(ÌáFxsÓõ£þg‡=?Zôê(ÌáFxsÓõ£þg‡=?Zôê(ÌáFxsÓõ£þg‡=?Zôî;œQ@?üJø[£xsÃëyh“v:צü%| jcYÿäPO÷«Wá7üˆÖßZîh¢Š(¢Š(¢Š(¢Š(¢Š(¢©\ë]ž~Õ©YÁŽ¾lê¸üÍ]¢°ÆþV(¾!ÓeqÁHnVFÓ +IÍ'ü&z;©Ç§Ùô»™AüV2?”ÐQ\ÿü%,ÿñïáýroûuèÆZ?·5¹?ÕxJù?ëæîÙô €: ++Ÿûg‹dûš&‘õ—TŸûå`ÇëG—ã åëC¶ÿ·i§ÇþDLÐã/ùÛØWMÿÒØj_øˆxO·úã[‘hªÆû7e‚õÁÇ_JÂñ%Ž½Ÿg-þµm<+ªéÛ¡‚ÇÊ ›È{—b0pô|aÿ’O¯ÿ×(ÿôbP4¿|OŠºÌ¿o?³Z!?Ÿ û²7nÚ8Ç5ßhõ—ˆü=i­Y3 K˜üÅó +àAúGá^â3ã­áމ5 ^ÚA ȳ³&¶‰ÐasՆ>\äg¡ëZ^8‚Ö ‡žÐc}C÷lÎ [(^ãiUi8%ؑê{q@(d`Êzr) Ñe2 ea¸dS^/á{c¾#ñ9Ó´Ø4›¤¼é¥.¤—m¨*û,gÓ¿Ò¹«O èwoü_4ò?ˆ'IZkÓrÅ÷—(c#8Ã/PF~jú4Íٙçû¿0ù¾ž´»ÓÌÙ¹wã;sÎ=kçëÔasðRR0›"\ûþëŠé%¸xh}b[p$š3*~a´ø~tëžl~g—½wõ۞*Y$Ž%Ý#ª ã,q_/i5î¿à9üBº@}b[–xŠ}e!0Éæ .ÖaN½ôÖøËDÖuÏhšƒ[é>&š="?´è¯|¨ñÈT3ʊ¬2FÏÓ4ìºÖµe è—Z½ë‘io‘Š ďaܚMYƒÄ –­n¥"»…eTb (aœwæ¼:1 ê¼_¦Ã¥j67<Æw±½¸2 iŽ@Øxàa†÷ç­zwNÒ~éØ[ˆšöÚ+›‚ò”·'Ž[‹Æk'Ä©¼ö;/¶}«ÍàŒ·n=úæ’ÿƂÇâF—á°7ö­sö¯;6‰8Ù·Ÿ¹×#¯·>w¯i–·ûAÝÚézäÚ5ÀÒÍÌ1 PW+‚G\Ê£³ÑuMö‚ðݶ­¯Ï­Lú|Ò,óD#(»ep 㠟ƀ=Á¥\#:‡nŠO&œÎ¨¥‚¨êIÀ¯™4Ý6ïÆ:gŠ5­CB7ú§Ú¥OíIµu¶ûÑòÑW=øÀÇ®¿_¹‹Rð߂4OZÞkšåÀgK;ôX.ŠpYy ÀÎAîÔíi"H»£ueõS‘X^0ñ<~𮡭‹qxl‚eØNçU냎¹éÚ¼gòj>Ô>#Ûi¶‹`öº`š+k³:[>Þ¡¿¼ ’}ø¬ýOÂ~‡öÄÉ$‹¬Ü*4—?hrgc.6ÁÉéÆÜÐÑf¤š†‰e©²ˆêÞ9ö³gfõã=qV÷§—¿rìÆwgŒz×ϺкÖüYà½})õ}>?Cpši»û2M!B =pqíõ©à°ÔtŸ‡¿4ùb†ÛLDkbš‚]5¡$îŒí$¯A×>´ïK,nÛUՎ7`ñëBM¹òäGÇ]¬+Ä´¿ØAðgûNÛPŠÃZÕ4¸ãkû»³mbŒ#É8QµBñY>·ƒÂž0ðâk~›F¹žE†ÛQÒï÷ÃtX<ÅÉ 9çø(èj(¢€ +(¢€ +(¢€ +çü=ÿ!ÏØV?ý"µ®‚¹ÿÈsşöÿH­h ¢Š(¢Š(¦Kþ¥ÿÝ4úd¿ê_ýÓ@Ãõº¿ý|7󢏆ÿëuúøoçEXø_ÿ"Ü¿õÝ¿™®Þ¸…ÿò-Ëÿ]Ûùší袊(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Ši‘Gzu›ž˜üMP¾Öl´ïšòåcQï@-4jÛYÔ7¡4â}³_?|Yñ¤ë,wz L`ü̵Åèü{©]¥µÌ—,p6Ò€=ÿâ›ãÁw@Ž¨kàWüˆMÿ]MSñ:Âü6š]fRÓ´d•=ªçÀ¯ù›þºšî¼Ar,ü99m¥abá^Y𘈭/üIt¤®æË{W øö7—Áº€@Iâ¸ÿ…­÷›»1‚î]HúÐjž1ÒeÓPY—ÊvÚ9ïE׌4Ë5¥pc€sÒ¼Wó­tßì+bË$njͬ— ðÝìnÌd²plôÅ{l¿toÙîPl-ž++ÆØïöUÍåÓË捰 ¯,Ó4 +š¥Èf»û¹¥Ô7Â᝸˜ çހ:kÏÝéÞ;³Ñmœ›`@9=E'Äè‘㍠T·$¬ â³5 cñ M§ÎÅrk¦øÈQn4x†7Gã@¥kp·v‘N§!”WüuÿY§¼?zŸ‡U“ÃöŠÃ ´W•|z ÂÁTá‰?z‡„ÿÂ'§¿òÈVÖæþá¯'ðï†<[7‡,Þ x$L™Tô¥ÿŸŒ¿èaz6æþá£spלÿÂ'ã/úGçGü"~2ÿ¡„~tÜêÚªi{ÞL„¢u¹íâ_‡µ‡(.Ò‘«ñO†¼Woáùä¹×±ržµàºw„¼Cªß°²µ™ŽóûÁ:õ ´âºŠáCÂáÐôeïS:|n<áɯÕrÞ6ðÎXçì‹ßږÚw´ñÅìˆÄ7”Ýý¨Ôoþ èZ~¤,d¸F}ÛKÀ5RñV•¥Ú%ėÁÆBƒÍ|ÿáûWÕôÝP"K¹þÐJÜçîó[’øSX·ÓcÕå"ëz-u>!½¿†-¯4rUÚPŸJî¼!ª6³á»kÇûìƒwÖ¼‡Ç—z>©ðæÆ}>%„Á^?C^¹à¸#·ð¥šÆ¸%&€9_ò('ûÕ©ð¡•< nÎÁTrI8²þ5ÿÈ ŸïQðÓÃZ§á+[½CFÓîîF–âÙ$aBÀâ€;»ŸèvyûV³§AŽ¾mÒ.?3T¿á8ðéÖìî?ëÙüìÿß­;mK³ÇÙtÛ81ÓʁW«´ÏÿÂc¦7ú›mbxô‹¢?ð“\¿ü{øc\›þÙÃþŒ•k ¢€9ÿíIþ§ÂÒ'ý|ßDŸúú>Ñâùziš%¸ì[P–Sø +þYük ¢€9ÿ³ø¾^ºž‰n;…Óå”þÌ¿ž? +?±üA'úïȟõícè{ë ¢€9ÿøFn_þ> Ó¥±Ò#™!–O5¼ÙKœàý­ê(!<3¥'ŠŸÄ«nÃU{³4Þc`ǐq·8ì9Å%dž4«¯Úx’hµKHLËæ0 +‡vFÜàýö­Š(‹Õ~øGYÕæÔ®tùVk†ÝrÜðχo®/4Í;ʖæ³Ï¾W‘eBA;ƒ 8äžO5’Ÿ¼†èd¹K,Ü9X³×g?.úÝ+½¢€9ká÷‡5û KÛ&ÿ‰|k¬ÑJÉ,J=‡\ÑcðÿÃzw†ït{ ¶WÙûVec$Ä÷gÎïÖºz($økHo §‡$³Yt¥mż„°Ø¸ÀÎs‘Îs‘XZ/Âß +èZ¾¡oi<ÓÚÿÇ·Ú®U·ÿqXàLWgEQEQEQEÏø{þCž,ÿ°¬úEk]sþÿç‹?ì+þ‘ZÐAEPEPL—ýKÿºiôÉÔ¿û¦€8?†ÿëuúøoçE ÿÖêÿõðßΊ±ð¿þE¹ë»3]½q ÿä[—þ»·ó5ÛÐEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPE! u5Kœí  I­FÓc Íaêþ&ÓtxËÜÜ+°ëk“—Æ׈§†­cèÆQŠîïu+{(Zk‰ÑPu¹®Jïâ%”»£Ñc{›‘ÆÒ¼f«Øü=’êáoukùšsËCŸ–» /é¶@,bFÆ4êx·ÄÀ‹´m5OBµ¡§ü=ò†5-Aïìæ»Àœ`œÓ‚Ú€8ü4Òõ­iöV«nwd¸ëZø}¥xJÑ•î1̤s]}Ä|ROø¢®‰ì†±>ȄßõÔÖïÅ/ùnÿÝ?Ê°¾ÿ×S@«Û}³C½¶dˆ¨¯-øGrÚ^¯}áÙÁFgÉW¯m>•^=2ΦºŠÑvûÒÉ 5¾øwqqã«íTôi”…^Õ?…>Ë¥Üêiqþ¢íJ^™óã½1ëšð]Cá÷Š`·½Ò¬ûä¦;ÖµçÃýZoxzÍcý唁¥ö¯eËûÒ|þôå·> Ô§ñeò§î¢ÆãY><™üMñI±†7òío8ã­{GÏïU³,üÿ´ DÐñÄ ‰"^Š¯øëþ³Nÿx:öm­ž†¼gã¨>fœÚ΀=;Â?áÓÆ?吭¯-}+Âò*ißõÈVÝ3Ë_J<µô§Ñ@\YÁu ŠxÃÆz©¨ì´»-=JÚ[G=vŠ·P\Nc ˚d°´— ÇÈ9¯ø†øѦãû«_@)%=q^ñþKN›þêлÚÿÇ¥¿û¢¼7âbÜ·Ä(~Æ؜WÜ×¹[- 㢊å5êøš=e„‰ÐPះº†¥«Üjþ#y¡òÕOaŽµBO‡Þ"ÓÙ´[2_J’BŽ¯mUa¦Ê1Nùñހ<ÿPѵxUtÍ +/<ȸq鞵‚ŸuøFX0Åä¼²zW®ã 4|ùÏ4Ïx#KŸDðÔVw#©ÉÏ|Oð­÷‰¦ÒZÉ7 yw?ç^„CÈ4à4Äø¿Á‡Ä~´PÛo,ÐyQX>ðïŠo®#‹[”Åk¼+Õ0ÙÎh;Ï\Љj^ñ&Ÿ©êi¤‚Öw¼}*ŧÃ+ãág†a‹äæ3ï^Ì7ZOŸ9æ€< xÅz†­¤Ë¨!hìÈä׺[æ;dF꫊“/ïMÚކ€<ÐxCQÿ…„š¾Ïôpܚ_x3QÃâ þ>`Æ;×¥üøÇ4à4æV^ ÖuÏ _[k× æÜê‡øMy—Œ4_è: vwùûS(Œžã5ô×ÌNH5ÍxÓÂQøÃMK9ݕUƒq@&·àÝCUÓ´=Iùîb¶P𫞠ð-ø¾ŸR×lÒ¡]‡Þ½+K²þÌÒ­¬S%`@€ý*ÑÜzƒ@0Þ ñO‡µ ì´9 °¹—{·¦k«ÔíhÛ¿jè(¢Š(¢Š)’ÿ©÷M>™/ú—ÿtÐðßýn¯ÿ_ üè£á¿úÝ_þ¾ùÑ@>ÿÈ·/ýwoæk·®#áü‹rÿ×vþf»z(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢šÌdЪ6”…äÔÜ,p´²¸H—©&¸ýKÅÒ]IöpÏÁ˜¹@&£«ÙéêMÕ£öBy5ÊÉâ c_¸0èÖíl‹Ã<ƒ†«oƒ ò‹­nfº›ªŒýÚì`µŽ•Uz`PcðþÃíBöùäšìœ°'+šë­ì ¶@°Â‘ýÁŠ²”´@¥¢Š(¢Š(¢Šä>$ÚÏyá ˜mâide *õ¯ðwŒTóÍ?ï‘G•üóOûäPƒÂÚñý.¿ïƒGü-¯ÿÐëþø5ï>TóÍ?ï‘G•üóOûäPƒÂÚñý.¿ïƒGü-¯ÿÐëþø5ï>TóÍ?ï‘G•üóOûäPƒÂÚñý.¿ïƒGü-¯ÿÐëþø5ï>TóÍ?ï‘G•üóOûäPƒÂÛñý.¿ïƒ\¿‹|CâŸÝZ,ºÊ,l?€ú×Ô>TóÍ?ï‘G•þü¨+±I†,#• +:ÄSÚ¶(éEQE5QrÇ“b³ê{TSÀÓ8üÅNªBŽ‚€¾xø»m¬ÛüI´Ôôý:k„Š0r‹‘_CÓJ+uP~¢€<?‹.Ž$OøGî¾Q¸iámx¿þ€_÷Á¯yò£ÿžiÿ|ÑåGÿ<Óþùàßð¶¼_ÿ@ ¯ûàÑÿ kÅÿôºÿ¾ {ϕüóOûäQåGÿ<Óþùàßð¶¼_ÿ@ ¯ûàÑÿ kÅÿôºÿ¾ {ϕüóOûäQåGÿ<Óþùàßð¶¼_ÿ@ ¯ûàÑÿ kÅÿôºÿ¾ {ϕüóOûäQåGÿ<Óþùàßð¶¼_ÿ@ ¯ûàÑÿ kÅÿôºÿ¾ {ϕüóOûäQåGÿ<Óþùàßð¶¼_ÿ@ ¯ûàÑÿ kÅÿôºÿ¾ {ϕüóOûäQåGÿ<Óþùà§âç‹G]äÀMWOºü“ù ¥ÌÓp/5ïòAÆ~ª+•Õ¼!o<u¦¤v×½wíægâߋ”àè9ÿtÑÿ kÅÿôºÿ¾ w–^(¸ÒnÏ\³EU8ûNÎ vOmq +Í +Æñ8ʲ@ÿ kÅÿôºÿ¾ ð¶¼_ÿ@ ¯ûà×¼âa‘~B—ʏþy§ýò(Á¿ámx¿þ€_÷Á£þ׋ÿèuÿ|÷Ÿ*?ùæŸ÷ȣʏþy§ýò(Á¿ámx¿þ€_÷Á£þ׋ÿèuÿ|÷Ÿ*?ùæŸ÷ȣʏþy§ýò(Á¿ámx¿þ€_÷Á£þ׋ÿèuÿ|÷Ÿ*?ùæŸ÷ȣʏþy§ýò(æxÏÅ~+ÒÖÅô•É; {?Âë[‹O[Eu E(ê­ÔWcåGÿ<×ò§À ¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¦Kþ¥ÿÝ4úd¿ê_ýÓ@Ãõº¿ý|7󢏆ÿëuúøoçEXø_ÿ"Ü¿õÝ¿™®Þ¸…ÿò-Ëÿ]Ûùší袊(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š†Ix88©ô <»xšÃ×Sru-mÌ÷’rcnU~”V;_œ‰îäkK xAÆñ]†—£Yé‘mµ…c'ï7­_ŠE + +:(íSt ª§QEQEQEQEQEQEQEQEQEQEQEQE^æVP\ÔÒH±¦æéB•p¡ 3°nëŽiÔQ@Q@Q@Q@Q@Q@Q@Q@50§Q@š–—m¨Àa¼„H„qžÕÄ5ž³àë¦{B×z{•<ùb½(ŒÔ +‘¹U4“¢x†ÏXƒu¼€J¿}‚ m«†ú× ¯xNX§þÕÐØÅy>HáXUßø®;ò-/‡‘|œ8n2}¨°¢£I3Áü I@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@2_õ/þé§Ó%ÿRÿîšàþÿ­Õÿë῝|7ÿ[«ÿ×Ã:(ÇÂÿùåÿ®íüÍvõÄ|/ÿ‘n_úîßÌ×o@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@àfƒÀª· /,Žf=…,÷ +‘´ŽÁ#Q–cÚ¸-cÄwšåÐÓ4>Q8’qÐÕ{ýFÿƺÓôÂÐé¨q$Ï0zWm¢è¶ºEš[ZÆŽ¤õ&€)øÃÚ·ÖíJH¡f^QÇ5Íèšíç‡îÿ²u¼ùˆî èÔW-kã­ëÄ)£[Ü,’°È`k© Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ™/ú—ÿtÓé’ÿ©÷Mp ÿÖêÿõðßΊ>ÿ­Õÿë῝cáü‹rÿ×vþf»zâ>ÿÈ·/ýwoæk· Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š* ¥ +Nu>”Ë›˜á‰å•‚ă,kÏoµKïjBÃO šj6$“ûõ.µ«ÏâMPhºVLh} û¤Wc£éÚUš[Û PÌù iZU¶™h–Ö±„@9ÇsZ``RÐEPEPEPEPEPEPEPEPEPEPEPEPEP%D…› ¢6 p:ÒIˌž=)ê¡TÐPÑEQEQEQEQEQEQEQEQEQEy¯¾'ÿ¨Eh°y¯'@MzUáŸð½/Ï#D¸Çýs£þž¡ÿ@Kû÷@çExgü/=Cþ€—÷îø^z‡ý.?ïÝ{“(aÍy¯Å¨µytN°Œs Šåÿáyêô¸ÿ¿tñÆùÔ«èwOQåõ ѵMG@ñ,7²,©2Hw¯²ô V=WF¶¹Fݹb=kç?ø²ËĨ|ïÍöd‹5sµ im`šU܈ÊY }+ExR|rÔ@ÁÑnOý³§ÂóÔ?è qÿ~èÜè¯ ÿ…ç¨ÐãþýÑÿ ÏPÿ %Çýû s¢¼3þž¡ÿ@Kû÷Gü/=Cþ€—÷î€=ΊðÏø^z‡ý.?ïÝð¼õú\ߺ÷:+Ã?áyêô¸ÿ¿tÂóÔ?è qÿ~èÜè¯ ÿ…ç¨ÐãþýÑÿ ÏPÿ %Çýû s¢¼3þž¡ÿ@Kû÷Gü/=Cþ€—÷î€=ΊðÏø^z‡ý.?ïÝð¼õú\ߺ÷:+ÂÏÇ[õ¶‹pîc®çáïÇa•¼½Á îŠ( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ™/ú—ÿtÓé’ÿ©÷Mp ÿÖêÿõðßΊ>ÿ­Õÿë῝cáü‹rÿ×vþf»zâ>ÿÈ·/ýwoæk· Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š)®ÛV€#ãåk…ñFµ=íÐÐôÂ|çâb=+WÅðÒlŠD<ˉþUªŸZƒÂz°„ß^~òúo›yì hø{A·Ñ4õ·…rç—s×?ZÞU +0)vzuQEQEQEQEQEQEQEQEQEQEQEQEQEË>ͨãÞ¤–AeÏjHdóP>1š!R‘(ców©(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +ð/‰J­ñOH¡†áÁW¾×üIÿ’©¤¼(Úí쬍¬GìVÿtË1þ(±²?òãoÿ~×ü)ÖßñéÐWŸüLø…/‚$¶Xàó<Ò(½û –qöûö¿áKö,ÿǍ¿ýû_ð®S]ñƒé_cñ"ŹÚ5}Ÿ\ÿ…s֟æ¸øqqâCo‡ˆãeza±²òãoÿ~×ü)>Åcÿ>6ÿ÷ì…x]—ÇmQ#Óèîö9Ã8 +ôÈüsk¨ø6M~Än¤”u&ÆÈˍ¿ýûáIö+/ùò·ÿ¿cü+‰øsã¹_–Ûk¼r#Vf8U'ڀ!ûüù[ÿß±þ}ŠÇþ|­ÿïØÿ +©c¯éZœï•ÚK*2ƒÒ´°}(±Xÿϕ¿ýûáGجçÊßþýð©ñIŠ‡ìV?óåoÿ~ÇøQö+ùò·ÿ¿cü*lQŠ‡ìV?óåoÿ~ÇøR‹ #ÒÆßþý¯øTê¹5俦¼â &Š:Fæ%‹ мZÿǤ?A^ûCÿ®ÓÿÞñéÐW†þÐÑ962…;†O¥oøÓþHõÁ?­pš`ÿ‹{þñ­ßxËF¹ø3›Ê5ɉW`=ÆkOàøvdR¡›Œ÷  -7Śø†-S@¿Ž{i¤8['¯J×ø‰ªÉ¬A ßܨŽGeÊÐI­üS¹ð¦‘§Xé¶âyÙ@" Ò¾9귚õ¦—.”¨ó0VÈÁÁê,–9Ò//Çú Ý ^ºÔ4ÝKãNŸ>š[—P6ôÍTñµ©[ü^[˜ã&häcõ¯AñŒ!·Õt–¾Ð¢–æãËV¹mxGÿ êÍJ®7®Eküd)ŽôµQ@(ø·q`öº_‡ìÖ[‰”Q÷kGÀ¿®5¿µÙj°/­ÁÂúהøNHt¿Š«&«…ŽLìi:Uí ~Õñ[V¸´!íÃ7̝(¡Ô¾=ꖷ—¶‰¦.è¨`+Ð>xêisÜ\B"’Ú@¯ `’÷Ä êŒÁÛö¯FýH:N©ùé@µ®ÿÈ +ëþ¹·ò¯%øÿ! _þ»ç^µ®ÿÈ +ëþ¹·ò¯%øÿ! _þ»ç@áEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPL—ýKÿºiôÉÔ¿û¦€8?†ÿëuúøoçE ÿÖêÿõðßΊ±ð¿þE¹ë»3]½q ÿä[—þ»·ó5ÛÐEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPHÇ4µòRÄüª2h ŸÓ4Æ8ËÏò.;Uü!¢É¥éÅî’yŽðýÀ5˜»¼Câßë4Ø¿ k¸‚0ª*ðJ‹µqN¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Ž”ÉdFXö¦Á#J›Ïö¥Ìrñ×ðŒ@ EPEPEPEPEPEPEPEPEPE„€2hj¤ï3È1Ü҉¤–mª¸QßÖ­PP@Zð_‰?òU4÷…{åxĶTø¥¤3päй[ǜ_îŠËñ'†4ïéÏg¨G¸Áô«–ú…´‹ý&?º?ˆTŸÚ6_óóýô(É­¾鉨ožg{Pr#Íwú‡‚ô»ß Â>±í´Æ0+kûFËþ~cÿ¾…Ú6_óóýô(˜·øw¥[øROͳõ¦èÿôíDŸI€·ÙæÎà}ë©þѲÿŸ˜ÿï¡Gö—üüÇÿ} +Âð§‚ì<#©d6MtSÆ'·–û²)SøÔ_Ú6_óóýô(þѲÿŸ˜ÿï¡@¿†¾éžÔnomNIoƋ/‡ze‰Ÿ]Œ´±É5ÔhÙÏÌ÷УûFËþ~cÿ¾…s¾,ø£ø¿cÞÇûÕþ!Ö°¬~ èv¡ä!‹§ šïÿ´l¿çæ?ûèQý£eÿ?1ÿßB€9¾é3jòj,§Í‘vš“@øo¤è²ÀûZ•¡®«ûFËþ~cÿ¾…Ú6_óóýô(Ì“à†ššâÞä’Ý_xÛ5Ókßôwì¢DÚ¶ØصtÿÚ6_óóýô(þѲÿŸ˜ÿï¡@®»ðÏD×ìííîcǐ>R:Öf—ðsAÒ5[}BÜ7›ʓ]ïö—üüÇÿ} +?´l¿çæ?ûèP+uðãK»ñT~ p~Ó~?‰<§x›U·Ô.ÁóaÆߺ?í/ùùþúhÙÏÌ÷Р+Å? +ôŸÁÑåOºðjׄ¾iž´•ošQ†sÉ®¯ûFËþ~cÿ¾…Ú6_óóýô(‹áVÝ°S›’KÖǃüaàËyá±,Ç&·?´l¿çæ?ûèQý£eÿ?1ÿßB€ ×äuÿ\ÛùW’ü ÿ†¯ÿ]ó¯R×5 #¡Ýq>[ô¯-øC_êäƒ)þtîQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEÉÔ¿û¦ŸL—ýKÿºhƒøoþ·Wÿ¯†þtQðßýn¯ÿ_ üè   ÿä[—þ»·ó5Û×ð¿þE¹ë»3]½QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE# ×ã½q´m:róŸ/¯5ÖLáW' äט]Êþ$ø‚–¡|Í6.§¨€:¯i-¦hŠå®?yϽu*6ŒT6ñÕQ~ê +ž€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +ŽefŒªõ4²?—oJŽÞG•w°À=(ÐEåF~楢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢™$©å+¸ 7AQC7Ÿ’äíNn#ƒƒÚ¤UT\(À ½)h¢€ +ó?ü.>0Ôᾎ顒>„W¦Q@> k@`x†ãï_øRúßý 7÷ѯo¢€"ÒcÔôé”´ñŒÅŽÆ·ê90Šåÿ­Õÿë῝cáü‹rÿ×vþf»zâ>ÿÈ·/ýwoæk· Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š(  ¸}Š[²Õ=fj÷qÚé÷2Jp d®(„³‡ûoâՐæ8FÒ;W¥F2I÷¯=øck,v7òÎ2^RPŸJôDQ@¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š À ÈÅ° T6ÅÜŒö§¤é$…œw©@ÇJ(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢«ÜLëòF¹j’bâ3°eª+h¤\¼ŒwÕ,!ÄcÌûÕ%QEQEQEQEQEQEQM–AO#}ÔRÇð Q^YsñãÂö÷rÛùW.ñ±S´wü/Ï Ï­ßýó@¯EyGü/Ï Ï­ßýóGü/Ï Ï­ßýó@¯EyGü/Ï Ï­ßýóGü/Ï Ï­ßýó@¯A¯(ÿ…ùá¯ùõ»ÿ¾hÿ…ùá¯ùõ»ÿ¾hG⏈oü=¡Kök?=$ÝŒí¯Ÿ¼;âýjóÅZdS_H°‰ÆS™/ú—ÿtÐðßýn¯ÿ_ üè£á¿úÝ_þ¾ùÑ@>ÿÈ·/ýwoæk·®#áü‹rÿ×vþf»z(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢ŠF8× ñ.é­<0®‡–”Šî$ûµç¾8ayyšß2– ¶€:o ÚÇ…fcó# kxtª\^U…´``"Š¿@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@5Æõ+ž´9! '²ÊÌd“‚{P°Â°¦ÑRQEQEQEQEQEQEQEQERÉéPÇp³9TQހ÷_¾òÐd÷5`ni«!ʌ}QEQEQEQEQEQEQE^ûþA÷?õÉ¿‘«^ûþA÷?õÉ¿‘ þh:n¯â½X_[¬¸±‘ï^ÎÞðÞãþýò+Ê~ ÈÙ«×süëÞ%;GþèÍsŸðxoþ|"ÿ¾Eðxoþ|"ÿ¾EWÑüo¯ât…‡kGüT–^9†÷ƒølC‰#ß@áðßüøEÿ|Š?áðßüøEÿ|ŠéÁÅ%sŸðxoþ|"ÿ¾E(ð†ÉâÂ/ûäWEX>2ÕeÑ<5u}ߍ2(3à ƒƒaýò(ðà1ÿß5ÃÝroøFFà~ñ؊éèÿ„ Ãóáýò)?áðßüøEÿ|Šèè sþ/ ÿτ_÷È£þ/ ÿτ_÷È®ŽŠç?áðßüøEÿ|Š?áðßüøEÿ|Šèè sþ/ ÿτ_÷È£þ/ ÿτ_÷È®Œ Ö%׋4«=n-"Y±u/Ý\Pø@¼7ÿ>ß"ø@¼7ÿ>ß"ºB1I@çü ^ÿŸ¿ï‘J<Ἇô¿ï‘]*ýáõ ž~1xLÒ5M4ØÛ¬D̹ÀÇz÷íþ@¶?õÁ?¯øéÿ!M7þ»-{^ÿ KúàŸÈPê(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +d¿ê_ýÓO¦Kþ¥ÿÝ4Áü7ÿ[«ÿ×Ã:(øoþ·Wÿ¯†þtP…ÿò-Ëÿ]Ûùšíëˆø_ÿ"Ü¿õÝ¿™®Þ€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€9Ÿx×Oð|Ë|N¦+Žÿ…í ÌG¨ZÌøò‹$Zr¸~µÖøSÁºþ±’]>v@K  _ø^ÚüðŸþù£þ¶ƒÿ<'ÿ¾k±ÿ„ÿôƒþø xäñ¦Áÿ|Pÿ ÛAÿžÿß4ÂöÐç„ÿ÷Ív'ÀÞtØ?ïŠ?áðïý ÿ¾(oŽºC?ýó\mÿÅK Ÿ[ê~Díd‹‚6ײÂáßúAÿ|QÿO‡±ìè1þåq‹ñÓAV8‚}½†Úwü/mþxOÿ|×cÿ?‡èýñGü þÿ t÷Åqßð½´ùá?ýóGü/mþxOÿ|×cÿ?‡èýñGü þÿ t÷Åqßð½´ùá?ýóRAñËÃóÜÇÙ¤`£pÅu£ÀþÈÿ‰l÷ÅyÆLÒ®ô¶²µŽ"fÚ¸ï@ùir—v±ÏÝq‘SV_‡ägÿ\‡ò­J(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š('&Škml¡<žÔsù’_º;ÔÕP¬+µjJ(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š) +2N…êqQMž“…ö Ê΄Å:8’%ŒRƂ4 +½:€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +¯}ÿ ûŸúäßÈՂ@êj®¥¿û.ëËûÞScò  +ø1ÿ#f­ÿ]Ïó¯w¹ÿiÿÝ5àÿ³ÿ V«ž¾qÏç^ñsÿÓÿºhÀtéžø‹y>¢$ÚrÅÍMàÝnÇXøÇ«Z–[Uˆ±.0qW|ggyñ.ñ.­¢œs€ëšÅ»->'ëQÙB"A|‘Œ(¼ºøÁe«åC ½§™å™BñšÖñč/G´·–ó¤›*ó^Sàí+TÕü)hÔ,~0éÒº%Ôo•±#¨¯H¶•g‚)×îÈ +ðŸÁ¦®áÓlù…%G5íÚ7ül?ë’ÿ*ñŽŸòÓë²×µèßò±ÿ® ü…x§ÇOù +i¿õÙkÚôoùXÿ×þB€/QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQES%ÿRÿîš}2_õ/þé á¿úÝ_þ¾ùÑGÃõº¿ý|7ó¢€,|/ÿ‘n_úîßÌ×o\GÂÿùåÿ®íüÍvôQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEâÿ¾î›þðþuèþÿ‘COÿ®b¼ãã·ÝÓÞνÁÿò(iÿõÌPÕs_5»øBãR´8š25sÄþ%³ð¾•%íË ë÷SÖ¼Ûž.ŸÅ? ïn%²6èÌ6üTè^ Õç×|3k}rs$‰“]yg†ü]oáoØnQ%ÃGòÇë[žø‘i­‡[ÈŬª¥‚žôÛÑ^hÿà“„´-g ìi»fµn¾%éöÖ w€Uþèõ ڊóÝâ’jÑÓní>ÎÅ7¡?Ä*í—ÄHoZð,Ù9õÅv´W§üFµ¼ðÔÚԑìŽ) +b² ø¿m&£2Z”µ•‚¬Ç¦hÒ×ï +ñ_Ž?ñó¥×aüëÚba$qȧ*à0¯øãÿ:Wýv΀=sÿò³ÿ®CùV¥eøwþ@õÈ*Ô Š( Š( Š( Š( Š( Š( Š( Š('4§qU­âbæY3ºÁ’rª¹AüUb€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +)®ÅT2j½¸™Ø¼‡° h$š|³b1Ú­€íKEQEQEQEQEQEQEQEQHX¦€sƒQL¯"íC·=é`‹ÊL“ÜÐ^LÏ.]þOJuèƝr?é“#V*½÷üƒîë“#@ðcþFÍ[þ»Ÿç^ñ(ޒ'÷†+Áþ ø«5nGúóüëޘeÌ?:âô?6âyµs(a'ðÓ-|!ñ­Þ»,Šñ\!FØ×oö—ó£í/ç@Yqðžá5mú}óC§4›ÚØÍkx—á¼ŝ²YHa¸„‚d'“]î?ڝÿi:ó-ádÚnµ6¡{t&¦ÆÏGSø;quqr-o|«IÄyé^·ö‡çF?ڝp+ðÒÙüo¢ÎÀÜ[ÑJ;ƒÃÿ î¬<öÔïšáÜa>lâ½í/çF?ڝr>ðcxgPººiC‰»Õ»¯œhgý“Z8ÿi:ŠâÝ.mÞ +”a‚3@<øCÂW~'½Õ µ»ò`f>hÏ^kÓo>ØÍá¨të|%Ô#喺}Ö²Éfª/-Íkãý¥üèÊto„·v ³Õno|Ö·Á9Ít^ð9Ð|I¨j¦PÂí³·Ò»L´?:1þÒþtÁø£ÁZ·ˆ®|±|ÁŽ^2zÕ{_†1Ùx†ÏS‚PÞ=›}kÑ1þÐüèÇûKùОéß šÄê‡Ïí®[隩¨øFÇÃþ»²Ô˜I ßÝ5é¸ÿi:­§Zꖍkz‹$-ÕI ™õ+x.lR L]ãdjs´WÒÚ@#G±`ùkÅszwÃ? é×ÿkŽÙKƒ•Éé]z" UR¡W Íx_ÇOù +i¿õÙkÚôoùXÿ×þB¼Sã ÿ‰¦™Èÿ\½ëÚôoùXÿ×þB€/QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQES%ÿRÿîš}2_õ/þé á¿úÝ_þ¾ùÑGÃõº¿ý|7ó¢€,|/ÿ‘n_úîßÌ×o\GÂÿùåÿ®íüÍvôQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEâÿ¾î›þðþuèþÿ‘GOÿ®b¼ãã·ÝÓÞνÁÿò(iÿõÌPž|dµm5e'ìčàô­GfŸ1måì +˜Ú~µ×x·Â¶ž,ҚÖãåáaÔW+Ã{£á9´+‹–’2~BOjò@\=ÿ†ÒPÄ2Jèu_ Lš’ê^r£ªÝÆz× ]|3µ¹ð彙b·.AÔTžøz4ÍÒj7<›J¨c‘@{§E`ÿ 5BÂ!/È'œÖEÂFÚ^œ¤»×Æ»›Ïƒ~t÷ Ó¥´òodŠÔ† +mm Ä$øP¯Etá…cè>•‡Z5þÚ ê§kðMz=ï€VóÅš³7Ä##Ú±õŸ„ßhÔZ}>ᣎSûÁž´Ãé`7Â;±ü?j?Χñl6|1Ò¸ó—•<×Qão ÚxOáºéÖÇäwùÉõ¬Ÿü3]rÆÖêæéÞÒ6¨Ozõ¯ ;¿‡,L„–ò—¯Ò¼¯ãü|é_õØ:öx"H!ŠÀ …{WŒ|qÿ+þ»ç@¹áßùYÿ×!ü«R²ü;ÿ ?úä?•jPEPEPEPEPEPEPEPM,¥¶gŸJSœu¨!…ĆIÍڀ&HÖ1…§QEQEQEQEQEQEQE ÄâÎ2{SfºXØ céSA`3ï@Û¼Ž›¤\g¥MEQEQEQEQEQEQEQEQœu¦™6ÒÃ>”É£iFÜá{Ёƒt9ªËlÆc#¹ÇaSE»T“õ©(¢Š(¨®Ëi4k÷š6QøŠ–Šù®ÏÀt-jöïKBÍ+09ê3Åk?âé9ò—ó¯}¢€< û;âïüò_ΏìóÉ:÷Ú(À¿³¾.ÿÏ%üèþÎø»ÿ<—ó¯}¢€< û;âïüò_ΏìóÉ:÷Ú(À¿³¾.ÿÏ%üèþÎø»ÿ<—ó¯}¢€< û;âïüò_ΐéÿ@ÿR?:÷êFÎ(æíGRø™¤ÝÁkw%¸8LÓ[‹Œ2"=ó^“ãë6}+ûLž×‘í[Ô_Qðí¥Ó¹fqÎhÈ?³¾.ÿÏ%üèþÎø»ÿ<—ó¯}¢€< û;âïüò_ΏìóÉ:÷Ú(À¿³¾.ÿÏ%üèþÎø»ÿ<—ó¯}¢€< û;âïüò_΁§ü]ýRþuï´PÍ:¯€¾$xŠþÖ]JÝJÅ"·_zú7N…íôÛX_ïÇ«}@«4PEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPL—ýKÿºiôÉÔ¿û¦€8?†ÿëuúøoçE ÿÖêÿõðßΊ±ð¿þE¹ë»3]½q ÿä[—þ»·ó5ÛÐEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP‹üvûºoûÃùפø=ü":xÿ¦`×ñ{šŸ‰mmF›wž+‰²Ò¾'XÙÇk˜#ŒaG4ôÆ¥Úßäׂý“â—÷¥ýhû'Å/ïKúмìj61¯û'Å/ïKúÑöOŠ_ޗõ zÚßäѱ«ÀÞŠ)Õ¤õïPÂß®fvÛÁÁé@@ìj]þMx µø¤FCKúÒý“â—÷¥ýhÚµ +Ï^´º„~d@ä Ôºv•o¤Ú-­šm…z +ñ²|Rþô¿­dø¥ýéZ÷ „ñ_ŽjVãJ'þ{çYÿdø¥ýéZÊÔ|ãïj6m©£¼QHæ€=ÿÿò³ÿ®CùV¥QÑíÞ×J·‚A†DŠ½@Q@Q@Q@Q@Q@Q@(¦SÌòÉùj…&y.p¿êÅY¦ª* (Å:€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +ÏC&Àriw UnE2+tŒîÆX÷ P>üsRQEQEQEQEQEQEQEQQ5Äk Bß1  ‚Œ±À¤WYPæ™4>v8^ã֞‘¬k… +Ú¯›æ1%»UŠ( Š( Š( Š( Š( Š( Š( Š( Š( Š(  zÇûGI¸³Æ|Á\·ÃûúëJíjHÅv¾£‘a-õÁÄQ©,k稾.ZøÄ7׶0ùé;t ¤ÐåE:¹Ÿx†Oh먼^Xd/¥tÔQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQES%ÿRÿîš}2_õ/þé á¿úÝ_þ¾ùÑGÃõº¿ý|7ó¢€,|/ÿ‘n_úîßÌ×o\GÂÿùåÿ®íüÍvôQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE‘âMZ=F¸»™‚¨B÷Åx·Â_\ÝøªóM¸˜´sÈY zf»ŒPjšž†ÚvŸÃs^àß ø†ßYŽþÂ&Ìmr}†)j¦˜òI¦Û´ ‰ + Ùõ«tQEQEQEQEQEQEQEQEQE•^+}²–íMY$’灈ÇZµ@Q@Q@Q@Q@Q@Q@C:¼‰µ3Þ£™f–PªpêÊ®Õv à„Bs“ÜÔ´Q@Q@Q@Q@Q@Q@PNMבcRÌpFnSÌØ2}Å,°,¤Ï¨REž2W84Ô¶EmÄnoSR… +0–€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(ªZ¼­y*pÉ 0ü¨כüôOΏ6?ùèŸ÷Я™<9'Žüeywý™å¬r0;›ÞºOøA¾(ÿÐV?ûî€=ß͏þz'ýô(ócÿž‰ÿ} +ðøA¾(ÿÐV?ûîøA¾(ÿÐV?ûî€=ã͏þz'ýô(ócÿž‰ÿ} +ðøA¾(ÿÐV?ûîøA¾(ÿÐV?ûî€=ã͏þz'ýô(ócÿž‰ÿ} +ðøA¾(ÿÐV?ûîøA¾(ÿÐV?ûî€=¿P¶³Ô¬¤µ¹1´R 0$Wɼ '†|Eû¦Öáÿw· Íz)ð/Åÿ1Hÿﺣ¨|,ø…«*­åômèYÅ{€"†ÓÁzta,gšé¼Øÿç¢ßB¼ +ßáçÄËHµ8Â'Aº¥ÿ„âýcÿ¾èÞ<Øÿç¢ßB6?ùèŸ÷Яÿ„âýcÿ¾èÿ„âýcÿ¾èÞ<Øÿç¢ßB6?ùèŸ÷Яÿ„âýcÿ¾èÿ„âýcÿ¾èÞ<Øÿç¢ßB6?ùèŸ÷Яÿ„âýcÿ¾èÿ„âýcÿ¾èÞ<Øÿç¢ßB6?ùèŸ÷Яÿ„âýcÿ¾èÿ„âýcÿ¾èÞ<Øÿç¢ßB6?ùèŸ÷Яÿ„âýcÿ¾èÿ„âýcÿ¾èÞ<Øÿç¢ßB62qæ/ç^< ñDŸù +Çÿ}×;{ã_ x£N´Õ¯|Á,À|­Ôf€>œ¢£‹[ÄÇ©@J’€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +d¿ê_ýÓO¦Kþ¥ÿÝ4Áü7ÿ[«ÿ×Ã:(øoþ·Wÿ¯†þtP…ÿò-Ëÿ]Ûùšíëˆø_ÿ"Ü¿õÝ¿™®Þ€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€*ßû5ÆUOîQí\Âð¦ßVÊ)ýùí]õ÷üzÜ×#ü«ø]ÿú·ýv?΀=/¹O¦E÷>€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +‰¦U”GÜÔµ +@†F9nÔ6éEPEPEPEPEPEÉeX³P‰ÀÍUIfšrmEýjH&iÁ%p½ªpé@Q@Q@Q@Q@Q@Q@„€ =@—>d›c½I,Éå>”FÞtYe#=©^$r .H§Ðq‘ýÑRQEQEQEQEQEQEQEQEŸ®ÿÈÿþ¸?ò­ +Ï×äÿ\ùPŒ|$^j<ÿËf¯r,wMxoÀøüÔë³W¸Ÿ¼~´n>¦ÇÔÓ± ~joFê£)ú7SFãêjº¶I<¦ž=þ›…:Y¡·PÓJˆL¶(MÇÔѸúšg›•çy¨#þöx¢9b7Å"ºÿ²s@Ü}M©¨¦¹·¶ÇŸ2!=lSՑÓzº”õÏíÇÔѸúš….ídÆ“ÆÎ;-.ãêhÜ}M2Yb7Í" ÿhℒ9ÌY§÷³Å?qõ4n>¦¢ŠâÞrDS#‘Ô¥ùGWQøиúš7SLYb‘£‘[hç5ÁÅñ:¦“+´ê8ÏZjIªY$R£©Š~æõ5NçZÓ¬§X.¯)Xà+MX†æÞYvG23 0¯ž~0\Oĝ9RFUóW€}Å}ŒX©*yà_I><Ñòå¸þuï_ñãiÿ\—ù +ð‹Ÿò>hÿõÜ:÷Ûoøô‡ýÅþU-Emÿÿ¸¿Ê¥ Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ™/ú—ÿtÓé’ÿ©÷Mp ÿÖêÿõðßΊ>ÿ­Õÿë῝cáü‹rÿ×vþf»zâ>ÿÈ·/ýwoæk· Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š(  +·ßñëqÿ\ò®áwü{êßõØÿ:ﯿãÖãþ¹å\Âïø÷Õ¿ë±þtè±}ÁO¦E÷>€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¨^áRQRh2%{G:ÕªQEQEQEQEQE1¥E`¤ŒúPK2D2Ɓ²dŒƒëM6èÒo9'Ò¦@Q€0)h¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¤cµIô ¨f¸Xx ’zS"æ—åRzՂªNHÐ",ñæAŒö§**}ÕéN¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¤­Ðƒ@ Yú÷ü€/ÿëƒÿ*’y.P z“PkA¿á¾ß÷¼‡Ïå@7ð#þ?5úìÕìÚ½Á´Ñ¯n8ف¯øÿšývjö]fÜÝè—ÖëËI(òþ•sâŸjšÅõŽ¡2Gnœ‚¶~xÓQÓ´^kûÙgtV ½³ƒXºþµàkíkOm:yä2‚«W|ákí_EÖKi#r”0ë@žÐüCâE¼K}¨Ì¶Ê_nx v¨u{Ý{â'Ä4½6òXmaùNÓéNøuãOB”øZöÆP“ÈcoJ©ss«|3ø‹qyœ’[Íód/¿ã=jûM—Nðjê BÓÉ©ü ®ßø{ƦCs=í¼ƒå2rfxÆÆ}CVÓ³ªÛ^I®MçÆْn¦¾#h>Ë_)xfµ?ˆÖ—µÅ¼MÒ +êÄ !ØççۂhæÿëZ׏>#`é÷r[Ãìm†´þ ꚧ‚´›_ ÛÞH÷ .yâ°u˜5O‡Ÿ¤ÖVÕ巚BùQZãÔ<]mcâ‹+I6Û`”Ç8ÐJÍ®|=ñ•-Æ£4ëx™ñÍ'ˆõê¾.XôíBdó·–ŒSu-Bçâ/ˆ4Xm¬¦ŒÚÆB̊ЏM¾µø‹e“dp•ßŽ:PƒÚÖ¯/‰µ 2öîIp¬¤1Î rSè„ß泎åÖc>ààóŒô®¯áE•ä?õ9&µ‘³a˜qÔÔ°ÙޏrMöi<­ßPgŽ/~¦œãšZ ¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š©=̨ábu[$“Ò q´»î>Õ"åãÆ ŠlvÑDő'½6â9d\Fû}imíÄ ×-ÜÔÔPYúïü€/ÿëƒÿ*ЬýtgA¿Çüðå@1ð#þ?5úìÕî'†?ZùËá/Œ4O ÞjU¸0™±‘ï^®~.x+?òÿÇh­“N²–S$–Ñ3·RTRÛÙZÚmáDÏ\ f¹ø[ž +ÿ Ÿþ;Gü-ÏÐOÿ ‘ô )ïEᵏÏ!‚Ô·úFŸª*‹Ët“oBV¹oø[ž +ÿ Ÿþ;Gü-ÏÐOÿ ­´Ë±û[¡·Æ•éLÓ´m?HY[${ºák—ÿ…¹à¯ú ÿã´ÂÜðWýÿñÚèî¼=¤ÞÜ ‹‹HÚQÎvŠ¸ö–òÚý•áC1´Šä?ánx+þ‚øíð·<ÿA?üv€:[ LÒݞÎÕ#fêBօq_ð¶üÿAAÿ|Ñÿ oÁ_ôÿÇhª¿Ò¬uD yn’Ó"ŸŸgŸÙò1¸®Kþ炿è'ÿŽÑÿ sÁ_ôÿÇh¥²Ðt½6V–ÒÖ4vêBՃahÓŒ æâÇ5ÉÂÜðWýÿñÚ?ánx+þ‚øíu±iö–ò"ÏR`´ó¼ÿ%<ßïcšä¿ánx+þ‚øíð·<ÿA?üv€:Ö°´y„Í +ñcš™Ñ$ŒÇ"+! Œ×ÿ sÁ_ôÿÇhÿ…¹à¯ú ÿã´ÒZxJ°¹k‹kHÖRs¢¬Íaiq ’hÜt$t®Kþ炿è'ÿŽÑÿ sÁ_ôÿÇh¶N +Ðt¯ø¹ÿ#æÿ]Çó¯G<ü„ÿñÚòˆ>'Ò|Iã}"M*c2‰×'ôô¥·üzCþâÿ*–¢¶ÿXÜ_åRÐEPEPEPEPEPEPEPEPEPEPEPEPEPEPL—ýKÿºiôÉÔ¿û¦€8?†ÿëuúøoçE ÿÖêÿõðßΊ±ð¿þE¹ë»3]½q ÿä[—þ»·ó5ÛÐEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP[ïøõ¸ÿ®GùWð»þ=õoúìw×ßñëqÿ\ò®áwü{êßõØÿ:ôX¾à§Ó"û‚Ÿ@Q@Q@Q@Q@Q@Q@A-ÆÉV02MLX/SŠh oÆO­éÛØUšjPnëޝEQEQEQEQEQEQEQEQUg½¶ÀŒÇÚ§½ˆgŒŠiž1 LäŸJK4®#ïޛ¤q9q’}êÅW¶·hTîrÄõÍO€qKEQEQEÑ,ð£ò¯C¢€<óþׅ¿çÔ~Tƒ^ÇüzÊ½ƒÒ€£ò¯C¢€<óþׅ¿çÔ~Tšð·üúÊ½ŠóÏøS^ÿŸQùQÿ +kÂßóê?*ô:(Ï?áMx[þ}GåGü)¯ Ϩü«Ðè <ÿ…5áoùõ•ð¦¼-ÿ>£ò¯C¢€<óþׅçÔ~U=§Â_ Ù]Eq xhÚXM¨\'Ï!Êät p¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¦Kþ¥ÿÝ4úd¿ê_ýÓ@Ãõº¿ý|7󢏆ÿëuúøoçEXø_ÿ"Ü¿õÝ¿™®Þ¸…ÿò-Ëÿ]Ûùší袊(¢¹]0ëzÿˆÚëRÕ#[[ô‚í契>Ëãj>ó±Ï½^ÿ„F×þ‚šçþ gÿ⨠¢¹ÿøDmè)®àÖþ*øDmè)®àÖþ*€: ++Ÿÿ„F×þ‚šçþ gÿâ¨ÿ„F×þ‚šçþ gÿ⨠¢¹ÿøDmè)®àÖþ*øDmè)®àÖþ*€: ++Ÿÿ„F×þ‚šçþ gÿâ¨ÿ„F×þ‚šçþ gÿ⨠¢¹ÿøDmè)®àÖþ*øDmè)®àÖþ*€: ++Ÿÿ„F×þ‚šçþ gÿâ¨ÿ„F×þ‚šçþ gÿ⨠¢¹ÿøDmè)®àÖþ*øDmè)®àÖþ*€: ++Ÿÿ„F×þ‚šçþ gÿâ¨ÿ„F×þ‚šçþ gÿ⨠¢¹ÿøDmè)®àÖþ*øDmè)®àÖþ*€: ++Ÿÿ„F×þ‚šçþ gÿâ¨ÿ„F×þ‚šçþ gÿ⨠¢¹ÿøDmè)®àÖþ*øDmè)®àÖþ*€: ++Ÿÿ„F×þ‚šçþ gÿâ¨ÿ„F×þ‚šçþ gÿ⨠¢¹ÿøDmè)®àÖþ*øDmè)®àÖþ*€: ++×4oì[KKëMSW2Jƕ!†6mÅ>µ%Ž”QEQEQEQEQEQEQEÍøßZŸAðä÷Öã.€šé+‰ø©ÿ"Mßû¦€<»Gñ¿Ä_Ú=î›j­nŒÕÿíϊŸó俕tÿÀÿ„ ÿZkÒ¾_îŠðïíϊŸó俕۟?çÉ*÷—û¢—û¢€<;ûsâ§üù/åGöçÅOùò_ʽÇåþè£åþè þÜø©ÿ>KùQý¹ñSþ|—ò¯o’X!™‘«R«E"îk)èExöçÅOùò_Êí¿ŠŸó俕{ËýÑGËýÑ@¨Ü|MÕ,d³¸²Sõ£OŸâV—iµ®žˆ‰ÀÀ¯~ùº(ùº(ÿ·>*ϒþTn|TÿŸ%ü«Üp¿Ý†ìáŸÛŸ?çÉ*?·>*ϒþUî?/÷E/÷ExwöçÅOùò_ʏíϊŸó俕{ËýÑGËýÑ@ý¹ñSþ|—ò£ûsâ§üù/å^å°c;&û¢€<;ûsâ§üù/åGöçÅOùò_ʽÇåþè£åþè þÜø©ÿ>KùU]CÅ_4Ë7ºº³Q ±¯{ùº+˜øˆþË4KáwŠo|UáïµÞ€%»ºòŸ_ò*Iÿ] zµQEQEQEQEQEQEQEQEQEQEQEQEQEQEÉÔ¿û¦ŸL—ýKÿºhƒøoþ·Wÿ¯†þtQðßýn¯ÿ_ üè   ÿä[—þ»·ó5Û×ð¿þE¹ë»3]½QEsþÿç‹?ì+þ‘Z×A\ÿ‡¿ä9âÏû +Çÿ¤VµÐPEPEPEPEPEPEPEPEPEPEPEPEPEP?ã/ùÛØWMÿÒØk ®Æ_ò¶ÿ°®›ÿ¥°×A@Q@Q@o¿ãÖãþ¹å\Âïø÷Õ¿ë±þuß_Ç­Çýr?ʸ…ßñï«×cüèÑbû‚ŸL‹î +}QEQEQEQE^âWFTŒd·J–I1–4¨UÀ`:Ѐ…ŽM:Š(¢Š(¢Š(¦ÈÅP2j;‰ŒIò.æì)`ÞcËõ=¨8#”¹yè*ÍPEPEPEבccŠu4HŒåCGjk©–?•±žôØ-Öž¬zšcÛ¼’åŸäì*¨QÒ–Š(¢Š(¢Š(¢Š(¢Š(¢™$©åÎ>ŠbÈ$MÉÍUKyÞc#ÈTgîЉå0Ǹ.ãéL¶šI¾gB£Ò§À#šZ…íby|Æ\µJ–Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š+‰ø©ÿ"Mßû§ùWlNkø§y x2í’ÛMf| ÿ‘ÿ×S^•Ôךü ÿ‘þښëü]­.ƒáË«¼áÄgiô4»°ûQ°çWʶ~6ñɵ»Õi$´$àŸá®žçǚÚ|6R,.Iå¨è=‡Ú¹ïxºÇÂ1C%é˜ákÅï<®Eá=ì\°–isëT~/É©]èšUÕۍðW>ôÚüdñ Áð…–£¦ÌcYHäzíþ\O{à :{‡ß+®I&¼+Äñj1ü2°7ĘH3YºG‰üW¢Ã£Æ'x´ö`GFõˆRN)J^/ñâô:~Ÿ¥¹K«¥¤ÃXžñ¶· ëI¤ê—x÷#†';hè=†«ÞÜ-…£ÜI¨2kæ­kÇÞ.¾§ka3´q·Þþ讓ÁÞ%Ö¼Qðß\Šâf’êB± PÑ|oeâ»[$ŒZâ|/ã_xîM:úÑŎò¼ÿà•¾±ÿ lïo³¢Ÿ?žõ³¤øúêÇâ­çœÛÄäŠú¡Ï)é_:iZύ£â¨táÄÐ.$Eþ"(èÖRªXô5ʧt×כF\}¤kʼãoj^9“HÕ%`V6VCë\5Å®·ÿ Ze·fBã#ŸáÍzÎ¥ã?ÃãÈ졲sb[é^»é-ãr0Ì ‘^ªø£P²øejí÷#gSŞ6ñŠ|Bt¯Ü<JnbèèB¤Rì5àžøªµ•þ¨ÎÒ_[¡ýáëÅqw™/ú—ÿtÐðßýn¯ÿ_ üè£á¿úÝ_þ¾ùÑ@>ÿÈ·/ýwoæk·®#áü‹rÿ×vþf»z(¢Šçü=ÿ!ÏØV?ý"µ®‚¹ÿÈsşöÿH­k  sǺ­æ‰àMcSÓå]Û[™"r¡°r;A® ÀŸõ{ø¢ëė1K¨é1 ¤o-P4rEº1…©qüB»ŠòKüCÿ^üÅxw‹ì/í¯<;e§ƒåø³CÓí%Èþ41Ž?OÀšôƒ>6ñ/‰ïu¸¼Iz“ H`–1ä¤{†$ vÇZê#ø½ài5/°®»ýþX”Äâ"ޞf6þ9Åyö‘¤ÜÏ®üYÒt|Ç9µŽ u^§à(úÆ²ßÅ>“àl~ŠÝÛÄ,«Ó…³y¢ãÌÉ~zŸ^Ôí¾%ñ§‡ü#¬ê \C£Hòtèª Ç#šât_ˆ×:ÏÄ_ç^ CC³Ò ݵ¼qf•Bdg³’ÃקJæõ5“ÁŸ<«ø ¿ö}¶Œ–rÜw¬3„`AÆyË/?àjυõˆµ?-Ö|=mç,Ú)–Ð:Öå”Æ7 àá™HÏ~´[@ñüc¢K­iž;ÓbÕw1‹AñŒàŸ“-ÎHÆ#¦O\z¨ñ?öƒmõy:M [˜Ã‰™’0›s»8È$¡¯Õ5_†^!ðååö³¦I¢ø°o igˆæQ˜ÙϘàç5g^·ñø_à WX{„ŽÂô½ÔÒCç<1–ýÓ¼m÷€QßÔôí~ñLJ¼[$ñh÷âYँãhäU=ö°þãÔV]ÇůZêma&¶›ÒO-åX¢FÎ0d ·ñÎ+…У‹Äþ?»Ô4ÏÜêú”:L¨tÔ·ƒ¬3†°bNÞ8ÊðwŒ|/ᯆxk_Ó Î±Û¬ú<–Ç|îdºA c¯÷qé@×7Š´ˆ*x[[¶¹µÑu¯ôãc5Änmd" ŠÇs¸ãÁëÇ­rڧř¼?àL5u]GR•¼ËÃjѯ’$u.(ä`(ÙÁ«_ì­í¿gyeŠ5O§ÞÉ#àeŽd~€¸Hù<{ "ÞÛVJàgjù“sŽ´íšO|;­êöú]•ãµÝůÚáI tߨ,Ï^:ð}*îŸâ'U×µÎv–÷NÛö¥°XÉè7cõàÇÒ¼çâ=ý¬ á_‰Ú3}¦ÚÊàE<‘‚ –ÎH=GL–÷zÙø7¦O„§×ï€þÐ×®žúfﴓ´}:‘þõ3âv¿â3]𞗠j‹§¶­u%¼²5ºL1…8aÛqèGZȓÄ^7ðgÄ H×õ›-jÇY”À¢+t†HÎàaFz°õžô¿l#Õ|Wà>i%Ž;›ébg…öº‚bSØ×Káÿ„þðö¸šÌm½¿Œ~ê[ë4Æzdp9ú稟±ø¢šOŽ¼]câ]SnŸc4qØĖûœgqll]Çž•ÝEãoMáoøI—U„ispÀŒãi\nݞ1Œ× ðþ(ßãÄGh՘I +‚FN쏡Àü«…ðî·>‡ð#Pº‹M´¾Îºñ7Úàó£J/ï +ãœ}hÙ¼=ñ'ÂÞ'Õ?³tÍEšô¦õ†X"àrvîÕc3¨+À;P`†#<ö­-o\ð¾§ð•µ[/>§áÿ0–²~ύ®rØ\pdã×5ÈÇsáÏüOð|¿-#hMF[Kc +$|¯ÀÆáï¸ Ð¬xËþ@vßöÓô¶è+Ÿñ—ü€í¿ì+¦ÿél5ÐPEPEP[ïøõ¸ÿ®GùWð»þ=õoúìw×ßñëqÿ\ò®áwü{êßõØÿ:ôX¾à§Ó"û‚Ÿ@Q@Q@Q@Uk§uÚ¨ ÝÔÐæ€LÊIàT 0‘®Ä@Q@Q@V–ël¢$cOÒl^O|SÖ5V$OzP2`3N¢Š(¢Š(¢Š($¦£yÑ ç҉J˜'г+¹U9¨ÚÕZo1˜Ÿj’(VÂþu%0(¢Š(¢Š(¢Š(¢Š(¦³ª ±{ѸʜЪ9¦X{gÕ]ÓO’@Œv«eC  AopgíÀíD–‹,¡Ùªp)hBŒ(À¥¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(£¥! ö ¢ª‹Õ3yaûÔÓ gÊ 7½I‘ëPÍp}ìþËxeSºVËTìŠÇ, Ap· ¹ǽA*\I&:'µ[ +`>”´Ô\&ÓÍqá‰|vB í<×s\OÅOùnÿÝ?ʀ1>ÿȁÿmMnüKÓfÕ<t.æXÉÅa| ÿ‘ÿ×S^’è²FѸ`ƒ@%Øx±,üs¡Ik(›$ -k=ÕßÂ4ò¡rAɯ}oxy¦yM”{Ÿ¯ËWíü;¦[iÏa öw#ò£kú¦ƒ£h¶Ñ¹¼ŠQ¼cÞ½ã=´öþ ðü.Œ]BäÒ½>Ãំ´ÝCí°[86àHï[š¾ƒ§ë±Æ—ÑXþèÇJðÿˆk#|$ÒF' Æ:W5« ¿áðÈòÜá‡é_I]økL¾°ŽÆxCAÝ\Tx?F–(bx¤?pc¥x'ôi­.ôk˅Z¾ :º+oC´ðÞ« ösMqv‹ÁnpkÚõ NÕ4ÿ°ÝÀ¯+7Dð.…áòíen77RE|ùœk:þcq’{WKðyd_ ø(ÊpØȯfÑÖId.é~ÿjm?Ãzf—ÐZB9¾ø­xÿÀÁ"êšÖäewQ\:eΩã­nÖ(Ÿs;q_OižÓ´w‘ì¢Ò}ì +Š×ÂÚM–¢÷ðÀ¢áùcŽ´á ¼iià™õTŠE’ISŽ¦²›QoüN}næÞCmp¥ë^÷}ðÿÃڎªº”ö«ö…9Èêî¡áMTò¾Õjå /Ë@ðêøêßfÔ'HæÜÃp­Ä¿ð¼$mß{íÖ>Ñ´ËÁwin©( TƒÃ:XԎ£ä´žwb€<#ÅQK'ŅAëŒâ³´ÛÏøWÿn®u8_ʞ#µ±Å}/†4¹õ¿’n£b¡×¼¢ø–5]BÝX¯B4ó׃íåÔ5ýoZ†û4ˆåXŠÊE›þí@yO̍Æ+ê 3ÂúN‘¦>ÒÝV¼Óü¸÷3l\¸ÃuúÓ¨ ¬h±ùjŠ¦Ð8ü©m–æÝà¡=cdO~*Z(„ñǁõ4dêiþ(‚æÎ+p^B¬O ÆÝã¦Ev¶–°ØÙÁil‚8 bðªŒù +šŠkFŽÊ̼̊©#8úS«ÏôŸj×_uÿÍtJ´Óãž<µ\ˆ²wcqûÍÔ÷úWuwwoai5ÝÜÑÁo +’Y +Š:’h@ˆ¬Ìª¡›ï9?ZoÙá4B(ü·2m9ë‘\†•ñ[ÁšÖ©e¬©¸•öEæBñ¬è¬Àj÷ˆ¼០_Cc«jB+¹†å‚8žG êBƒÁë@ñÚÛđ¤pD‰ÜU@ý=)ÊÖK•¹{hZuû²˜Áaô=kHñ÷†uÛ}NæÃTŽKm0º”¢ r@ÈùOJÇÿ…Íà_$Ê5†+¿bÿ£J óŒ¨+È÷ êX£ž&ŠXÖHØa‘ÆA∡Š–(£HãQ…DP¹)µ«…ø­o£ r5·m<Ît¿²ÌrÛŽœtÏj¨ÿü VÖaŒ¨·²àã$àgŒž½¨¹DXÔ*(U½¥µ¢²Û[Åc¹„h'Ôâ±õ_x{EÐ ×/µHcÓ®Z @-æädmdñíT4‰~×u‹]'NÔZkë•fHŒ¤Žì´àgš»ã/ùÛØWMÿÒØk ®Æ_ò¶ÿ°®›ÿ¥°×A@Q@Q@o¿ãÖãþ¹å\Âïø÷Õ¿ë±þuß_Ç­Çýr?ʸ…ßñï«×cüèÑbû‚ŸL‹î +}QEQEQE2YV%Éü?˜ˆÅ6XVb¤ž•( Š( Š(Î( dô¦nYT…lÓg‰¦]¡°)а UüM$P$9*9=jZ( Š( Š*.QgVô  YÕ,p)‘̲çg#֕ÐJ˜n”©ƸA@ýš3'˜FZ¦¢Š(¢Š(¢Š(¢ŒÖ€ +)°¤ŽjšËs$ày{cèԒ¤K—8y8\(è}jW$uÈ¡Qp£€ šÔÎÿ;|ž•:"ƁTp)ÔPEPEPEPEPEPEPE™½-…‚©cÐUQvÏ(XÓ+ë@èÍG4m"VÚ}j+{g„å¥/õ Ïp #$ö¥‚V•rP­=£W °ŠuS–Úáåț éV•pO4ê(ªŠ§QEQEQEÄüTÿ‘&ì»Mv՟¬i0k6ip>Fë@Gð{Æ>Ñüö]CRŽ üÒJ?Zï¿ácxCþƒ0~uοÀÿHìì§$çŠoü(Ï ÿu¨¤ÿ…áú ÁùÑÿ Âôƒó®oþg†ÿºÔŒðß÷Z€:OøXÞÿ Ìð±¼!ÿA˜?:æÿáFxoû­Gü(Ï ÿu¨¤ÿ…áú ÁùÑÿ Âôƒó®oþg†ÿºÔŒðß÷Z€:OøXÞÿ Ìð±¼!ÿA˜?:æÿáFxoû­QIðCÃQ«3p ôÕˆ¾óƒó¤ÿ…áú Áùדx?áV‘«k:œ3©òalFsÖ»Eøá¼rç@/ü,oÐfΏøXÞÿ Ìsð£<7ýÖ£þg†ÿºÔÒÂÆð‡ý`üèÿ…áú Áù×7ÿ +3ÃÝj?áFxoû­@'ü,oÐfΏøXÞÿ Ìsð£<7ýÖ£þg†ÿºÔÒÂÆð‡ý`üèÿ…áú Áù×7ÿ +3ÃÝj?áFxoû­@'ü,oÐfΏøXÞÿ Ìsð£<7ýÖ£þg†ÿºÔÒÂÆð‡ý`üëžñώü/}á;Ø-õh¤•£!UOZgü(Ï ÿu¨ÿ…á±Ð‹àIÝá7#¡rEz½bøoÃVžÓŝ˜Äb¶¨¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¦Kþ¥ÿÝ4úd¿ê_ýÓ@Ãõº¿ý|7󢏆ÿëuúøoçEXø_ÿ"Ü¿õÝ¿™®Þ¸…ÿò-Ëÿ]Ûùší袊(Ÿð÷ü‡[l'P{ZÞ7ñ-—ÄŸ…úü>¹žî[3 ÜD°:³¦ì•žž?»ï^®öÐHŞُRPNŽ¢Ï—&zíP3@?ø»Ä~ñ¼9á DgքÐm‫Zm\1$€¾¿jعÔí|ñçRÕ|N`‰gz`,¡‚ #叺ÏQë^Ë­¼3I4vñ$²}÷T›ê{×â øž÷^¿‡¼W%‰(ªÖWQyÐ?Tð§§oSžhÈôûKxoâºh¶’Äg»‚xíŒ[\Æ$w+·±Ú{S—pæð,a¶/š6’;ð„~Öº8üA¤ø›ö†ðæ¡£‡’ÛìGö“ ŒNBJr»€$ œuv¯Hñ†µ wO¶F×n4k›i ©‡˜å}×@@#8ýxæ±¼=àZÛøŸÄúìz–¡inÖÖ±ÛÛc‰Ny㯠ݻûPÿŒ¿ämÿa]7ÿKa®‚¹ÿÈÛþºoþ–Ã]QEQEU¾ÿ[úä•p? ¿ãßVÿ®Çù×}}ÿ·õÈÿ*à~Ǿ­ÿ]ó E‹î +}2/¸)ôQEQEU{£&б÷êjI¥XS$óڈ\Éf4±GåÆ$ýiôQ@R3mRqœPÕYcšWÚNڒ&žYI< è*Ý5bÎqN¢Š(¢Š)²H#RÍÒ¡{ ²U,}EJÈ$Q¸PaœN J°¢¶ìdúšz¨Q€¥ Š( Š( Š) À'Ҁ‘˜(É +§ö¹$”"F@Ï$ՙaY”Ïá@ Šå&r«ž*)íäð\ªûUˆâH— +1O EŠ0™'Í>Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢šÒ"ýæ”°ÚXr(h'jœw,›V6PSV%ŒÈ›sŠxe'>Æ¡žäCÆ &’ 4Ë©$ŸZœ¨=@424‹–¨e³ó¥Þd`=[Æ( ª@½G½ +Š¿u@§Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@s~0½6»º•­Nù4Ý>k¹²Æ¹ Wø›âv‘®Æºdmå$‡n=(·ð $wøÃ\òk³Q…ÎøJ{ 4;h,.£™bì=+£ Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ™/ú—ÿtÓé’ÿ©÷Mp ÿÖêÿõðßΊ>ÿ­Õÿë῝cáü‹rÿ×vþf»zâ>ÿÈ·/ýwoæk· Š( Ãßòñgý…cÿÒ+Zè+Ÿð÷ü‡€ +(¨¦¸Hq»©è(f”B…'°¦[»È»Üc=ª@Š—š}QEQUÃ´»#MÀu44²ˆÔ“Éô¦A+L¤²m© +†ÆáNé@ XÑ *:Ó袀 +(¢€ +('5Sí›äÙîõ  d€2zTiµ%`zQEQEQEQEQE1åHÆXâ€E7vSróéUV{¦›i‹ ë@ ÇZ`™¶†ÒK–=»±ïM†Ù"ç«zÐnn$‡îD_éN·w’=λO¥MEV{A$›œäzU…P«Ò–Š0=(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢³uÍZ=M’òQ•A“@TWŽ?ǽ5de[Wp§U&›ÿ óNÿŸ)¿ïƒ@ËEx×ü/Í;þ|¦ÿ¾ ð¿4ïùò›þø4ì´WÂüÓ¿çÊoûàÑÿ óNÿŸ)¿ïƒ@ËEx×ü/Í;þ|¦ÿ¾ ð¿4ïùò›þø4ì´WÂüÓ¿çÊoûàÑÿ óNÿŸ)¿ïƒ@³ª[ý«Nš gz‘ŠøÏ[ѧºñåΗl§Ìi¶€;W¸Ÿ–âÊoûà× £xÛCÓüUw®Ïe$³Lۓ1ýÚö߆þÂžŽ#¸ÜH¹“qÍv•ã ñóOÇ6Sߝÿ óNÿŸ)¿ïƒ@ËEx×ü/Í;þ|¦ÿ¾ ð¿4ïùò›þø4ì´WÂüÓ¿çÊoûàÑÿ óNÿŸ)¿ïƒ@ËEx×ü/Í;þ|¦ÿ¾ ð¿4ïùò›þø4ì´WÂüÓ¿çÊoûàÑÿ óNÿŸ)¿ïƒ@ËExä´×•­]e”Šõ=UXÓc¼ˆa\dP…Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@2_õ/þé§Ó%ÿRÿîšàþÿ­Õÿë῝|7ÿ[«ÿ×Ã:(ÇÂÿùåÿ®íüÍvõÄ|/ÿ‘n_úîßÌ×o@Q@ÙÒ5û=_UºÓ/´ÕƒP¸[‚—6Ò;#cˆŒ«€GîéÞ¤ò|aÿ?ÚþÍÿÇk ¢€9ÿ'Æóý¡ÿàßüv'Æóý¡ÿàßüvº +(Ÿò|aÿ?ÚþÍÿÇhò|aÿ?ÚþÍÿÇk ¢€9ÿ'Æóý¡ÿàßüv'Æóý¡ÿàßüvº +(Ÿò|aÿ?ÚþÍÿÇhò|aÿ?ÚþÍÿÇk ¢€9ÿ'Æóý¡ÿàßüv'Æóý¡ÿàßüvº +(Ÿò|aÿ?ÚþÍÿÇhò|aÿ?ÚþÍÿÇk ¢€9ÿ'Æóý¡ÿàßüv'Æóý¡ÿàßüvº +(Ÿò|aÿ?ÚþÍÿÇhò|aÿ?ÚþÍÿÇk ¢€9ÿ'Æóý¡ÿàßüv'Æóý¡ÿàßüvº +(Ÿò|aÿ?ÚþÍÿÇj9ãñªÀíow I(T{Y”1ôϘqùWIErf£âHIÞhÐ]C=¬ÖR‰"'¦@”‚bjÿ“ãùþÐÿðoþ;Zž‘¢c™d{kØsä]Àñç¨ç†SÆTä¨V³Õæ†í4íb4‚ñø†dϓuþá=”<ŽpX ÐOŒ?çûCÿÀ9¿øíOŒ?çûCÿÀ9¿øítP?äøÃþ´?ü›ÿŽÑäøÃþ´?ü›ÿŽ×AEr÷šG‰5E··¾Ô4‘mݽËù’>TÉ(™(NõÔQEQEQEU¾ÿ[úä•p? ¿ãßVÿ®Çù×}}ÿ·õÈÿ*à~Ǿ­ÿ]ó E‹î +}2/¸)ôQEàdÐsJ"L÷íInò<{¤4 ¤Ë‘È%QM,*¬7PZtW œŸAHÐ#>æúÓb¶XÜÈycSÐE„àf€¢žo(p '¥D%šY°ƒjŽ¹ïVH¨ áis Ò¤ + –Š(¢Š(éUšñ›>Õ$ÈÒŅ8&€IÀ`OµW¹káaÍ:ÞÕ ’zæ¬Pq+ðüžôååT¥:Š(¢Š(¢Š(¢Š(¨šâ$m¥Æ})ûóåæ€HH$T×ío( €Á«Rij&ÖÎ=¨dvœý*;™&LW$Ó¡¶Žògñ©¨ Å?|>ÔÃf&öb}ªÍ€‚–Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(®Câ_ü‰wŸîå]}rÿäK¼ÿpÿ*â>hšUÿƒf–ïO‚iÇ,é“^—ÿ¿‡ÿèkÿ~ÅpäHŸþ»ë^¡@ð‹øþ€ö¿÷ìQÿ¿‡ÿèkÿ~ÅjQ@ð‹øþ€ö¿÷ìQÿ¿‡ÿèkÿ~ÅjT7–¶jêt…OBç  +#Âúé£Úÿß±Að¿‡Ç]×þýŠåþ&øÊãÂÞŽÿMu}熊Úð·?‰€pÎ3ÍG:4‰µN=kZ»xnÆØ5.—©É9:’GñP´Q,)µiÂD.T0Ü;S.%ÀÎN8®Oíó –1ëڀ:ٕÙ0‡֛!’r穨ì&3Z«sïR\]Glã45đdzƒÒ yeù¾E­>âY#"n'ô§B®.rMKEQP½ÔI Bß1  ©23ŒÔs+Ô5S,˹zTMr¯ˆâÜ=hÝÈË2e† Vò&i 23@+Žø–ëÿeàÏ;ò®¹²m݃ë\_ċm¾ ¼%‰Âçþÿȑ?ýv?Ö½R¾LÓg¼”±!lzל|ÿ‘"úì­t_DÇÁ·>Fwl9Åyü´$i¸ ¥1Š,àŽø­ÿø\°Â%ý½ýœÛs/5äšèŸð€ß,á>ߓÔóR~6FãŒP©Iñ®¼=i«5¶Ü>͙é\—Æ?ÜjºƒA–êX6àz×sq |=ÒbWA0ʃÏZì~+Eü4Ðßf×;rOZÍñ½6³ðªÊÞh +ûÆïW|ñþÝMÑMa»o™RøÆ(£ø1¦¼hˆ"¹;Û{xü'áé‘di[ր=ëÅ¿,ü3¡[ßy^l· + +F:æ¹ÏüeþÚÖ£Óu #lÓ«-Þ¼÷ÅâAªhFôŸ²ezô©uáhÞ=ÑN·Øh»ñÇ8ôM~çHM-¥’&Ú¦²|qâ­h´»½{C3Ëq‚ »\Ž›mßƶŽõƒxÈ5ÒþÐPÅö†‘ Ep>´Õj¿WÂZ%³Ñ^[GO—ùE7Â_×ÅZ™´]%¡FZLä +¡ã}jÇGøUg ±£ÜÏT'¨¬¿…ú,o®Ì¨×wJ€yP–¡ñæ+-~âÁ4Ó$P1Rã¾*K‹KâOjW6ÖC•ÆzלøEô•:Úê¡ Ö[nîµ£ðõb“A×TbË`Pƒ>)¹ŸY»Ón y¢Y™‰ÎÑé]„¼EáDñÕú[éÖæݛ3úàÕ_vðµ©<µ.¡°}+ÎWÏok¿f'Íóîõ RÕ¾;Io«J¶ºcIg ìià×e©|L³±ð<~%†=£¡¯ðïöxøU«‹’ŸnÞØÜy¢ÌH¿®üÜàÍòçҀ:ãûCÁ,Ð$z[(‘€$ö¯eÓoWQÓ`»NˆòDÖ¶©áM>eD¦Eù«ê_È«eÿ\…q?äN´ÿ®ãúW]ðçþDÛ/÷ò®Gãçü‰ÖŸõÜJë¾ÿțeþàþTÖQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQES%ÿRÿîš}2_õ/þé á¿úÝ_þ¾ùÑGÃõº¿ý|7ó¢€,|/ÿ‘n_úîßÌ×o\GÂÿùåÿ®íüÍvôQEQEQEQEQEQEQEQEQEQEQEQEQEQE•¨èæ{Ÿí ¾Ç©*…ó‚îITtIWËéЎpFNWNÖÕÃXÞÀlõ$]Ín͐ëýøۍëӞ£# +R³µ« ký=…ÂÑ~ò)PíxœrôÈ<@4WÏsüQñtºýΙ¦£\‹”¹Q–ÇsŒý*Ïü'?¿èÿ÷Í{Ýàð|Eÿ {ÿß4Âuñþïÿ|оQ^ÿ ×Ä_ú¿ýóGü'_èÿ÷Í{ê“kqÿ,ò®árŸ³êÜõçù×'¾"Ë¡°“ ¤}ÚÉеè)p¶öbfÜß/zúN0BŒÓ«Àǎ~"ÿ ÷ÿ¾hÿ„ëâ/ýßþù `ºÓf¾¿ÞÊV1ëZ–Öq[ TQŸZð¿øN¾"ÿÐ=ÿïš?á:ø‹ÿ@÷ÿ¾hÛïíe»A½Gm£ÛÁ‚Fãï^)ÿ ×Ä_ú¿ýóM—Ç¿"…åk +£$í z; Œ¶¨ô®[Qº’òsµX é\§Ã/ê^2»¸µÔÆ<°xés [‹•\Ž€Ð-Y˜äRtÍmUK[Øf‰[*¤ö©æýÑÃP™ª·~QتKž”¶ÑL„´Í’jÆÐNp(‘ïx¿yÁ4Ôµ¶2}MMEQEUi®Ö6–>‚¦ ^ À`‘Þ€Mw©cÒª¤W^a28+ØU¦@뵺P1^G4›Ñqö‚q1S**•@§PVèéäҘ#fÜÈ ÷©( €1KEQEQEQEQEQEQEQEQE5¤DûÌրE5]\eH#Ú¢’éàòhz)¡²›±Úª­ë<›L9êhåÉ”ù ….ę•Á_j²HN( §¡£¸„Ì›AÅ$Ë ’hÏ2G÷9$ Šd–é)ËSÑ.J¯%òG/–U‹}*ubÑîšvÕ'%F~”´Ouï›÷WeYu-Á§Ñ@bµepÌäãµM,BUÁ$T”PPÀ°–žÑ£ýåëN¢€UTa@JZ( Š( ¹‰ò%Þ¸•uõÈ|Kÿ‘.óýÃü¨—ø ÿ"DÿõØÿZô›ÛH¯ìf´™C$ªTæ¼Óà4ˆ¾ œ3€|ãÔרy°ÿÏUüèÇåø¥½Ìηr¬rvƒ]6›ð¿N²ð¼º,Œ^6i5ÝyÑÏUüèó¡ÿž«ùЊi¿ßUŽ[‹–kX¤Þ©ž+¼ñ·€m<_¤ÚiìÆ(í±·o+°óâÿžÃó¤ó¡ÿž«ùЫü8µÕ|#o ´Œ#„ 0¬Ëƒö7E…•¶Ú0e5é~t_óÕ:<è¿çªþtÆxŸáΟâOÁ§ÈvKn1ŽµÎø;àä:&°šýÃÌñ݆9Åz¯üõ_΃4G¬«ùÐÂûH¼nþ$7˜Í»oj»ãχÖÞ7¹³–y>ÍÓë²ó¢ÿž«ùÑçCÿ=Wó 7ñ'ˆ|Ikgo=êZŒ( +ü(Ãwë8¾–X€Ç”ÇŠô:/ù꿝t_óÕ:ò[àn•¨ë3_%̑ ˜³*Ö·‡~Yø{N»³ŠfeŸ9&½΋þz¯çGüõ_΀8ïxÛÁæðÀå¾ÓœçÞ³´O…~•â ½MœÉö’IVè3^…çCÿ=Wó£Î‹þz¯ç@3«ü Kaæ³»t´™÷¼`ñ]ž£ðãOºðZxr&)Á,=k´óâÿžÃó¤ó¡ÿž«ùЗIðbÁô¨,|æÛ z>“`º^› š¬jµçEÿ=Wó£Í‡þz¯ç@]ñóþDëOúî?¥ußäM²ÿp*ãþ=:7ƒíB¸'ÏÒ»‡?ò&Ù¸?•u”QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEÉÔ¿û¦ŸL—ýKÿºhƒøoþ·Wÿ¯†þtQðßýn¯ÿ_ üè   ÿä[—þ»·ó5Û×ð¿þE¹ë»3]½QEQEQEQEQEQEQEQEQEQEQEQEQEQEïüxÏþá©ê ßøñŸýÃ@ð¯âµ•SûÃÔ{׺°P~âþUá? ?ä¡ë_õÐÿ:÷sü_îеq‘þTߗþy§å_>ø_ÄzÕÇÆ+»µ ^Õe DOf¾„prÀ}M'Ëÿ<Óò£åÿžiùQŠ0;04|¿óÍ?*>_ù柕÷õ¥ žâ€ ÿ<Óò£åÿžiùW’øÓâVµ xÆ *ÒÁ¥…ØÁ}ëÕ-$iì`™ÆÐ1”7Ëÿ<Óò£åÿžiùQBҌQŸJ>_ù柕RÖÿaޝ‹þ©»{UÌ{Õ=cþ@WßõÉ¿•xÇÁÉ<¿êd.IfàW¨^%õììLm·< +ó/‚ã>+ÔÿÞjöۻȬã,Änô  &Òhæýü'«¡ª¶WbîøÁô¢[ÅI<µµZ¢˜¥ž,ô&ª­”‚a!™ˆô  në–j†“3Z•\a†E +Šƒ +ÔSK*Mž´ø"xÓۏ­KE3ÊMÛ¶óO¢Š(¢Š(¢Š(¢Š(¢“põ´RÏj€^B_h'?J±E2Iiº¢†á¥sòá}hÅË̊<”Üh·2L£€'¢ªÜZ¼Ç++'Ò¦†3aK>¦€®bFÃ8Ÿ¼Ü9µ‰Ÿ{ š˜( ´=(¸» &Å©¥vH‹*î>”‘NB€iôV 敾xŠ +’xä‘qí55¼RÆ?y&úY­–fªj(‘ı.Õ†Ën+ÍIE`bŒ +( Š( Š( Š( Š( Š( Š( Š( Š( Š( ±»¡Obµ¤ÍmÑ@cð“ÅúDrA§k ,Äí¬ÿ·ñ÷ýßó¯v¢€<'þ¿¿è>ÿð­ü}ÿA÷üëݨ  ÿ…oãïú¿çGü+Ð}ÿ:÷j(Âá[øûþƒïùÓ[á׏“þcÏù×¼V~¥}ö ®Î +Ä3Zð ï xâÒö+XµÇ•Üá°~ík¯Ã¯7üǟ§­z…-öö}n\”œŠ{Wl€…æ€ÿð­ü}ÿA÷üëݨ  ÿ…oãïú¿çGü+Ð}ÿ:÷j(Âá[øûþƒïùÑÿ +ßÇßôνڊðŸøVþ>ÿ ûþt·ñ÷ýßó¯v¢€<'þ¿¿è>ÿð­ü}ÿA÷üëݨ  ÿ…oãïú¿çGü+Ð}ÿ:÷j(À/¾ø¿WX¡Ôµ†š`v“^Ëám!ô= mÍÆkjŠ(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š)’ÿ©÷M>™/ú—ÿtÐðßýn¯ÿ_ üè£á¿úÝ_þ¾ùÑ@>ÿÈ·/ýwoæk·®#áü‹rÿ×vþf»z(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š* ßøñŸýÃSÔ¿ñã?û†€<+ágü”=kþºç^ð‹ýÚð…ŸòPõ¯úè{Áþ/÷hæO ÜEiñ£Qžc„IÕÿ|AñV¿¯Þ&Š6ÚZ7Qß…§[¶¡ñ[V¶…°ìíŠ~‰­ÛøZ÷\Óu²Wf +[½wZGŋ¶ð õÍÖ?´-r€zšâ­¾'øÚ=.M@G›f¼k&ÇF¼¼ð^±ªF¬-ą€þð«ø§M»øpºjK”`îh¸Ö¾(êVþ …Óölm®j_‰þ5ÒÞÆ;ØÂ$ì»Iî ¬_XÍÿޗ}ƒäDT±«>>ñ>âðòXÌöúñ@ǎ­^ç,±Ä¥¤`½dhÑM2È;Vǖ›·mõ¨à¸Žáw&*\Œã4´SYÕX€)hä8Gé@¢¡žqilúQþp'a_­MEUšYCmž=Ûþ´ú3Š¦aºi 2 ¹àU­›£ÚÔ œýi$D…› ¨ÂäÞ7gëVYC ‘@Cv“>Õñ§O1ˆp2jEE_º S°Q@Àò:åÆ*9þÕæb,l«TPqáúÔ`¯&ÿ1ǵ[¢€ÛÔSVÔä(ÍIE!Œ@P:)h Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š) À&€1<]ª¶á«Û¸ÿÖ¤d§Ö¾~±øËw©½½–®6ÃæaÈî+Ö>-^¼–8ùyWGS^GðëàýÞ¹4wú²46Á³°Œ@Dx~k;½.,-ˆVÍRÒôËm"Æ;;UÛ jíQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEÉÔ¿û¦ŸL—ýKÿºhƒøoþ·Wÿ¯†þtQðßýn¯ÿ_ üè   ÿä[—þ»·ó5Û×ð¿þE¹ë»3]½QEQEQEQEQEQEQEQEQEQEQEQEQEQEïüxÏþá©ê½÷üxÏþá  øYÿ%Zÿ®‡ù×»·Sô¯ž¾ë:~‘ñY7Ó¬`¹ÆN;ײ7Ž|;Ÿøÿþúû_x~ËW}VÞÉVõÎZOZÏ×>øs_¼û]Õ ó‰ùˆïW?á9ðçüÿÇÿ} +?á9ðçüÿÇÿ} +ËñF›gáŸÏ§ ¡Q†„µó¦«©ø~÷L6֚SÛêO Úx5ôìž6ðÔ±˜ä½‰õ…bùÿ~Ñö"ËÍÎw`g?yõظÑ~Ú®£¤µÍ³(-ÇA^w¬Ë¤ëz¶›†ì7Þ­"íès_MOâ¿ ]Z}’{ˆßòɬÛKχ¶ùö±YÅ/÷” ÿ:ҋÁš.«g¦Þj–K%ä0¨zƒŠµ7‚¼=qz·’Ø«N£hojgü'>ûBøN|9ÿ?ñÿßB€#Ohz)ºÔôë[ÃÉ[Ú¾{Ö5ϝCQ]KC{{³¸/ËÔú×Ñðœøsû|xÿxV=å÷ÃÝB>î+9eþóŸç@wÀm:ê+IîÞ&HŽÌŽÕëÚ×ü€ï¿ë“V§‹|'§À ´¹‚‡ER¨õ_xzMñþ2Ld¸s@ið~I#ñF§å®ã¹«Ô¯Eü®Þj¶Üñ^cðJhæñ>§$l +’Äs^áqumýë +ÌјÞ.Cc­hÅk*>ç—u6ÊâÞyÈ@=êí2H–UÚã"™¬Pœ¢â¦¢€¨'‘šZ( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ¨ëœZ>•=üÿêá]ÍW«’ø›ÿ$ûUÿ®TʟŽÚê­øIÿ ãÃÿÝÈÖ?ÁŸ h:§†¼Ûí6åÉùœf½#þ/ +ÐÛþù ?þLJÿºÿ‘£þLJÿºÿ‘®Ãþ/ +ÐÛþù£þ/ +ÐÛþù ?þLJÿºÿ‘£þLJÿºÿ‘®Ãþ/ +ÐÛþù£þ/ +ÐÛþù ?þLJÿºÿ‘£þLJÿºÿ‘®Ãþ/ +ÐÛþù£þ/ +ÐÛþù ?þLJÿºÿ‘£þLJÿºÿ‘®Ãþ/ +ÐÛþù£þ? +ÐÛþù ?þLJÿºÿ‘£þLJÿºÿ‘®Ãþ? +ÐÛþù£þ? +ÐÛþù ?þLJÿºÿ‘£þLJÿºÿ‘®Ãþ? +ÐÛþù£þ? +ÐÛþù ?þLJÿºÿ‘¦?Ç}Œoûä×gÿ…?è mÿ|Ñÿ…?è mÿ|О_ü`ð¶¨b7p<³•ÊÕè~9øz$±P0\Wkÿ…?è mÿ|ÒÿÂáOú[ÿß4ÇÂøðÿ÷_ò4Âøðÿ÷_ò5ØÂáOú[ß4ÂáOú[ß4ÇÿÂøðÿ÷_ò4Âøðÿ÷_ò5ØÂáOú[ß4¿ðxSþ€–ÿ÷Íqßð¾ÿÈ­ùקÜJ¶öï3œ*My‡ÀŸù¿:ï¼Pþ_†®Û8ùHÍføOƖ^+¹¾†Û†´m­žõ¿ì.¼Pt8Á3ƒ^Oðºñ´ß´Ïò\nÀõª^¸š?ŽN$åf•öí7~7´´ñ”>`|ùz.½‚Öã%æ .=꿉ü}iá«{™‘›ÏPT +ò‹ú›ÞøƒHÔ!?¹ùÑüG–!¥è3Í´FQ '¥vþñññ¢¶¢Êh•†C²àWi#Ç2:¢ú±¬ ë: õ…¬:}ͬ“ˆ”Œ Àâ¹ÏŒÄú_†ȎBûþòР«£ŒÆá—ÔRאø+â|6º-´…œÊò0@íÞ»M_ǖZEü6mK,ªì(ª¢¼ïTø½a§Êb‡O–æEuŒ}Ñ[ô›¿ n}Åé䞤úPYEyöƒñfÃZÔ~Ç-„¶›ŽäèÕßË"CNìj»‰ö C²qÔ ×Ÿx3Ç—ˆ"éú…íþœ–RË·H:Vv‡ã?iz}ýõ•«D‘ŸÞg¹ I¢¼ÖÏã%…Ωmg.™4+q÷%aÁ­O|LÓü7wª[=äҌ…‹“@µ$¿ñí?û‡ùW'ៈ6'ŸìðÀÑL>ò7Q]dÃӏöò ø}ÿ%bóýó_AWÏ¿¿ä¬^¾kè*(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š)’ÿ©÷M>™/ú—ÿtÐðßýn¯ÿ_ üè£á¿úÝ_þ¾ùÑ@>ÿÈ·/ýwoæk·®#áü‹rÿ×vþf»z(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Šl‹¾6Oï+ȵïƒÖ ­Añ$ä™Ò½~ ž=ÊÊ~덦€8†ÒiòéR HOnv7ÍwÊr¯.·á}’5Ù§Oó3vÍzd2+ ©ÊžA  ¨¢Š*£éð´ÂP 5[¢€1PËk§,9õ©¨ G–›EVv¸Žl¹}*åÐçËÜF=ª%¼…œ&ÿ˜ö©ÈÈÁ¨…¼!÷ÆïZ–ŠŽhŒ©´1_qQÛÀð’Ëz±EW¸šHˆ*¹éðÌ&\ŒP´Sw®pXf@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@(¢Š( ƒEЊ§ b‡da‘N¢€‘$tb›-´S}õÍKE68Ö4Ø£¢k8÷”ùªz(»fÜqP‹8•Ã¨Á«P]w©S޸߉6þ_ÃÝP)ãfk´®Kâoü“íWþ¹P%ð+þEoλHcð]ãzãþÿÈ­ù×wâ­ø‹Ã—XÆeþ!ڀ>wÖíçЭtÝj/Æð+XZÍŽ´b(ö­Â†&½&ãá¤7~ƒFšRÆ,|æ§Ô|.ãÒÒ)Ê}‰B‚;â€8íY̟ì$'$ÄOéXæ™.§ýµw Ÿ½†bF=«Óßáð“Å–ºÛNKCÌzÒiWO—Tig2-ëƒÛ4ã3yÞ$ð*ޏ›g0R~†ºOŸíD‚ëæ]ª¤f»ë†ÐØxnóJŽ^.$ß»Ò¨êŸ _PÒâµûcî·¥tþðf…¡Ú[^iöÞ\ï’Û³“ŠÌø¸âS÷ûÒxO¾‡¨Ç-Ö§,öè»Dlx­ïxy|O¤}„¹A»9庶“ö¿†–7Ð(YmÜHÄ›àÇox²MUÎûx-ü¼P+¸Õlíü)ðú{Ȑµ—ðFg‚ïfxöÉ+3Gjç|' âípCˆ˜|ޕçúē&Ÿ6lÂ#tztë]6—ởøãP··¾’×vC•=EzuÂí:×Ã/¥Jþd¹È˜õ€8Fð„÷Ï£ÝϨ¤"6V +§ïW®ø§zx#PØNájpGÒ¸Ýádúv ³^j²Ïm¹½"xc¹´kYcuÚGµyOÁ8,φî¦*†ô»n-Œ×?á…VñG‹Ã*·îÛ¨Íuvÿ +§Ó|Hu ;T’fl´*x5£¥ü~cÚ²4¿„÷z¥¼²êòµ­«nŽ"x Sáå¤ð³uµ&¼g÷M'ÿ^«ümK—ñ†œ–<\q³mwÞ+ø\šÆ©£¦^5”ëÆ>3ROðäÝë^¡urÒÉf>bßÅ@÷nlÛº¼UuSç“ÔœWà«×_ë^©sðÛf»u}epÑGuþ±Jþ#h÷v"àâvݟJä|@‘ÿdx\„PÞPä +“B$ø‰kö ùGnþ•ÜêÖúÓJƒÎ#ì*×ÍøÓDЎ½g Ô¤²Ô£ +W€h$iñ'Ròð?zsŽkÚ.?ÔOþáþUá? +íÚݏ1§Úÿ4§½{´ÿê'ÿpÿ*ðO‡ßòV/?ß5ô|ûðûþJÅçû澂 Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ™/ú—ÿtÓé’ÿ©÷Mp ÿÖêÿõðßΊ>ÿ­Õÿë῝cáü‹rÿ×vþf»zâ>ÿÈ·/ýwoæk· Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ‘†åÅ-Ìø§HþÔÒØ"…–Ÿw~)ž×VÓvò¯l|²©ÅtSF?Ý<\¬á&¥âÆC†Aë@†§pÍ-T³ºKˆc™RA»éV袊(¢Š(¢Š(¢Š(¢Š( ´BôRÑ@¦²IŽK0>Õ2¦È©Î§Ñ@ÔÞ >`»*̒ãÜA?J}0ECÊLp½} M;ÔKk&ð0i'‰¤_‘°hj* t™%pÔÙîÌ/´DÌ=EY¢£Š_17cZQ4dà8Í>Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ¹/‰¿òOµ_úå]msÞ7ÓfÕü!¨XÀ3,±áh‡ø§þL㌞kÕ6·¥|ã h¿¼3iö]-¶EèEký¯âïü÷•{¾Öô£kzW„}¯âïü÷•kø»ÿ=Çå@ïµ½(Úޕákø»ÿ=ÇåGÚþ.ÿÏqùP»íoJ6½xGÚþ.ÿÏqùQö¿‹¿óÜ~Tîû\ѵ½+Â>×ñwþ{Ê˜o¾.”%Z{f•·,…}…K +²¦Ö9Çz’Š¨÷m¥]>_Z²®”ê)¡ÔôaùÓ¨¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢ŠÍÖõH4*{©Ü"ª늼ïŽ ®OÄþ,]/ýÅãQ“€Š3·Þ¼>Çã>«k¬ÜÛ¹ó –BŠÄýќf½ŸÁÞ¶ZIEÝÔÿ8œíö ðυžµ5b'¿“揻í]ª ?*1ÉëO Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ™/ú—ÿtÓé’ÿ©÷Mp ÿÖêÿõðßΊ>ÿ­Õÿë῝cáü‹rÿ×vþf»zâ>ÿÈ·/ýwoæk· Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( äLò:×â­Va«iƒmä_3㸮ޢ’<òá@׆|Oo­[„'ʺåxÛ©5Ó£†õÂø›ÃoÇöސ w‘üÒ"ðV§†¼O¹Cû›Øøx[¯Ö€:š)‰&îZ}QEQEQEQEQEQEQEQEQEQEQEQE!Un  +»z +Z( °A0;dv©æó6~ë½êJ(´ qœLáRMp°‘¸jZk¢¸Ã ÐG"ȹSš~j8¡H +:ÔÃ;6è¤Û@è¦FcÎ[½VÇÍ(a`ë@(¦—wBȏ÷XuQ@Q@Q@Q@! “KY'í¼7}4g± hý®ÜËxÿï¡GÚíÿç¼÷Яš|/£øÃÆ÷7og¬}"cÕ½ë¥ÿ…Sãßú×þú qû]¿ü÷þú}®ßþ{Çÿ} +ðïøU>=ÿ¡ïª?áTø÷þ†5ÿ¾¨Ü~×oÿ=ãÿ¾…k·ÿžñÿßB¼;þOèc_ûêøU>=ÿ¡ïª÷µÛÿÏxÿï¡A¼¶gþúáßðª|{ÿCÿßT…<#Ÿ¯ýõ@Ö÷Ö¬@1Æ¼«âÝåæ­ +xMpL§%Áâ±ÿáSxïþ†%ÿ¾¨ÿ…Iã‚ruèËxžh'ÂÿĬ$×/‘Tó„j÷o hv~ÓÊÊs4KбÍxÆ¡ð×ÇZvŸ5Ûx„:Ä¥Š†®“àŽ¯©i×I}1‘âr¹'4ë”QEQEQEQEQEQEQEQEQEQEQEQÖ5Xt]9¯fŠiTIK* »É"ƀdË0šÍÿ„šëþ…}sþøƒÿŽÑã/ùÛØWMÿÒØk  þk¯úõÏûâþ;Gü$×_ô+ëŸ÷Äüvº +(Ÿÿ„šëþ…}sþøƒÿŽÑÿ 5×ý +úçýñÿ®‚Šçÿá&ºÿ¡_\ÿ¾ ÿã´ÂMuÿB¾¹ÿ|AÿÇk ¢€9ÿøI®¿èW×?ïˆ?øíð“]Я®ßñÚè( þk¯úõÏûâþ;Gü$×_ô+ëŸ÷Äüvº +(Ÿÿ„šëþ…}sþøƒÿŽÑÿ 5×ý +úçýñÿ®‚Šçÿá&ºÿ¡_\ÿ¾ ÿã´ÂMuÿB¾¹ÿ|AÿÇk ¢€9ÿøI®¿èW×?ïˆ?øíð“]Я®ßñÚè( þk¯úõÏûâþ;Gü$×_ô+ëŸ÷Äüvº +(Ÿÿ„šëþ…}sþøƒÿŽÑÿ 5×ý +úçýñÿ®‚Šçÿá&ºÿ¡_\ÿ¾ ÿã´ÂMuÿB¾¹ÿ|AÿÇk ¢€9ÿøI®¿èW×?ïˆ?øíð“]Я®ßñÚè( þk¯úõÏûâþ;Gü$×_ô+ëŸ÷Äüvº +(Ÿÿ„šëþ…}sþøƒÿŽÕíZYK½¶·6²ÚOäM ʨum‰ û¤Œm‘O^õ¥\ÿ‡¿ä9âÏû +Çÿ¤V´ÐQEQES%ÿRÿîš}2_õ/þé á¿úÝ_þ¾ùÑGÃõº¿ý|7ó¢€,|/ÿ‘n_úîßÌ×o\GÂÿùåÿ®íüÍvôQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE‘ç+Œ×ü&ípÚ®æÞù9!Ú»ŠcF ÈàÐᏍA† ¾F¡Œû×`’vo靖ú«}¦ö{ÕäH¼¬k/_è7)c¯DÂ;c˜¿ZôJ*¥½ÒK¼R,ˆÃ ©ÍZ dPÑEQEQEQEQEQEQEQEQEQEQEQEQEQEQERQKE5‘]v°â¡ŽÔE.åúõ¥TT]ª0(ÔUF¶K½d$zU’HŒœr:Š©à-±Ô†«E€êhkÅßò*j?õÈÖÐ`zkÅßò*j?õÈЗü ÿ]¨ÿ¼{.O<׌ü +ÿ]¨ÿ¼zýël°™·žMdÂmáï큤‹õ7¤íZÞ9ÿZð†FŸªxã]¾¼xÚê’Y¹Î{W¤xV×W´Õµ u[´{vcå|ßtP_“ëFO­7̇nï>=¾»†)<Èrš<žƒp怓ëFO­7|DàJ„ún¦™íÔá®aи  2}hÉõ¦´‘"îyQWûÅ°)H¥ŠTz£f€2üTOü#7¼ÿË&¯4ø ÿºýv5é^*ÿ‘f÷þ¹5y¯ÀoøõÔë± h¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(Ÿñ—ü€í¿ì+¦ÿél5ÐW?ã/ùÛØWMÿÒØkOWÕìt-.}OS¸öpe”©m Ԋ»Ebé>,ÐõÝ}gMÔ}>ܸ–}Œ¡6Í@<Jg†üe x¸\ P[Ám·Î"'M»³¼~éé@´QEVU·‰t{ÍjÿG‚õZÿOP÷Qaå±èGC\Ãüeð^c®)Ãì2¬³þø\~=(¼¢™ Ñ\CÐȒE"‡GFYHÈ Ž Ó袊(¢Š­¨_ÚéZuÆ¡{(ŠÖÚ3,²NÕ$às@h¬«h÷:eŽ£¡ÙoÝRÕß(ff8P à’OµjÐEâ?xwÂOnšî¤¶mpÄ'}ÁqŸº¨  ú+˜Ð~!øOÄú‡Ø4}j›­¥„E€ëÀgð­=+ÄZVµ{¨Ùé×b{:o"í62ùo’1Èû§¦zP¥Q@Q@UcYÓt 6MCU¼ŠÒÒxNÚóĺÝË]̏dÌP)ûßZ×ð ½÷‰›ÅßM»y’ßwžÕánŸ{k¬ø®-Ú5“~ÂGÞª^mCãÅÏhá˟-q÷¹ wJºÖu§„šö_*ÚΓ]¢.ôߋ:Nš·r˜cwpÜVÑuÍ#X‹Åð[9i›/9­o¾§kã'Å_Ùò\FÑþñ}ӊ›K½¼_kº‘•KmRxÏéºM÷‰ô½gU“R¸I­';[Œ[žµÔ5mGWÖf²’Ò U\W3áïÞiúN»¦ÙéÒ]4ó‘½Lš¿s¯jz֙½ä“®#’X?Zöizv™ (Óožò9>bÎÙ*}+‰ÐƒøcÁSC©iMsö¥-·nHÈ­ƒÖWÐYÞË,Û[É!)q@ŸŒgKo ßK&í‹ÎÔ,yã ד|ñ—¦[ߋ˟(´¤å±þB½{Åò-^ÿ×&þU柿ã×Qÿ®Æ€=#þŸ +½â 9róªõ'O‹Æ¾™ŠÅâ}F$-üGÿf­Úd°Å2…–4‘AÈ  Ð|~#ЦRÑkZt€·H­YMJÆD—¶Ì§¡YTƒúÓ%Ñôɘ4ºu¤„ Ð)þ•Yü-áé»è:[1êZÎ2Oé@ÔW?ÿ'„GÝ𾌇³%ŒJGЅȣþ ¹£ÛÆ}bÊø©ÐQ\ÿü!Zû–÷1H¯gAù+Š?á ҇ݸ֐vTÖï àPAEsÿð‰[ŽSV×»í9[$~”Â/"ÿ«ñ¸‡¹ûB?þ„†€: ++Ÿÿ„sP^#ñ~¸ƒÓe£~­4akC…ñv @è^Ö؟Ǐä( ¢¹ÿ쯯+âd'Ñôä#ñÃúÑö/Üñ–Çþšé.Gá¶u ‚ŠçþÏããûOC—ý¯ìé“ôóÛùя/´7Ç|L¹ü2qúÐAEsþŒŸìÝOö´&Lþ>IÇåGÛ¼X¿@Ò[ÓÊÕÜþ{­Ö€: ++ŸþÕñ"ðþ‰¬ZŠ‘ú¨?¥ۚÚýï ^’:ì»· ý2ãõÅtW?ÿ ¢9눽ϙfߢÎOéGü%¯úÏ ë‰éûˆß?÷˟րÈÛþºoþ–ÃXÿä“ëÿõÊ?ý”x“Ä1Þéöv§LÕmä}WNÃOdꃐž_•=kkÆ~oøGPÐÒä[5Ú*‰Šo † Ó#==hçø5†ðw„ü[áÈݖMRÎÊâÅPcqž4ø6?à5·àïøW:Wċ„…f}&Kx‘3Ã8.ƒ>ۈ&»}Wá:¯ˆ<+ªI¨ -¼M‘Ÿ´ˆŽG;¸Éϯ¡aðÒÙ&ñ’jW_j³ñ$ÂF‰cBb0rrA`AÇQҀ9 ýSâ&à‹_ÏâK{èÙ"¸¸ÒÍ¢$B)ÀWlüËùž½ôu/kÞ/øƒc០êÿØփMMBâçìë,­½U‚á¸èééÔòp8ü(ñ þmáígÆOwá›fB–éjgE?*3ç üz8³âO‡·—>$²ñ…µ…ѵK{aháàÅ$# Ú{Ç éŒÐ᫏ˆÿtísPÎ–Åmæ¼U‚¬D˜ÎÚAÆzÖ|VÞ-ðgƒ%Ñ5O +i¾$ðšv¹²”hòX¾Wž99ÛÇ­wúÂáa«xŠïU՟TMvÔArŒX†9ÀŽ=+/…¾0²Ñäð݇ŽÌ~Øö`̈ÝT6s¡“ÅQ×|o¥øOÁ¶>¸:.Ÿ«ïÿJš3;Y„P§q$G~œ{Zð‡Ä+è5­wO½ÕÛÄu–œú…½ÿÙ>Îí°eã#wàû~[ºÂ¸áëMS–ÃPðù/exñ‰79mëÜçóâ´ü?á]j)õ+Ÿø†M]¯¡ò œjb¶ÁÂg©øê}hŽðôŸüWáË_éþ%±ŠK™ÙâÒdµ(9Rð[<ÀuÍkEâmpüvOMvN:`™íP)A&ܒ¨cÏÓéT!øMâ+m=¼9oãYcð¿š$X¸óÐnÝ°8< Œç?…lø‡áæ¡qâ½;Ä~Ö×M¿¶µoöˆ<ðñ Œòyn{õÀæ€0­|_¯זùa]äf„Ÿ˻F:zóÛ}/[ñ—ÅM \ÁóørËL%î.'P?R03éßáû/\ø›â\Ú&¼ºLvڄ’¹[e•åpd*2Ü*ð}ù¯|®/Að$š5狧mAe åP"Ǒ»Ÿ›ïût bÃÇÖ³ð^Ó[m{LÒ5œÁq¨]®B³rˆ‚äÆ1קjþñŽ±?ĄЛÄRëÚUŋOÅŇ٘8þï+ïÏJ²~ O€ôÝ qEþ›~o­îM¿îËѐ“ùçð­/ÀâxæÓÅZωúå-^Úh#¶ò)2+‚sž¤ç¥yÄ_ƒá­sNѵXõ\ß꺀r· ¸ŠÕˆ!|¤ÏžÙÀéŠÄñ'ÃÝĞ°ðåϊ‰š9 ——onI¹ä•#Ž~è  O ã‹Oã.Çìz›jÖpÏålûkÀ‘ì3øaGÓØkÏü!à¿xrúÅ/<`—ºE¬f1`– #i †Œ½€ +çü=ÿ!ÏØV?ý"µ®‚¹ÿÈsşöÿH­h ¢Š(¢Š(¦Kþ¥ÿÝ4úd¿ê_ýÓ@Ãõº¿ý|7󢏆ÿëuúøoçEXø_ÿ"Ü¿õÝ¿™®Þ¸…ÿò-Ëÿ]Ûùší袊(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¦²ëN¢€3u&×R„Ãy’?¥q÷z« Hnt‰ZX‘kšô*iAÔph‘Ò|coxË †Òðñå‘]:Mò‚0>†³u/Ù_‡f…Vfÿ–£¨®u´oÃì[L•¯u”ݬŠßZuqö>/·iVÖù+³ÃqÀ®’+¤p<¹QóØÐÊ*1(þ!ƒR ãÿ¼]¬h…­¶—1F”­{xWƯù4¿ªÐ8$ø£qmèÒqy§ã◬Ÿ­{fŒÇû +Ä÷ò—ùUß3yÂýhÁ±ñKÖO֌|Rõ“õ¯yû²+cFò:>´àØø¥ë'ëF>)zÉú×¼yÉÿ=“ó¥2`eU}OJðl|Rõ“õ£½dýkÞÊßrT÷Ni|Õe@}  ÇÅ/Y?Z1ñKÖOÖ½çy#!¢ä ³¦€<½dýhÇÅ/Y?Z÷…™_ý\¨çý’ /™¼á~´àØø¥ë'ëF>)zÉú×¼ù‡®á^Ô 3÷][é@ Š^²~´c◬Ÿ­{ÁᦌBE/™Üºãր<½dýhÛñKÖOÖ½ãÎSÒT?(sž´ó†¥â¿øwS¶‹T™ÑdaÁ¯¡´k‡ºÑ­'åäŒ15ãŸÉþØÓ`Ë^»áÏù,?눠 J(¢€ +(¢€ +(¢€ +(Èõ¦™P¨¨^pƒ-…¦©]êöv™%º‹¨V  "ÁzšŒÌ;`{šáî¾$i´VÉ4“ô/¬¹n|câLEöqkdÝ%^(¸Ôõý?HM÷÷+{×âß=æƒyd×vì¤4¸é[gÃÈ q&£y%öy)!È­_i6vÔÊÕ!Y8Q@uð³}½˜a‰$Æ½œókç_…þ<Ñ|%=újÆXÙØí!}ëÑ¿ávø7þ{Íÿ|P ¤FIŽ0¥ºàu¦}’Û‘å.¯kÿ…Ûàßùï7ýñGü.ßÿÏy¿ïŠô†&ˆDÑ©Œt¤û</(Ä¥=¯?ÿ…Ûàßùï7ýñGü.ßÿÏy¿ïŠî5`úLööñª–BÃü,ð­ß‡ãÕ¥y‹&ᜊ_ø]Þÿžóߍþ=g›þø @’¥@’F¬£ Å<U +ŠG`1^wÿ ·Á¿óÞoûâø]¾ ÿžóßÖø«þE›ßúäÕæ¿¿ã×Qÿ®Æ®ë¿ü%}¢][C,Í$‘•Q·½QøKØ_Kµ‚¼¤ŒŠöš(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€9ÿÈÛþºoþ–ÃZz¾¯c¡isêzÀ·³€,¥Km€8ž¤VgŒ¿ämÿa]7ÿKa¬Œ?òIõÿúåþŒJhøËðýˆÄQsÇ6óý’»[{ˆní¢¹¶•%‚UˆÙVSЃÜWϺ·u¼¤øvÿÁö£R°ŽÚÓQ½¹C ~ì(“!~Sƒ¸dädVj <)àï[êÑÚ\]o[­OÉó„slR9åð8è½³ÀµQ^Aàÿˆñkzæ›y«·ˆtû=9¯íï¾Éöwmƒ/¿Ûò̇[ñýßÃkïEɯš¶hR8÷È~»Œç§9Í{•ã^4ñ +]ü,EԜ.³ñå§ïÉòóž8ûǦ:Öüž*Ôí¾4êL·nÚ=¶ŠnþÌ~ø*IÎ3ހ="ŠùÑ>'øŠïEŸÄ‘ø²8¯DÅ ÐNÝDL˜ëŒž½ºæºxû\¶Õ´Iöû@ðýöœ—_kµ²[†30ÎÆÝÓhê>ÜðìóM¼/4Ò$q"–wvT¤“ÐTvw–ú…œ7–“$Öó xäC•u=>•ãZ¶¥©x‹àž½/ü%öz§Ù˜–¸µ¶ØòBʤ ¬r@íß­vß ì¯¬þiMy©µêOo°+D©öxÊ.#}à=O<ÐÝwâ7„ü5©¶¬jékvªÆa‘¸=UH«ñ׆|W<°hš´7sD»Þ0¬Œ× #é^_ânÛö»“@Ò-õ[Ïì„ÞâQ„Êå²xÈãó¥Ð&ºm.¼W¤Å êrÙ4vPZíh®I,òrq;N@=¢û4ä\ùùávù»ìzg®+Ét][Ɵîõ­ODñhºe•Ë[ÙAö4“Îe̅¹åzg©â³®>-ëw? tû«u‚]êÙm0LÆ +€L€:õ&€=sSñ•£juŽ¡v!¹Ô¤1Z!Fo1†2ï¸ëZ•á>+Ó4¶|Q¦FZ돆|]a(6¢‹eþy¯.ø‹y©Ë⻵Îõu½hè}þ@6?õÉk€øÉ®_hš +Ébå$fÆA®ÿFÿýrZòÿ_ò.F{‡  +?x÷ú<!–o2ÉÈê{W«ÜøÂMcá¡Ö­ŽÙDyb=kÂ'ñeþ·¢ØøQ—Ê…ŠŒ·zö›ï ü%6;³º,“øP›øRçÇ~+»W ä,¸n{f·>$xË\¶Ô-<-k)K§YÁîk•øqãkA¸–O<O†`: ×gñsÁ¥Í巋4Å/:ª³F£zÐßÃ= Åú³"ëÓ´¶¯å$çšâüQ¯xŸQø…q¤iH8Qší¾üPþ߈èúºyWð®Ýǽyw‰õý'â¤÷Zd-5À9U^ôÛx7⻢ø¸xoÄÇ,p©>&üEÔå×SÃZĒ zÈð÷„|EâÍâ]fµ‘*b²¼8ïâÛ5ÈÜèØûP†­ãO†z¥´Ú¬ï-¼ì n9â½âoŒn‚,u}&R‚` Ó?h(£ Ú»(Ü­òšóífâVøI§#’QzP¢x ǓøƒÀWË+ÿ¦Z¡ç<Ö?ÃOêréþ!¾½”È-ɯ4Ñ®¯ü¤ –A¨¹í]·Á9uÛ?éᶋ…?7ր2tÙ|oñöïTÒ®Ý#³°õjz¦‰ð¶)årº‚¦ûדéWúÿÁßËлéÎøcŽf½7â&·iâ/†ohÃk®vúP à–ñ߈f†úØÚ–Éí_DX¬‹c +Íþ´»ë_9|'ñ†·c-¾›“Éjç@8ô”D´HǂzЊüoÿÖ™þò×®øq‡ü#šýqä??ä1¦ÿ¼µ»«øêûÃ^±ŽÓIšáš!‰Tp(Óî/-íuÄÉú¹ÅÝÃr»áq"ÿyzWÇ(ø…âMzvŽúâH6Dc ŠõïëÚáðÜqAò€Ð¶ïÿdÒnÈkÎ~Ïã+â±<äö¥ÿ„{ǃƒ­G@ì·ÑB3,ÉÿhÕ¼E¥D¤FGð†æ¹h¼¬\œj—þj¡MZá¦€JÉ3Ißæ _|BÓ¬ù[yný3ª-㫍Mvi–G!èdZê¬|;§éê u |f´–Ò%äCýç‹cãU¶_KvýÞ¸«vß ì‚{‹Û™$<•-ÅwÂ08(¨"Ó@Ó­¢XÒÆWøŠóZqÂB•GaÒ¥¢€(ª;›xî­Þ FQÆ©h :_†>šBïd…‰Ï"™ÿ +³ÂÿóàŸ÷ȮҊâÿáVx_þ|þù¬ð¿üø'ýò+´¢€8¿øUžÿŸÿ¾Eð« ÿ|Ší( /þg…ÿçÁ?ï‘Gü*Ï ÿςß"»J(‹ÿ…YáùðOûäQÿ +³ÂÿóàŸ÷ȮҊâÿáVx_þ|þù¿¢ø{OÐ!1XÄ#CØV­QEQEQEQEQEQEQEQEQEQEQEÏøËþ@vßöÓô¶wŒü<Þ+ðŽ¡¡¥È¶k´UÞ ¦FzzÓ|eÿ ;oû +é¿ú[ tÉêÞ³×>ÁáKù7ù±E® +IYúŽž„ŠÁŸá–§sáÝè@c<œó]ðT*€v¥ ,³øcâmÒMEñ¤¶^į‹oþ“-¸¢ÈLõ!›Q†û@ñLÖûmż¶Wên-åcyðÝ2qÏâsÛQ@w£|*‚ÃÂÞ#Ónµ-î¾ ¹¸†q¶ݑŽ0 ŒŒûVç€ü?¬xcÑéZ¾«¡ö|Glb‡Ëľ¤ðy5ÔQ@qâO‡Zæ£ã©‹Eyøiâ O_Ð5Ïx©oo4« -G°p¸#æ8åŽzJä~!Zi^>ø±£é:,ÒËr»­u­‘TŠ9a‰$ÞÜ-{íE­¼2I$PEÈrìˆcêOz‘cEDPª£@ÀҖŠ(¢Š(¢Š(¢Š(¢Š(®Ãßòñgý…cÿÒ+Zè+Ÿð÷ü‡"ZøT›8ÌÒˀå3Œšö/|PµÐ¬Ñîm G*d ¾½«ªðàpãG¶ AÙޗTðΏ¬@°ÝÙFÊ¿w#¥|ûà˜fñgÄYõkF‚Øœ +³øÖWËc´à’¼WÐ^‰¦è°ùv±ÃêTu¥þÄÒ¾ÖnþÁÚOü´ÛÍ_*%€FÀmuæ¾dñͅ÷¾$ n(Ù³îÈújªjVŸ«@a¿µŽu?ÞÅ|×ã¿Ïñ-ì4>ÍÓ 7u5»ñ#E>øW¥Ø&r+N÷M±ÔãßÚÇpƒ¢¸Èâ7þMàu…Ú¡Ú¦à1ÍQýŸ§6I­NQ–¹Æ=«ß£±³ŠÏìqÛ¢ÚãPb¡³Ñ´­88³±Š'߸Ý@ ñ+âeˆì$Ò"Ӌ]nÚo Չ´k½'à㛥|ºä.+ØÀþæ÷û:)9éÞ¶g±³º¶û4öé%¸‘Å|çðÃâU®… :TºnùílÍ}g8º´Šà â³£ð§‡bI‘l®:+UP* Ú£ ¨Å>8s¬é¿ï-z¾‡g υ¬"™ÐÄ2¯)øßÿ!­3ýå¯^ðçü‹–õÄP¯ðÇÃZ²–{IOGµ¼9áؼ=`m"pÉێ•¹EGäŠQŠ}Њ;Rà +Z(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(Ÿñ—ü€í¿ì+¦ÿél5ÐW9ãycƒÃ±M4‰Qêzs»»aUEä$’O@[ÿ„³Ãô0i_øøÐŏÿ g†ÿè`Ò¿ð6?ñ£þÏ ÿÐÁ¥àlã@V?ü%žÿ¡ƒJÿÀØÿƏøK<7ÿC•ÿ±ÿlQXÿð–xoþ† +ÿcÿ?á,ðßý WþÇþ4±EcÿÂYá¿ú4¯ü ühÿ„³Ãô0i_øøÐŏÿ g†ÿè`Ò¿ð6?ñ£þÏ ÿÐÁ¥àlã@V?ü%žÿ¡ƒJÿÀØÿƏøK<7ÿC•ÿ±ÿlQXÿð–xoþ† +ÿcÿ?á,ðßý WþÇþ4±EcÿÂYá¿ú4¯ü ühÿ„³Ãô0i_øøÐŏÿ g†ÿè`Ò¿ð6?ñ£þÏ ÿÐÁ¥àlã@V?ü%žÿ¡ƒJÿÀØÿƏøK<7ÿC•ÿ±ÿlQXÿð–xoþ† +ÿcÿ?á,ðßý WþÇþ4±EcÿÂYá¿ú4¯ü ühÿ„³Ãô0i_øøÐŏÿ g†ÿè`Ò¿ð6?ñ£þÏ ÿÐÁ¥àlã@Ïø{þCž,ÿ°¬úEkV?á,ðßý WþÇþ5G—v×ڟŠnm."¸õTÛ,N[vÀàŽ Â€:j(¢€ +(¢€ +d¿ê_ýÓO¦Kþ¥ÿÝ4Áü7ÿ[«ÿ×Ã:(øoþ·Wÿ¯†þtP…ÿò-Ëÿ]Ûùšíëˆø_ÿ"Ü¿õÝ¿™®Þ€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +ðoóG‰4Ǒ‚¨*I5ízž­k¥¤~qy'”í‚Þ%Ý,Íè«ßÜðR@æ¸ýsáèñ­Â_x‡lEF"³„äF=]ÿ‰¾˜QӜn tŸxv-ÍQ€2ƺU¿øO¼7ÿA(?ïªå¿áEøwûÒÿßT‹ðï÷æÿ¾u?ðŸxoþ‚PßTÂ}á¿ú Aÿ}W-ÿ +/ÿߛþú4‹ðï÷æÿ¾u?ðŸxoþ‚PßTÂ}á¿ú Aÿ}W-ÿ +/ÿߛþú4‹ðï÷æÿ¾u?ðŸxoþ‚PßTÂ}á¿ú Aÿ}W-ÿ +/ÿߛþú4‹ðï÷æÿ¾u?ðŸxoþ‚PßT§Çž^ºŒþ\V«ðSÃöšEÔñ´Þdq–Sº¼ûᧀ4ïj×°_I+$$óPºÿÂ}á¿ú Aÿ}Qÿ ÷†ÿè%ýõ\·ü(¿ÿ~oûèÑÿ +/ÿߛþú4ÔÿÂ}á¿ú Aÿ}Qÿ ÷†ÿè%ýõ\·ü(¿ÿ~oûèÑÿ +/ÿߛþú4ÔÿÂ}á¿ú Aÿ}Qÿ ÷†ÿè%ýõ\·ü(¿ÿ~oûèÑÿ +/ÿߛþú4ÔÿÂ}á¿ú Aÿ}P<}á¼ÿÈJûê¹oøQ~þüß÷Ñ£þ_‡¿7ýôhŒø»â/WÖ´ï±]Ç.Ö\í9¯rðçü‹–õÄWŸŸ~Ü%ž9Tå$S’§×œƒøŠëí5ü9ož·%¤`,z” +|œÓQɈû’Wý N(¥¢‘Y]C+R29RÐEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP]D(êOPà Ô?`³ÿŸH?ïØ«P°YÿϤ÷ìQö ?ùôƒþýŠ±EWûŸüúAÿ~Å`³ÿŸH?ïØ«P°YÿϤ÷ìQö ?ùôƒþýŠ±EWûŸüúAÿ~Å`³ÿŸH?ïØ«P°YÿϤ÷ìQö ?ùôƒþýŠ±EWûŸüúAÿ~Å`³ÿŸH?ïØ«P°YÿϤ÷ìQö ?ùôƒþýŠ±EWûŸüúAÿ~Å`³ÿŸH?ïØ«P°YÿϤ÷ìQö ?ùôƒþýŠ±EWûŸüúAÿ~Å`³ÿŸH?ïØ«P°YÿϤ÷ìQö ?ùôƒþýŠ±EWûŸüúAÿ~Å`³ÿŸH?ïØ«P°YÿϤ÷ìQö ?ùôƒþýŠ±EWûŸüúAÿ~ÅKQ»bQzáF>Š(¢Š(¢Š)’ÿ©÷M>™/ú—ÿtÐðßýn¯ÿ_ üè£á¿úÝ_þ¾ùÑ@>ÿÈ·/ýwoæk·®#áü‹rÿ×vþf»z(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢«ÞßZ鶏uy:C +c.ç¹àêIàÉ4b±.5™ï.d±Ð£Žyãb“]ɓ¹î }Ç÷ñüExÌ^V£ânÚn”z@ K‹þÙƧû£æ=Êòµ·om´vöÐÇ ¨TŽ5 +ª=(–™£A§<— $—WҌMw> Ž=8U•@Ó$šÒ¢Š(¢Š(¢Š(¢Š)‚)cÐrii # Ð â_ˆ¾µ²¾°ŸRU¸òÊìïšò¯…>1Ðt-_Q›Q½XRBvÞ³~9øLézùÕ¢M°ÜqÓ5å6}}¬zW +(îMÄn¿oö6àM÷…i×+ðûéῠÚZl .ܱ®ª€ +(¢€ +(¢€ +(¢€ +FAê Ph—:K¼=,qGœ¾1?g÷Ɉÿº +õÊäæ­éÚå½üíi,rY껞ÎààyqïûJHõÁâµ*ž£¥YjÐ,W‡ØÛãpJ¼Mýäa‚­î4rŠçþÑ«h<^,º®œ?åæ$ÍÌCý´QûÁþÒ ßìžMlÙÞÛj©ugqðH2²FÁühz(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +d¿ê_ýÓO¦Kþ¥ÿÝ4Áü7ÿ[«ÿ×Ã:(øoþ·Wÿ¯†þtP…ÿò-Ëÿ]Ûùšíëˆø_ÿ"Ü¿õÝ¿™®Þ€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +)®ém$Œ¨Š fc€îM`ÿh^ëÿ&ík§Ÿ½©2Òú`§‚?é£ ¾³oQ֖ÖäXÙÀ׺“.án€€ôi¢/¹äàí F)–Z+}­5Ze¼Ô&<."·Ïh”ô8à±ËP8tí2ÓJ¶0ZE°3ovf,ò1êÎǖcêNjÝQEQEQEQEQEUyïm­ï¦Túš‡ûgNÿŸ¸ÿ:å¾(øj?xJua—K­x?ÁÏ lx¹žá[C»‘ÜWӗ:Ž™um$wÙ©æ±|?¤è¸–[[ˆ„’žh¬*€:ŠZEeu ¤zK@Q@Q@Q@Q@Q@c^h#íO¥\>ýÎde]ÑNé¬|ÿxßícŠÙ¢€1muãÔv͸°½íˆ–ÝÁÿ¦r`dÿ²À7^涪«[{ëY-®àŽx$^92°÷±~Ǫè_6œÒjZxëg<Ÿ¿ˆÓ)üÃý—?F€: +*–›«YêÑ;ÚJKFvË©I"oîºTýE] Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ™/ú—ÿtÓé’ÿ©÷Mp ÿÖêÿõðßΊ>ÿ­Õÿë῝cáü‹rÿ×vþf»zâ>ÿÈ·/ýwoæk· Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ¨ë¬:.œ×³E4ª$Š%ŽÝä‘c@2@å˜M^®Æ_ò¶ÿ°®›ÿ¥°Ðÿ 5×ý +úçýñÿ£þk¯úõÏûâþ;]ÏÿÂMuÿB¾¹ÿ|AÿÇhÿ„šëþ…}sþøƒÿŽ×AEsÿð“]Я®ßñÚ?á&ºÿ¡_\ÿ¾ ÿãµÐQ@ÿü$×_ô+ëŸ÷ÄüvøI®¿èW×?ïˆ?øítP?ÿ 5×ý +úçýñÿ£þk¯úõÏûâþ;]ÏÿÂMuÿB¾¹ÿ|AÿÇhÿ„šëþ…}sþøƒÿŽ×AEsÿð“]Я®ßñÚ?á&ºÿ¡_\ÿ¾ ÿãµÐQ@ÿü$×_ô+ëŸ÷ÄüvøI®¿èW×?ïˆ?øítP?ÿ 5×ý +úçýñÿ£þk¯úõÏûâþ;]ÏÿÂMuÿB¾¹ÿ|AÿÇhÿ„šëþ…}sþøƒÿŽ×AEsÿð“]Я®ßñÚ‰®€$x[]>Á ÿãµÐQ@Ûu=VãÎ×<3¬=º6bÓáXL#†™‘»à€£Ð·?á%ºÿ¡[\ÿ¾ ÿãµÐQ@ÿü$×_ô+ëŸ÷ÄüvøI®¿èW×?ïˆ?øítP?ÿ 5×ý +úçýñÿ£þk¯úõÏûâþ;]›£kQë)w¶ÖæÖ[Iü‰¡¹U­±$t‘²)ëÞ´«Ÿð÷ü‡gü®§§zoü$×_ô+ëŸ÷ÄüvÈsşöÿH­k  þk¯úõÏûâþ;Gü$×_ô+ëŸ÷Äüvº +(Ô®¿´eK‘áŸÚßÆ1åºÀ² ô?¼!—ý–}ªM7ÄÚê#Å©ø[T‘á.-Ò%VC/È}aî:W]Esÿð“]Я®ßñÚ?á&ºÿ¡_\ÿ¾ ÿãµÐQ@ÿü$×_ô+ëŸ÷ÄüvøI®¿èW×?ïˆ?øítP?ÿ 5×ý +úçýñÿ£þk¯úõÏûâþ;]ÏÿÂMuÿB¾¹ÿ|AÿÇhÿ„šëþ…}sþøƒÿŽ×AEsÿð“]Я®ßñÚ?á&ºÿ¡_\ÿ¾ ÿãµÐQ@ÿü$×_ô+ëŸ÷ÄüvøI®¿èW×?ïˆ?øítP?ÿ 5×ý +úçýñÿ£þk¯úõÏûâþ;]ÏÿÂMuÿB¾¹ÿ|AÿÇhÿ„šëþ…}sþøƒÿŽ×AEsÿð“]Я®ßñÚ?á&ºÿ¡_\ÿ¾ ÿãµÐQ@ÿü$×_ô+ëŸ÷ÄüvøI®¿èW×?ïˆ?øítP?ÿ 5×ý +úçýñÿ£þk¯úõÏûâþ;]ο‹<‡‡íz¯k³Å*E±ZGX×;d'™GNõÑW?ã/ùÛØWMÿÒØk  Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ™/ú—ÿtÓé’ÿ©÷Mp ÿÖêÿõðßΊ>ÿ­Õÿë῝cáü‹rÿ×vþf»zâ>ÿÈ·/ýwoæk· Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ¹ÿÈÛþºoþ–Ã]sþ2ÿ·ý…tßý-†€: +(¢€ ++ÔôïøãÃ~šµÍM,äKF¦7rÀpOÊ:÷ ‚Šj:Ȋêr¬ڝ@KWÕìt-.}OS¸öpe”©m ԊÊÖ=ðߋå–RYçˆnx]78ÎÖã5ÒPEPEPEeÜx‹Jµñ ¦5Ø]Rî6–61. N@Àû§©íVíµ;ˋ›{k˜¦–Ù‚N±°cǵY¢Š(¢¸Cñ—áø$Æê ´ßüEo]øÏö^‹Ä3ê‘dÊ@K”Vu$ðœ‚:qހ7h¦£¬ˆ®§*À}©ÔQEQEQYúÞ·§xwHŸTÕnVÞÎ ÈA=NrI=…M¦j6º¾—k¨ÙHdµº‰e‰Ê•Ê°È8<ŠÉð÷ü‡éëЌu­Ú(¢Š(¢Š(¢¹MWâ_ƒ´MYô½G]·†ò2ǵÛa=‰P@?SÅutSb–9¢Ibu’7PÈêr„â@ÿŒ¿ämÿa]7ÿKa®‚¹ÿÈÛþºoþ–Ã]QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEÉÔ¿û¦ŸL—ýKÿºhƒøoþ·Wÿ¯†þtQðßýn¯ÿ_ üè   ÿä[—þ»·ó5Û×ð¿þE¹ë»3]½QEQEQEQEQEQEQEQEQEQEQEQEQEÏøËþ@vßöÓô¶è+Ÿñ—ü€í¿ì+¦ÿél4ÐQEó¯ÅM1ïþ!ø’î~Õ¦hÖ÷а©IS'þù, +Àø›ª/¯5?ÄU¬ôë #ÛÑd›÷„gÔeÇá^óqàU»ñ®¯®ÏxßRÒNšöÂ<Œ¶ìóÀéŠãí~ý—áÝÿ†WYCsyz—-wöc€¨ ·wûÇ9ï@|Câ?j~8Ò¼á½F=,›uy|Ð ]W*†ãÓþúëÇ1iÞ7×|/®ø›ÃÞ$¼‹T“KÓ[R´¼ùM**ƒ±•xêzû¼cÄþºÔõ?Ä°t½vÆßìë3B$Žhùá”ýO<õéҙáχ-eq¬ê^"ÕWÕµˆ µÔʞR,$`¢(éÀû=@<ÛZ—ÆšÿÁ[ÿê>#†k[Õ úh³UDŒJmqÈ`@<çZÛÕ|1«_ÙøÄ>¸ÓçÖ4í&]6õ—)Œ¨=ùnxèa =r™ Òè>¿Š]fóĺüÚ¥î­lmf§•q•Úv§MØœv÷ ZëÆ^ öt·ñ*jN5‡#uז™?é:cwŽ”¾'ñ‹î1ë^#ÒL’ø~ÊY&µwj‰@´Ü1éÙkÞ(æ ¼²ð-ö›€ï<@$¼™–ahr@IÁcãžqÏZgŽ+…ž×!y!ût®šý¥¢Êðª¹PUÊ3‚{ ŒqšØð'^ê-né¼]ˆ,lìÚé!’×ì÷‘ímÀ¥{dgøzf¯Yü:×t¿éF™âɬﴩãž(ˆ†ug-²X÷|Ã'®O~j_ü5’ÛÄWþ ñí­ýõå«Z46¶¢Dm÷²Ë8Éõú`ÍcøŸâ94#âdñl~Óïk¼­ûvy›sœsœôïšöFMWÖ¼?¬éºŒvÚ[ù·–R/ï%Þ¹^vœc#¸é\­‡Ã?i6‹¡iÞ7šÛÃÉ7›Ço‹˜×v㐄÷÷éÚ»KÝU›ÄºMõ¦¹%¾›hŒ—6%7ý¤B’Äõ~TãaÏ¥l¤‹äEþžßtv¬oçûNÛhËnµjÞL_è–øÚ1@y‰ÿ?íùQæ'üÿ·åQcVÿŸ;z1«ϝ½Kæ'üÿ·å\ߋX4öX¸2üÂ:Vþ5oùó·®wÅ_lûE—Ú¡Ž1¸ceu×?ò°ü+£·ÿPŸJç.äaøWGoþ¡>”%Q@Q@Q@Q@ÿ‡¿ä9âÏû +Çÿ¤VµáŸ쥓âoŠµKn.´‹[;øˆåZ ~œ6 +÷?ÈsşöÿH­k"çáêÞx»ÄzÌ÷Ê`Ö´Ïìó““Ê«»9çîç ø“¨Çã oSñ%»—±²k+}݌ŠÒ0B~5ëZæ½âOüLŸÁžÕ#Ñ °´7wžBÍ#–Ú@PÜcæ_NÿJÏƒà‰·øz|4šÌh}Io¤ºû1Á +»BmÝúç¹®ÄÞÔ.üPž(ðÆ·ý‘¬˜|‹‚ð‰b¸N۔ô#× èFhšµø‡®ø\xÇGñ °ê:†…l·6—B0‚u}¡wªð9téê}3\·ŒcñïÁoíý_Äi}m¨ˆ&–Ë숂g …\`çî‚1ßÛ5ézà kkxëڄº®¥¯!Žúëh ŽqƒÈú8®~ãሯü(þ¾ñŸ›¥[íû kd ®#Ì9ÉdŸNxÅ3ÄÞÖnõ +ø—Ãi·Z¾Ÿ§ÇÓ/~tÛÊ ß=Æ8Á¤ð§ˆ-fø•·Äþ}ŒZ»¥ÌR±Žáß(8<)çæû½rt"øks¨i:ޅ®6•®é¶Ël'‡IÔ a—>ç׃ӊ<;ðóS‡Å«âŸx€êúœp´G(¢R<¹ñÔõ 6_Š Ôô›ßCâÔ²¼Žf6šé¾bI#¤ÇR ïÛ·n×Zñ®»¯kðîs‘s­X‹û‹·‹Ìh“kŠ­ßån¾Ý9§Ûü1ñ&oq£x{ÆO§èÎfòÅ°7däªHô<~§;^+øq¬\hú®­M§ëºL~T7²¯šfL`‰3×<óßqÈ9  ­JOøSÁ~)ŸSÖ­o–Ú&¨$a'#!ÓnÞþ§§å‘â/ø†Ïà‡‡uë}IãÔf¸¦\0|ñŒvtú_붲×ψõéµ;ín"g<¸á]»~DÎ3Àç¥s²ü ñ ÷…`ðíÿ‹£}>ÆUk(’È IÎrN vÏzŸÅzϋn¾0ÚøWBֆŸks¦‰]ͺIåaœ³€G$…dãšï^â՟†_Y #xtî¼6±–óþqæŽàó·8®¶_<Ÿ!ñÛ”$vÏì¾W$äÛ³ïÓKàǓâ„>1ûr„ŽÀÙý—Ê䜓»v}úb€<§á~›âøVþ%¾Ñõù#•%míÙg_-́Žy` +íÆ9­ÛŸˆ:¾¿á?Zèw¦ o[¸Üʁ¢ÅĬW?7AÀ5¿áo \|1ÍÝ÷ˆ#o n{•€Û|Ñ;ù™€$à `qÎk‘øAáû-Câˆ|M§‡}Öy"ÓՂîåŠÐã× :P·^ǕÇýsoå_9x^¼á‹èðx÷]<Án< Ðîn0N ã>߅}!4~lGœoR¹ôÈ®gá÷„ÀþE{Õ¼d•äóV=ƒæ9Æ2hƼIáWŸ´m?R +—Í­¤ÞK6áå|)#铏S]·öϊü-ñO@Ñu¦«e¬DæHþȐˆœ˜ÉÆqÔýk¬øƒà×ñ¾…k¦Çz¶†Èü… 1ŒïT^!ð;ëž;ðÿ‰ýa]'v`1n2äÿ{#‘ Æ^+Öìõ}tÁãÛx.-7M'M°78U&}‡kqórqÏ¥MâOx™~øGX†i¬áÔ:¥õ ™¢À·qÏåÚ´SáN¹fÚþŸ¦ø©mt]fWšdû iÁ`r»óӜééœÖ¢ø]±ð¦…§é>+šËPÒ(‘#>EÊîÈY"ݎyïøcøKǓ ÄZ‘ñ]·ˆítû6¹†'µû=Òá×ÏíÏ8®>‰Þ!¶Òl|B|Z—÷’̦çBnØÒ"Ç!d œ€~ýûú.ƒðÅ¢Ô5­OÄWð^ÞjֆÎXí-„$Da°;±Àäþµ[Møsâ½>ÞËF_́g(xÒÚ*å|³ =9>¿N˜ënlüAqã3Q´ÔâÃénÂæɗç–Bk·¶W¸é\_ÄÏ Ë§xWX>Ðmd]O̸Õî¤rÒ¨6ä ܟ¼p8®âïHÕ¦ñ…†©´ðépBÉ>œ"g!°Û³Æ2; qz§Ã íz½¾ƒâױѵ™ï-fƒÍdÝÃˆØœàŒŒqÆMuþŸO¸ð†ÚTÒÍd¶‰RL»\ìNà2È<è«/Ãz ¯†<;c¢Ùk{Hö+?Þc’I>ä’Ô Æ_ò¶ÿ°®›ÿ¥°×A\ÿŒ¿ämÿa]7ÿKa®‚€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +d¿ê_ýÓO¦Kþ¥ÿÝ4Áü7ÿ[«ÿ×Ã:(øoþ·Wÿ¯†þtP…ÿò-Ëÿ]Ûùšíëˆø_ÿ"Ü¿õÝ¿™®Þ€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +(¢€ +çüeÿ ;oû +é¿ú[ tÏøËþ@vßöÓô¶è(¢Š(¢Š(¢Š(¢ŠÏÖõÍ7Ú\šž­r-¬â*R¬Ø$àp ž¤W*Ÿþ»ªÄ  ÐJâJ`U?ŽŸòIµOúéþZóÿx«QÔü;§ø>÷ÁvúeƧ QZßß\¡|á‚à|ŒÐБKÑ$±:ɨdu9 BqN¯ñ>¿¨x"? x×[],}Œ5æ¬ÐÙUQpz•#§÷zsV<+ãÏ]'Š´˜.‡ˆn´ûCu¦^‹C ¸ù~ã&H$p'>ÔìW€øSâ«{©é‹wãÑ ûÌ«{¦êÚjÃÉåcuð2WúWIw©xÃZøÇ®xgJñ +éºu½¤Sn6É+G”îܳw< ЭR:,ˆÈêX`©zWX|K×'ÿ ŠÿßUÖeÍÿ=OçGö\ßóÔþtÉÿÂ3âú¯ýõPËàÍvòâ'»¾GXÎpMv_ÙsÏSùÑý—7üõ?SÔ#[ÙÀX3.ÅtÿêéYGGvug|ã¥kD¥# +{P袊(¢Š(¢Š(¢Šçü=ÿ!ÏØV?ý"µªšßğxsT“LÕµ”¶¼ˆ)xŒ26ª‘ÐÕ¿ÈsşöÿH­k˵ ORÒ¾>øŠãLðëë²fDÝ&XÊ.ØÎï˜ôÆ<Шx{Ç^ñ\òÁ¢jðÝÍîx²6=@` JèkÃü+xãâD¾8K="×K·{y,ápÓÈä0̀êy }Ð=qˆ¿1Ôäø_âJ×ŶšÄöIºÖîo*xéæ£3ÇzòqÀ¯Ñ^s­|CÓ~éÞ=oC:$pÉ>˜öˆâbqqÉcN1׎•¹©ø·^ñw¬¼1á}Dig&¡wxÖë+€ê¬ª¡¸èËéÔóÅzµåg‹µËËâ_ˆü'³ñÑñL#…bÉ•L¦<»ã®{­{ýã~>ñεc{áù“P»Ñô ë¹–úÎÉgo5†vü¯=ê[oˆwÚgÂís]_ØxŠkY;Iã·0țØ*ùѐ0FsïÈÉë@¿PÝÝCcg=ÝËùpAK#àª£$àsÐW‡èß5›wÃ¥üYÿ ZœÉ ý™Ó|Ÿ²—Æ +8Q Çáùz÷‹äL×ìqÿ¢Ú€&Óµ}/Ä:jVS%֛:¶£ :‚U¾Vêj‹Ãzö‹â-$]èÏc˜AŽ6U€€£µx÷Ãýkâ·Ãm>ßHð•æ–±J#¹’ùQ˜o}Çi99…dø3Å·¾ø 5öš©öۍa­a’A•ˆ²)ÜG|?}Exdž|s©ZxëIÒÅĺv¢¬’ÈtóÚÊËÎTž?>+7ž2ñœú½Ü>¶7Ö³•¦iÿh…cq$¥x<œäÿ<y¬¶ñ’ž$O5Ø«Ãç­¾ÆɏŸ›8ÇcÞ¼ãÄ>4ñ¥yàŸh×±i·úõ¤w—W‚æ5)¸„VÈìÿäVMšêš/ÇÄþÜÔ?´¤µÐÝÖéaXšXÆãʃ€ÙÜ=ð(Üh¯âˆ®ôYüI‹#ŠôLZ tíÑ´A±´ÉŽ¸ÉëÛ®kªñ‰¼U¬ü@ðƑ j¿Ù0k:ÝȲB²yD‡bpGÞ;f€=†Šñø§Äþ×l4kÄwÖbÙ):½®›¿i¸þ"Àð g çëšô‡ÅƳáƒ5׈,uÉc™“ív±˜þ^0nýQש먢Š(¢Šçüeÿ ;oû +é¿ú[ tÏøËþ@vßöÓô¶è(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¦Kþ¥ÿÝ4úd¿ê_ýÓ@Ãõº¿ý|7󢏆ÿëuúøoçEXø_ÿ"Ü¿õÝ¿™®Þ¸…ÿò-Ëÿ]Ûùší袊(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(®Æ_ò¶ÿ°®›ÿ¥°×A\ÿŒ¿ämÿa]7ÿKa ‚Š( Š( Š( Š( kǾoxBïCK±hÓ´l&1ïk†é‘éU¼[à+?ø*=êEY­ãAow³&9cv3ЎÏz먠9Ô>ê×všü>"øŸEˆÃ£ö|­Ä}6º鑞zŸ^54Ÿ뉧jË­ø²úêûQ\,¶¤Â–|qå.NN{ãëžÊŠò›¿…zî½öøš CM²•dYÈ-Ô¡z+HI#‚rrk}/WÔÿh Y:]ü|.²4BXä"]OQÈ9ì@¯o¦ˆÐHd¡Ï€äþ4Àhß ­­ü7¯iúÕüš…æ¼þmýʯ—óWhí†$ûÖOü*{R´²Ñëºv·ª_ø?ÄãI‡V”Ëwo-¨”+œåÐö<“Ö½&Šó©>émðäxM/nÄÿlûv>sqÓyéŽ1žóÍTÿ…iâ=OVÐ5_ø´_Üéi4q­ D(¤8#.Ø\±ô¯P¢€< âŒ:WŽþ%hZ‹u4šˆy,õO)¢WîÎ3œ÷=«Þ¡†;x#‚ jtP¦Çko ÒK$²rî¨o©ïRÐ?áïùx³þ±ÿé­tÏø{þCž,ÿ°¬úEk]QEŒÊ£$õ4’8Ž6v蠓_=x§Æ> ñWŒçÒü9#,vÊKàúPüG­êº·Ælìï+hØeðkèŽÈ#Ã!@9>ÕóÃy¦›âíæªG›i,Or*Ö¯ãxºþòãKv†ÎБ•=q@Lõ¤, à‘Ÿ­x·ƒ~)É‚î'՛7žäVƒ¨xÛŒ]xehì!$…Ï +ú#ÔR䆼µ-Zã[{ÙJÇmð{Š„¼{®?‡5[ûÆ%Wpˆš÷½ÃÔQ¹@ÎF>µò…ßÄ/Ý´Œ–ìÄÍ-÷|dº.žóÈÉ°ÚàòÔõ~F3ž)+t ý x®¹ñ"æ˺]œƒí÷jÝÏÝ®oBñž¹áOÁg{z·‰tyÃd.hèìQAu +[pÀêkæ½[âŠnuíQtö&}úVŸ€üUâ=sÂ:óKO¥N(Õ´ÿˆ>§¯Ë£ÛÊâ3ƒÍu•òŸÂ]YÔüp×ðà¤n~Òÿ}XQEQEÏø{þCž,ÿ°¬úEkTì|ö5OÕt½³[Qmåà¡]œîÏ?sÓ½\ð÷ü‡$Ñ­î4oxÉôýyÌÞX¶⠜•I€gÔçÔè 7Ä>×®gÓ®ü?⋛9­!ò$‚ðàº\ct‹‘óòryÏ1\n³à#áO‡~5Õ//"»Õ5;mÓ´aŒ÷Qדÿ×ϲR2†R¬SÁu Ð>k~&ðaqâ§_ Ïo ̶"Ù|Ðp “®ÜœŒôô8®ÇÄ..5ë?ø_VþÆÕí­…¦Z!,RÄ8 +Ê}× ô®ðª@ ;RТ|8šÊ×Äz¶°ÚŽ¿­Û½¼÷­ԍ +í +¨Aǧ@ÿ ¥›á ^þÕA$d¥ù>îï|u¯D¢€8=GÁ^!Ž=&MÅ/i-”vsZÜFdµ¸ +»wóòŸÏ ühéŸíSÃ^ Óõkñsw®ºÉq5¼ p²Éå éƒùûW¥Q@¢ø/Ŷږ˜uoÉ>›¦q½¤K\€¢bÌçŸ\×g¬XSD¿ÓĂ3um$ÈÎÝÊW8ïÖ®Ñ@ïƒü0ÞðMŸ‡žè\5¼r!œ&Ðۙ›8Éþ÷¯jä4ÁðÚ_ ^jÆI ïÛa¼Š¦'Àå$ç¡ïÞ½FŠât x² zKÄ>.{è­£1Ågk“™ÏÏ æ<ôÇaÍs0|!Ö­4M_Ãv¾)Ž-úG™cû3n `3g8ëŽÙ¯\¢€<ëWøky{¤xjKlYøƒÃð¬6÷ÂRE + „÷Àõêx9¥Ò>ßÛøÚ?k:ðÔîžÉ­®ck`Šäñò€pª0rr{×¢Q@YgðÇÄÚ=¤š‹ãIl¼<әQßý&[qE™êxïÇ'=þy~"hþ(]AŒzu³ò$Rï.CÅó×çôçØQ@_ˆü-âK½qµMĦÙ%‡É›O¾ˆÏjÚTÎð;zúšŸÀ~ÁvwÁ¯Ýæ¡?Ú.eHDI»Ñp dþuÖÑ@Q@Q@ÿŒ¿ämÿa]7ÿKa®‚¹ÿÈÛþºoþ–Ã]QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEÉÔ¿û¦ŸL—ýKÿºhƒøoþ·Wÿ¯†þtQðßýn¯ÿ_ üè   ÿä[—þ»·ó5Û×ð¿þE¹ë»3]½QEQEQEQEQEQEQEQEQEQEQEQEQEÏøËþ@vßöÓô¶è+œñ¼±ÁáئšDŽ(õ=9ÝÝ°ª¢òI' €::+þÏ ÿÐÁ¥àlãGü%žÿ¡ƒJÿÀØÿƀ6(¬øK<7ÿC•ÿ±ÿð–xoþ† +ÿcÿØ¢±ÿá,ðßý WþÇþ4ÂYá¿ú4¯ü ühbŠÇÿ„³Ãô0i_øøÑÿ g†ÿè`Ò¿ð6?ñ  Š+þÏ ÿÐÁ¥àlãGü%žÿ¡ƒJÿÀØÿƀ6(¬øK<7ÿC•ÿ±ÿð–xoþ† +ÿcÿØ¢±ÿá,ðßý WþÇþ4ÂYá¿ú4¯ü ühbŠÇÿ„³Ãô0i_øøÑÿ g†ÿè`Ò¿ð6?ñ  Š+þÏ ÿÐÁ¥àlãGü%žÿ¡ƒJÿÀØÿƀ6(¬øK<7ÿC•ÿ±ÿð–xoþ† +ÿcÿØ¢±ÿá,ðßý WþÇþ4ÂYá¿ú4¯ü ühbŠÇÿ„³Ãô0i_øøÑÿ g†ÿè`Ò¿ð6?ñ  Š+þÏ ÿÐÁ¥àlãGü%žÿ¡ƒJÿÀØÿƀ6(¬øK<7ÿC•ÿ±ÿð–xoþ† +ÿcÿ¯áïùx³þ±ÿé­tÌøRîÚûSñMÍ¥ÄW>ª›e‰Ã«bÎØÁäøWM@Q@µN›t©‰ñùùSÂ^'_xŸZ–òÖG–mê§95õ›ÊTòÁ®voxvâåî$Óã2?Þ>´óç…,®õ /XÕ"…üÉKØÕ]ƺ?„/t˜ãΣ;²íkéÍ;ÃÚf•hö¶v©O÷—k>xQ5/íÓí·nÏzðkÂwÖ? ¡½x]f’Mî¸çÓxÆöÓü5»Ð´ûwûlP¶â¨ë^ç{¥ÙêFÎæxÆÌqŠÈÑ| áíIßN°HšpDó@+i>"¶Ó4{ëás}p̧Ž¦»=bÒï@øAj^2“]7*G<×´'Â說öåÒÓÏÝ»w½nêžÒõ›h­ïm–H¢û‹ØP͞#¶ ðÓBµŠ2.%q¿Š5ؚDðþ%Yr+è¹ü#¢ÜC RÙ«$?pzR?ƒ´7»Šå¬ÔËÜoJù»ÅZJÙxËN¶ÕËç¶2ý0+§M;Á ¡u£Áu=Śe'rJ潫^ð~‰âTEÕ,Ö]Ÿtô"—Nð†‰¥i’iö–H–ò 8<“øÐÎþ ¿…ß±GØ,ÿçÒûö*Å_ìóéýû}‚Ïþ} ÿ¿b¬Q@þÁgÿ>ß±GØ,ÿçÒûö*Å_ìóéýû}‚Ïþ} ÿ¿b¬Q@þÁgÿ>ß±GØ,ÿçÒûö*Å_ìóéýû}‚Ïþ} ÿ¿b¬Q@þÁgÿ>ß±GØ,ÿçÒûö*Å_ìóéýû}‚Ïþ} ÿ¿b¬Q@þÁgÿ>ß±GØ,ÿçÒûö*Å_ìóéýû}‚Ïþ} ÿ¿b¬Q@þÁgÿ>ß±GØ,ÿçÒûö*Å_ìóéýû}‚Ïþ} ÿ¿b¬Q@þÁgÿ>ß±GØ,ÿçÒûö*ÅÈâŽÛj‹× +0)ôQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Éko+ï’Þ'oV@M7ìóéýûbŠ¯ö ?ùôƒþýŠ>Ágÿ>ß±V(  +ÿ`³ÿŸH?ïØ£ìóéýûbŠ¯ö ?ùôƒþýŠ>Ágÿ>ß±V(  +ÿ`³ÿŸH?ïØ£ìóéýûbŠ¯ö ?ùôƒþýŠ>Ágÿ>ß±V(  +ÿ`³ÿŸH?ïØ£ìóéýûbŠ¯ö ?ùôƒþýŠ>Ágÿ>ß±V(  +ÿ`³ÿŸH?ïØ£ìóéýûbŠ¯ö ?ùôƒþýŠ>Ágÿ>ß±V(  +ÿ`³ÿŸH?ïØ£ìóéýûbŠ¯ö ?ùôƒþýŠ>Ágÿ>ß±V(  +ÿ`³ÿŸH?ïØ£ìóéýûbŠ¯ö ?ùôƒþýŠ>Ágÿ>ß±V( ÎÕ2[B¬9 TôQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@2_õ/þé§Ó%ÿRÿîšàþÿ­Õÿë῝|7ÿ[«ÿ×Ã:(ÇÂÿùåÿ®íüÍvõÄ|/ÿ‘n_úîßÌ×o@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@2_õ/þé§Ó%ÿRÿîšàþÿ­Õÿë῝|7ÿ[«ÿ×Ã:(ÇÂÿùåÿ®íüÍvõæºv‘ãÀ֚jÛ¼ ìÿ8É5wí獧ýó@íÁ}£âüñ´ÿ¾hûGÄùãiÿ|Ð{Ep_høƒÿÑñþxÚß4ÞÑ\Ú> ÿÏOû援|Aÿž6Ÿ÷Íw´Wöˆ?óÆÓþù£í獧ýó@íÁ}£âüñ´ÿ¾hûGÄùãiÿ|Ð{Ep_høƒÿÑñþxÚß4ÞÑ\Ú> ÿÏOû援|Aÿž6Ÿ÷Íw´Wöˆ?óÆÓþù£í獧ýó@íÁ}£âüñ´ÿ¾hûGÄùãiÿ|Ð{Ep_høƒÿÑñþxÚß4ÞÑ\Ú> ÿÏOû援|Aÿž6Ÿ÷Íw´Wöˆ?óÆÓþù£í獧ýó@íÁ}£âüñ´ÿ¾hûGÄùãiÿ|Ð{Ep_høƒÿÑñþxÚß4ÞÑ\Ú> ÿÏOû援|Aÿž6Ÿ÷Íw´Wöˆ?óÆÓþù£í獧ýó@íÁ}£âüñ´ÿ¾hûGÄùãiÿ|Ð{Ep_høƒÿÑñþxÚß4ÞÑ\Ú> ÿÏOû援|Aÿž6Ÿ÷Íw´Wöˆ?óÆÓþù£í獧ýó@íÁ}£âüñ´ÿ¾hûGÄùãiÿ|Ð{Ep_høƒÿÑñþxÚß4ÞÑ\Ú> ÿÏOû援|Aÿž6Ÿ÷Íw´Wöˆ?óÆÓþù£í獧ýó@íÁ}£âüñ´ÿ¾hûGÄùãiÿ|Ð{Ep_høƒÿÑñþxÚß4ÞÑ\Ú> ÿÏOû援|Aÿž6Ÿ÷Íw´Wöˆ?óÆÓþù£í獧ýó@íÁ}£âüñ´ÿ¾hûGÄùãiÿ|Ð{Ep_høƒÿÑñþxÚß4ÞÑ\Ú> ÿÏOû援|Aÿž6Ÿ÷Íw´Wöˆ?óÆÓþù£í獧ýó@íÁ}£âüñ´ÿ¾hûGÄùãiÿ|Ð{Ep_høƒÿÑñþxÚß4ÞÑ\Ú> ÿÏOû援|Aÿž6Ÿ÷Íw´Wöˆ?óÆÓþù£í獧ýó@íÁ}£âüñ´ÿ¾hûGÄùãiÿ|Ð{Ep_høƒÿÑñþxÚß4ÞÑ\Ú> ÿÏOû援|Aÿž6Ÿ÷Íw´Wöˆ?óÆÓþù£í獧ýó@íÁ}£âüñ´ÿ¾hûGÄùãiÿ|Ð{Ep_høƒÿÑñþxÚß4ÞÑ\Ú> ÿÏOû援|Aÿž6Ÿ÷Íw´Wöˆ?óÆÓþù£í獧ýó@íÁ}£âüñ´ÿ¾hûGÄùãiÿ|Ð{Ep_høƒÿÑñþxÚß4ÞÑ\Ú> ÿÏOû援|Aÿž6Ÿ÷Íw´Wöˆ?óÆÓþù£í獧ýó@íÁ}£âüñ´ÿ¾hûGÄùãiÿ|Ð{Ep_høƒÿÑñþxÚß4ÞÑ\Ú> ÿÏOû援|Aÿž6Ÿ÷Íw´Wöˆ?óÆÓþù£í獧ýó@íÁ}£âüñ´ÿ¾hûGÄùãiÿ|Ð{Ep_høƒÿÑñþxÚß4ÞÑ\Ú> ÿÏOû援|Aÿž6Ÿ÷Íw´Wöˆ?óÆÓþù£í獧ýó@íÁ}£âüñ´ÿ¾hûGÄùãiÿ|Ð{Ep_høƒÿÑñþxÚß4ÞÑ\Ú> ÿÏOû援|Aÿž6Ÿ÷Íw´Wöˆ?óÆÓþù£í獧ýó@íÁ}£âüñ´ÿ¾hûGÄùãiÿ|Ð{Ep_høƒÿÑñþxÚß4ÞÑ\Ú> ÿÏOû援|Aÿž6Ÿ÷Íw´Wöˆ?óÆÓþù£í獧ýó@íÁ}£âüñ´ÿ¾hûGÄùãiÿ|Ð{Ep_høƒÿÑñþxÚß4ÞÑ\Ú> ÿÏOû援|Aÿž6Ÿ÷Íw´Wöˆ?óÆÓþù£í獧ýó@íÁ}£âüñ´ÿ¾hûGÄùãiÿ|Ð{Ep_høƒÿÑñþxÚß4ÞÑ\Ú> ÿÏOû援|Aÿž6Ÿ÷Íw´Wöˆ?óÆÓþù£í獧ýó@íÁ}£âüñ´ÿ¾hûGÄùãiÿ|Ð{Ep_høƒÿÑñþxÚß4ÞÑ\Ú> ÿÏOû援|Aÿž6Ÿ÷Íw´Wöˆ?óÆÓþù£í獧ýó@íÁ}£âüñ´ÿ¾hûGÄùãiÿ|Ð{Ep_høƒÿÑñþxÚß4ÞÑ\Ú> ÿÏOû援|Aÿž6Ÿ÷Íw´Wöˆ?óÆÓþù£í獧ýó@í2_õOþé®í獧ýóHÓüA*G•iÈþí'ÃõÚ¿ý|7ó¢´< j:-­Óên†ââBä(éš(ÿÙ +endstream +endobj +621 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 619 0 R +>> +endobj +622 0 obj +<< /Length 2838 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gat=-969.7%DM^@k\+%#D8%I\2NqZa-T0c:9O+Pr76.`OQH0KRk42q`s*gI((B@C>PL;npfK]N])F/qIT5OZ)FS#B(YW1F>!uA8jZre2"uZALmH?p1`TmKPYjr9M=gPs)t>/kK1gpk'mn1d!'*[nU1FU.-]C*[c`i9mCm^cp=-).Mi6=%[@kNkD[T?8YD:B6-VmiRh=FTZh9s+)WW.mZ&_iIM=uGmklE6gZ0tfS7%:**Y4R$5"_bY&l#cor3.UbWQ_?tEMb/WtIDg:7qAmn/RGeL_p9cSq)'guuLq4o8#nm:XLX]**X\)WD7XCk*;84+/A+BbL4i[VR)0(MGu?qn#t3+66cBf1@%]ssfJAdEID#-iU(f3UnEJ38`DbI:inI/3W^QRggDA'tb:Qu.^C'a%#AZT*l.<#o%j2PJ)DqR+)`A[9hrURZ;fir[nK_D*&L\3M,U.&5mHVr'=[:eOJ(H*=Oe^eVkId`f7#M(>r.dOB+?,uR%8%bF5%QVa+ngO(P(^*NNkE@p(;Kaj[Z5c^!RE1>.2_WKDgT3cn33W=YR!%IZ?PXP"=p4RlQ^15#mC,hY.r`=`@@J]5&``PK0G'j[jI?1mXq/R[FEcFK_GN+>,g%82i/?%1"^;r-/pfP4rFc8Pjs%%06%";5]k=h9'5+M4X"f.bf+!6Ac/^b.%k6U%(_lZ.+)rYc_5#lh/c-/8dDUNU6N'\C2)/]mDq'ATPm'p^+,YXoqG(XQ^@KkddgejmJ(XJn)'s4Tc*Z+)N-cmgsFRrB15%9LB>lp/J?C=_Ks0HA+K%SKS!C:.H?*(4fKQ@5t7k[A0rK^^DeGr`fbaE>upul3c"L!pl>2CF[%5A<"mmT!g9]E4M1rRJ*"3bCTFWd!`n:1?[MZWoG]Cq9-.mC(2*D,=^C\`dm!LmeAoO;3pZ^94YR8#-aZJIe6/YO()p<%i?@7gc)5Fc1IL^gte0JP4&.>*N]Wh:Gi?%o(>u-;]Kce["l^IjqN@mk1DpjI!:XFS]XFhZ)l'=Wi7&C/Js_*[YMg&s0(]1eq*OJ*i;TgW;i@m&bj>Xa=a;-(!Ef(Sss6K1o#%Tgak;`-W7_Si$@[N%D?)ZCI#V,O0f*9,)"TCO9g_d)od=B$]-H?/*juWYs@H<:1/7)=\XuYZ-Q*"IfUdn@/`Y0at8d3k$i(=[?)bj68*Ld(.3B5Rr^4(^)1#e?V^iY\D5Y:1sgj+$=`%_-qluh:iS'*b5?iZ^&+NMI1#QK2.0Zj31<$*lOR(^I5Q-!#`t?^3TjBS43IN)k(aN9VhAN.g1Sp]p7_`%2YTT6$W.8@>)K#eaT<8F)FlI+\'Aj5LJ.]2D.p@hjqk`'W"mOU[!;h3P]obG[6n9Vr_#PQU=tOL5Xlq_/^O%JB1sk4EYpK1sLYp*]D*L.EHJ@kHhT$j-fh;CkWkLU$>;$f(KW1f)^*LYj0f-h#*\'Rh]taK*FPMURm).d`HiGlDA'A?_e]agG9piQNS8-C.qp!M6I5@K0cTn"]kO..5)+HX009-g[7`bYO7q[`gTPj'EWKMNj2,7\$@\B=m&9QG^Pek^r#<+=lLnA=)XG(s^'FaRqa=2&*^Q-/Oq"=s?<>)kc6FPEH<>c"U%lI@CDXOAlL7W/;9RNsP[^+aI]l:=gh'W_iC&-P@fGnA?bH.nL+&%li(5Sa3i*eGR%UZi)=3M+[jWVO;s:i*_0o49C@,_:LBhY1_r:@0)*>+ar%Z=$K32NEn+;\I,:=[,q;'0AGF5]F`X'Q,>2.?Zrk$;lKUu_0]M@A(0Ca'`(Tq/VA^:F~> +endstream +endobj +623 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 622 0 R +>> +endobj +624 0 obj +<< /Length 1622 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gasb\hfIg)&BE],=6Qd39VUaK-20!*Hdh67Ffoq;kqmh('"6?3TE>nKrTagm"A:Sr9jY+ITnQd<0.T9T,6-(>bn:>`A/eTq(%';o?gFUI+.L_RFI-p033CXjMq3\O]1@gWRpZN>&=a;GHe^rD&aMO&+RBB@`@5cFn@'!N!F^%dqI&+X$LNTL25)\6.L=>998!K_m6_E]E*bif^@?ESq^kA1Am<3a9s\6`nVGk_TWBX'U+FHHag>^@f)[f3[kYf3D;0o-'%H[->PLa$DqYQUBa?[]#D?ML:r3<\_PkG4LD(g#NdoQe@:7R@p^rn,=isZCa'5#\4]e%H\P8o9B_FtjjlE*KV9b7I-11Tgd/I0/\qT>uAhTj!>s9>)M%V"V8FFH=,.o9]:QA\!@+2@kh!++q^cm"`<1cAc%;](L93?kcMrl%h'Q0RmcGNu]Eph:4GZ7hG*3suK"UBBgm@f*4D*V"loJ*#%/"h^a9Ke>LNF6J-m1lT#-L)\4/F6Xlp6;G^Nk`\,T(X",6SH"&?t[6k],Mt*Do?%S,&BcT\S[LD,]Xi;k@Uk-K!ml4;ZIIpuG#scqC:%a5`_@p-mkNSu_C#:eH*C0g.e6Td/TBW[T%E*VLfgCpV"h%&V>J72aYLONG*n`gepuMqY;0%*F/RC^.:6<;N^p*C6iG'aXI^4WmC7:IhO2NrHWeoF[7=5+K?6M9\Y+,(.a\]]gjeR9!Mc!&GBO3Fg@^&bBC)_5IJ$H5s!tNA;1l\d$tBVabE+18i,C;CdO8^.0//LZL*?jH.6UpL$V,gr**5MF)Fk(C3_%45csW6$)_Dp4/P\FOQa?5$sIjUlEYC':f7&@)0j+*kbS%?p3ops%b'7flG.u>;0YHj\e9BFk_"[o48crJ`M#p>VNlP>k1OhuHLo]IkT9[V@=$8A">XZ0-3hI2aJ-[\<)8H;UifXI`=.("CoKA$n-R4C(LLWB,Gm]UR>8f>B[^>#PYYo(F4k5_`U@\=.Tid<9's?oXr$YT,95\\B\Q.aDiWoQu9U4gd?"Z6f::$4O`*7U)PS7;&6PnBG>O*Am?Yj=p:Xff"2KKEAJ)1:8,BJq,/N1,]W:H\$73B"h*3YJp]'t+E-_!ah/Qs2?AVE@hK84YB_rN'Z6"\N\7]e!-f,!Eq`\s@CQg23Y.-OVp;[&B\,&#]3\apH6]b.26$@+FY,#()IT1895;)&rCr/m"`apZ49nM;i+*"L9GHVuH`_=sp*~> +endstream +endobj +625 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 624 0 R +>> +endobj +626 0 obj +<< /Length 2373 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gat%%D/\/e&H88.T`W-i!\#?le6B\i5[/=q\$#8pAR5buVJTbIj@XHV'`7D^M584fALBcp,56n;4HnAFNPj0c%u7a\jOuphAcMa3YA`OffG*.o"W=k#4_dPSXUM80%N"4P9bXAb0;%.ZNZ@l*F"p9hQ;2Bm=9:><3Q4*LJ&j%7,S/k_9H\'R[ZRVnW%5NZ>2s/qIpYf9*a=KQHfBnmlVQKtmu,k*MTXDS/2>ssO*b#TP)=!S*nT[p/_]TrI\2)(SSPQW`XQF@)+/fb%qR?DMjN$YF2CJjdO:L=(#9?#!`6qr#pW)08Q#kWm>J3!T79PnB[?.$pu7nhbYm2%D^qD,5d=k<8\=S6Rc16?ZGA!snXSV5A#8a+o+2U8e?CJ[>9Y"o#1XOkb?d:Ci=\!5`-B9Pk#p%h*ZcT[>9IK+J>+dGH7j%8>%%;Fef<]nS49@A[!SG8T-Mh@-Pob_OXC<lAjf"%iBG4^W'XKG/\4jLeR:n0U9q?,?e&PNKJYVF.Ujl_fTt$\md>=(ksh^`lBR&]GLH4l)_EGL7!*I(R=Sp\6g0]DV]ILc>"ifg\KC/X,uD4_YnAm^YW>FTfg=G-".e_Tc&)DU$tQ/BOn?[qW$kcI.4G3jJPF$L8>L64T^l-cc=uM8N:CWWhc?>7FRUf8(n1Xr_DLlH;e`h'luAh5TL/C]D>9OQOO-@l6E$_r@B(k%KV1u=AicM$^`J#!Wqs\Go76n_m.&D&S579+FLmRYS:*u/Njen8*Xhj_"$$?50$Ss;I_n]cWM$XH>Mi:/.W"_#JfZuKdA)_`ZWUgH&D?4V;uR^bE%BtNtmjJ+Z6#"E5oeZ1hf-$#<6SEA/DM&b.c9eYSGf8&O$`@-L>_I=h__bc"QDHcKEOeQZ-"<;1?Z^0=j#41iJp)mGUjoJo]*a8D@f6mm*_.RI@paiEIbnXk@R&_`DA*]Mg#!%@m[$eT*^,@@Y:q@6uR&L(.ZbDOIBG*V`6s.I(pQKS`,DMVhdC*FRH0>h#CK=N:dhmYVEWbW_o.7f6rj^HJ6>d&h`=.ZmfKrhLqmnXe3uuWl]u6OmaJQtTBb5!iWt@TuqW&me$Vk(@GfkRdK7i1F:QGC0-\R(oT,mfWQd<#!6L=aH@`SO6St,oYVEX0Q1T=%TCJ@a^@Tm/[#]NXMcrO]o2)CgKWt0/F^1t,^[MmVqqH/#`TPq``?;qFP6%-5Ce&d0[M$9o;(/XDMFKK/#6o&9-YsV/_&g]5qO8Xe::r?`#7U,;@DTpafN*VC;`7?+_FL*,dn_Kf+)kQYgh3'q5]R.KglDQ'>"Z;W-\jR3"OH-#q-hNW#!H[J-EM^:F3][siD5Mh1P>$.-]t"F[5G8+YVB8$bWQfo,E;pW.6UE`dob=GZPHF*X@$&1h)+*l6Y\*ToQXg@/S+c%`A!H:L`&Juq;+ul@_:quDo["*fg#[>T!!KuR%C]'R$ek>ISdoe\(O+PO%!*DPo.oWFdI>NCldY-!gE>Wb5q!7(WM@H2*IN"/B'!b[O\J4jVrff\M)B&>SC/6Gt_+G7?brmSg-_6dSKGfm7q"8:qk>?G'3+.jj)JSgq#0:b(%^OWhiO1,Dm3hemC'oW5XGc/5Jq^'W/U/--o@01kkrI^GHVZHi^p!VV;0K(+>CX_K\W0'ERZ,V][7)YJE\BJ6/U.,T/YRnE+!`K!8sRF;><4*E;uS(_tBN;DGs\QKJ#Qkg.iVemoFa5p^32&X/W>cKEE)OXQ,BfD*,pS#?%m6SnodN0jlKXu2BBrGXuNY?,1XD8bc:0"JrqFL7(8)jOI^#0YEAJA;8]f!TP6eP::7T`B.m4r+HQ!'4@O:s`K/^*K~> +endstream +endobj +627 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 626 0 R +>> +endobj +628 0 obj +<< /Length 2147 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +GauHL=``=U&:XAW?o3;9V_UqN4T&0j;*<.B3G`i8C"7GN$8U:4Ud@t&h!'mgncV5*P24@S7H/d7@MaBDkL5(*o\f%dD;?6-2R4nNqhSI8&pUkD.?i?Ri7#MfJ">VGn2n#Fj:/RP#'d_\Q=C;'=P0X_[lGY^[AGJ?pVY28a>t['7G,L!Yn!tc`Jk9a=]@MP0/36FCa):rO/tRIl!"_^GN)e'`3p8c\LHq4qVnC4iS-Ht%SiG6F"agib[Y>oc\jVcR*[V5G3D;uNA0eboBDU`p#k)!l1O08M]I+@T-2@(HMt?@(pbs6Y%oe?r,=I*rHS&3h1r>g4+o=!%+j\0RJn@oR1sqQMr@s^o9%Y1-0[e9=M?bR$M>sbX[TP:'i:^[_IO877uN@_("R[S8"Jo^>M(`SGKWg)(jOGNPfI]lrc!"/q0qo2p?(qTac<-+;Or=>lnp/XL/FeDlg%_&7)X*ATWNH42i=OE(5;K]J/4oU.bb[FC4iKJ+9C01`_\8`+g=9Z&.&7d"!7p`'(d9#ihYWOYFmn'?agj5_UA`=XmKOLrWPm,i;Qbf!$>473CbIBj@W'NB9"nEp9`47,qGa?&1h78/9hs4dU/RYkhBI)9Alj;::f'aZN74gF@HVAX$$2CD0i`o"J"D^qST6aD:0)h^k,"F?B"T`#32?f\p.Kb?ABbNUe&uBm,/'GZ)T'WJR4eC%.GqAR-kPRk@FHaWq%s8Z-:3O%&7=W9`>F2MZ@B&E+rVKH`K![\;_+f%Nq'L!7+0>5*'u1Q5UQdI#E%!NrFPk6)Ba!XJnfQpCiFC"_J.D27j;+8O[AP;pLdP@ok*jX,e/bmk>?74VftunS"Xu7*iT=L=oX/6+t3&QGf[eI&P$5d-lKo4j+U/Ja6QR_ns#)kdj.X5r'@j6/-)o+aq>HNntRVMdBNSR"22M7SYg6hp6H")(NEo)mH?f>-7!0koh>A4:NqMu!o]of%?S+;\Wgjg92k9tI-SU):(`%3UE7XZg;$h@ns_\e;*c,@ASnSRP(N#:e<*I2;L<(gW<3g=C'o=nIBEseOsWjW\J/0X)UPd-$#7Rc#1515SghFP[P4%INFX.k(j1tmg?V$MFbBFMDu7%[r[g,`.h+8,HM6_s@8Q8HO36V:"61eS1nZsm#tuZ0fKe1GUnqi?C9ljS<::uh$447NSmcfPaeRqBA2SRg&u`\7nBuo2cd]G-k(=fr&qX5$_^8c-dVulTW3XQG-#@a8i+Wfg)M$HS@@BJJ?C7tZrXModf0NT<:gc'a.\N1i%'2It!Zn'qhP4jk26\7IfIjI6b7HN;CWC+M2M<%?=?WfE[Uc'D83L<4ogOq!8AQ>"$fm1kVJTu@5G:?``HZY,D[b)kF,dHI'=i@"Q_NSY_ffDDVC5-N(p8WIDGqp%4-AElfper#^g2g,pSPS7`?mf\2Z<&%7A4``N4uMj)-d8l@_4e>QrlXcH68f'1l_$*Jh[kAnMOaVJSfSATb#(0]L[Fo:L-$l&+0S8N,IlRN']OONC?nmoJ^&u@#o%2G[13I^/G=fF^1/6uuTLK\`7A=I;fj[BC(IK,:qE"8_c2"=VJ4Q.@HJ@Y2Fh>n;+NRK-)jDJicf^r&Dm.M'^Jl?kYR=0rhl>:U&Q.Xel%FGscRaQT6+NCetlP6cM)pbo^$A\)@"R`.se`B#A'RLfs4k7]96[PA\Tq(pJXr2$XalYlTjsK![,b'EK8=V7hG"%Q]Wrt;)rh!`%D:8e`(QZo3$O,FnSq3N%C)@V_.t-mQcSZ!+1=ls.`^pYl$RU'k7s3a]S9*U$iXTY02s6ilDfLe3dB2.aTQ=Co)"-]d@uBMI29Br:k?)l^-h>Z/+i:J[`]EJXmaHICB:%9W>7CA4msDa/k:57ACs69=YO#*m0YWV"ZNmG-6se'5b[_?"EHidml;Qtu)@f+KZm[/==9iT-3/?Im +endstream +endobj +629 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 628 0 R +>> +endobj +630 0 obj +<< /Length 1842 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gb!SlD/\/e&H;*)+W(b9drY7'okHC2q3Fp:L;^N4o9!lA7b"a&O'7):=C=5/$[c`uZMlmGrA8kN1]-4AkmQfqC\@d64c@b>ZhL2S%=fNU@Y[882I">`KluC"oe/gZ4I>t('a(a@Bqdae0"'S]"_LfXR$U]^"25E0;C-s$'gf6!V=0bnKU;P(a=Scl3IThdFXe`oq51LGkE/I_7VMjZl2Q)hU.r@Lh^>+10aH!=SPYp]0"#_.h2X[Z?IamlXGB8kP2l@kZER'KQ&%)o3ZD?oWP.?Q#K1\ffC#-\funA_&fGTI>@,Bq$jZLnk.ms"*%)rb*#BnSX(&q^pNXC4Kp^6IEg!GLOiLjHGOZc%h[]#@FYpX*V)Z[1l4CH!kSW;WRkTm(H3A/FA)psn.7Q'm@c19pS)84RG$NL(R2M&oF.K@ec,iR(L0GkQWS4G(NJ>%WHHT[o!L(EI/B*/rV(1UVl-bDekXGK4oWrjPaumbFmrjK79QVZl*tEFPJ(U\,"8Aff'+AG=(e@SMROtjT/`P3'BIPdlRe6+-CbuLhkq8k]qbn&(iq3h1r%u*Uh7TAO^6r;69hlkt.[OMRUd%IA(FgU!n4H?iPGU),76,H\e/dK_OT:mjVs21h#?gLU!HILEQe*]]+ZU*?SU2/FW6UH:*Tc:%-$)pkP[h%]fqN'OJ?=+BTehQG_q.D+^&uA)g0b\;lonasAcUC`bhm%S3E[^S('>_j!ppTe&l4VIJT.:IVe45TKTh/!`Fe,e!GIgnpYpa^:d\I$qea%ElK)n9[>\.3I0U/d9B#S0j,JG8mOoo?/^@O4F_a9\XIUG]AY6('>[WLAtrA)&G4eE5!N7YVal4e$&Z0"Jpr.JCmCEO\9>IO!7;Y%e&79-F#/6,\4Y$G>[!@rql(N?_;oEgeY*jHT+)@n!O&%2HB1)ksclWGV)ld"Tqc#+UoIMPKHK-r=bqGS+5&Kj(`Ja\Qm47V\kuJL'8KY62N?Z]P[mJ6\+kLN51fg/-M]42WCA7OmT6&JR#:2d/iFSN>rT(3NK'd+17R(cI#e6VC9E`m;*eB:F).?<*?f[.U8GU3_7Qdin@_p;>WD(.!$GrqWp5ge`r84;>531BH?&4-(Agj#&XG#is!c$5G:^_g[h">=3(a_ICH5Lku/\9N3BEVXKqX4?T!9n#7Jk3ZbYrrMs'6qYNN+7/uEQ)Y0R#/Hq/28C?*[DEj'dHFX"F6'"Br$Jm`Dlb,1%QW/t?pa/8\i]-G,l<%rF1KTTZL@@FIYQFY`7*IA"o0mJ61I*_X+lIe9BLs_Z0_s0C=l%IF`qCMW$Cj5fU\VNG=m>`!G0OW4;47[]T?+\mIKXf#'j.@.L^j9bMp3.tfLGF[Ol=&6FITV4N9\6`=Ql8q";Js!Ua%M,;meTL6YDLXOFFV6b:SEG\qNde9#H*dPtE3J:!YZ6_!k!$ND326=FtWUMoq'6/ckI8+&0k%!h5Mmr!-]M[?ZGpn);,-hMcM$E^3^<;:UL+0MOr,,%O$%G<$qdhOk!IR!464@2>^Nh$e4`Gi,(Xm@U>n`XeGc&bF01=o`TC*M.h3Pe&#>2Er.G+#SNU^9B;X;W`gl0h>uZjO,=@Kp_ErE6u^P_M-!VlhGS07dkHp%2'T!&fPYnm3*-EJX3+u[`R_]dCWH#O[U4nPe5@&t"`hnpa27<`E?U4."T)]-57MjVabNXE"i.u`V1/MY:&Rl~> +endstream +endobj +631 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 630 0 R +>> +endobj +632 0 obj +<< /Length 2187 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +GauHMD0+Dj&H9tYi:<`39Hl%&4.l(5-oVIsJTGnGlV0hL!M14a[H4dnqchelXc*A@DL.L"etP[g?"kDJDQ`n4n(-c%9!k`cmqCNGLNYQMUKsm8+ETH$3/5oT=5CXJk=HMs)4u?@T'9;Glhbr=nr1Z[-l2_c%c\sBb7T)06-,Wb/k*UhZ'HAYk:)k@Iu'=`KsGn@YN/5*dHm*IbBYG1i&RC2Odc4jCmB[-VLNgg?TW\No<"c"c_T%k&(Fs=%](dO[lp9a>uN]@qi'7e&)'a'pUTm"kGn$DfCar$\5.7@D&_-el#4(OeXU:SBcAd50X3DH$4(?`bD_h)*c`LG+ak"?&IZB/qq%mr"'/M7%#N9l>X='X7CMeR^W82(FWY7:.H1Hs,PcP#bE@J\3/u<-Tb@)FXaHS12V#Z95!`i/O"e0#TNjl:Ni_I[>$*?qt:RkfQ+9CXFbmKc=JQJBe=[>?e&pV%,@+iJ9?r-:V92at"9ItN7mVRE$b,/m7#a0ig#>)b+(3+2t>(=nKfQSE1(RUd]%*.'*ZquOW'+\nU+@5fq\3NKK$&;Zh!u`ZUJE0:lj<<8?+]A6NYKSKkPLf^c?AJ'5QdGqfHYPR(7jnFXhku&#-RRPA^AM@[=Icbo86goC.#/C/=@jQl%OF/s=F$\!fWVg)BR4&?3Zs*j>hg4^22^c_!BSqQ=nI38k:BQ/G)+Y$hp<)qQE'_28D/&?^A"mTPo5n1tqhqU]gG?<__gkc*#XVc\4HB@0kGRX$S,W4I('jPVD-I2@hpJDtQ`T7NjM5K"7j;5K_2Mm,qu\6jO-Jmr(3j"mk8;(m:##Nra)`;AfJ\.6YrVN0#DDnqX">aPUb:&=RC5$ReK#K=<]N6,Y"!&!JFe^;gP26:TG`Km^I^*`I+XQYZP@ii:!CJi308&bp#&UBUpE.?NMW4VYgm^?pG0B*#U5^l_4?(Y6,r-TOn;%3,knEHP%(]7;A,9:f8]akk"Y9Rl4c.4[WZ.DDJ)$J1J.U/FX)o^4Xi(?`m97UNJhd.?7h>"g>F^p\bImK=ZIWV9?BK>*3LIGsZS(`Nj5?,@ST!pni:(d]-:ra"1t!8FoQ.%.D4TCG4@66\VfKY?GO/KifAA=kP5hP"DK\d+je\]_/YjWGu\a7emCq;b70H/Bi)]T1-7sYftKjDeq1.D,/2@Ws$]rM\3DcJDbN,a3=mUmHMWXO;AhHVjMT=MENo?[,;s>+PQGBMW96Cb)>SQ)?I54&C5F05U6N(bpti="VDIN=,bi_+MC?L1;H'-ggW)9oe5`6hng3#*V64SsTeI%\8>j3>!U(@5~> +endstream +endobj +633 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 632 0 R +>> +endobj +634 0 obj +<< /Length 2243 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gat%%gMYb*&:Ml+BEJrCJV5P:U+QH^8=I+a(/;DV]>YQ?7DR!O:"5>2?/buUs*[C]P.'HdaFecV+jUQeB84Rpl-X0jo_lk>(.Wq8Cs0/5`%6ZVphdpP<*8ae^Q2]jo3@%oa)uUOr;Ea1@0b`T]J@8g(MCr7<=i2]2;L6'W2H&/mK/e*_fR*>HbKX#tKj-^=$Y-O"M/ME\p+-`c!6H&0M]]E6;#mqZ24c"1VleN/mI`\$6`6'k[j^FZf(O6^]kB,UQ;d]bW:a:uljXqDFY#Dqo&`L6%Q!V%F7H"%)h=YG:]pjsEO2a--0E%*p$[!LNeN4#FJ%j!(rAY]pSq\g0O4J/m]*$3Z<-aC?7#(](Y_.SgdiStnE_=">:^efs4$P%M_HfN;jR#\-Js)#R;%]o]50WAu14l1HX\8j8#\XAGoe-fjU+8;Ca'nN;JmVjm31QcXfGASZ:oqfjMYUa%#F;Tt`30aptppoN!_LEIS`k@b:1.3^t3UG8+qGE[K_k'8T-\-Kks,^#q045FmAZl*Z76-,;_AeIMZ-eKQg.ZD'[g@Z".WEJVOQn^G'$RE*2q&3(DoKje1sI9l6=^a>W$>)pM)B8WgBb_b.,N'][.h)&*JPr-Gm?o5prG1H,SC>q1c=9:hnOKE<-<^\IA8<]f3JmFU685WNu1j52I)M@A4WAi@*J%R9h;f9^Q?_fJMM_fc7oqAnS,cdLD)MfkhsSj^`FDaLuaCm&n+.7E6uAmeq&%S@E.#mtY#OkbD35J?mYE]h%I)S^cK=8q$'(ekL?'QtK"8#rU',qd%u/.ZI0iX6c(Ud@@+ZKYXVjPH7)V+(\N("h&N&f7_:I\>0-"5XTM+kQ=-K?[<4j],%4R-VYg=QT)^MM&aKm$L4RJ08GnKHg6E2"hrsP-Nt.Ufeu'Wg2II.BsQ%Ks!LlTdCa@n;>r&DGiJlqX?T%.\a6echUtQCkQY$?Xis,W[-uI*?!32cs;s)uQh@pG*;ln_aAZXogkQGXcm`5(AoCbeahkH+B@9=St^4QEHgm6MZ2OpGZ.S[VE`E&(>,t4?iQn/D!!go=@S4nDqoE!(NRqJ-4B(]b6.>@$Ql5_=ba*RRhf_4-%O+PJ-C6d%-I%rt]9<^!#=O8)'dB?pkgjJK7(Ml(S+K`UT\7'lmhWbTFf&%U2dbW<:02J(i-ePW7[_n7CkaG(L4?2K_T13hE!?Se[AAH*ufpV:%Y@X&:<8$5Ue/TJIB8r;"=87OdBnNs$C@DLYTbI.<`3n(+nnY#_eb:+)Zn;Zo3rV9hhQihCIgq_WM;S=qfNRq7Kh#=`G(3>Tr25l(DGmsMVP6M^U$7u+Ws!;bAZV-fSceK.@G/)K*mgQdo~> +endstream +endobj +635 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 634 0 R +>> +endobj +636 0 obj +<< /Length 2827 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gb!;e>Ar7W&q801n.o,r(.`[l^Z9*mfK&UKM-J$VK4;.mBSj1*PpKLuj;<,);Iqn)L-.iV?0m%#;aZ2tZLsin&O(V!CDf/QN\ABRQS82#*u0F@-/WeU6AFmV&jGrUXMaP>@r(e+8F\R#X?+8E2[Xa3Z<\0YlOY*i01Zk[MFb#%Q=4`ZrGh?3V@-">jc%12EMJ(jM,$(aC!r`\:;db$r4a!>NEj(B!B!m(Z#J^I&_6/rFKKD+u5jNo8s,LW/ncR=caOp_GU=EF3VGMq>T:_u4BD2gq,WGBWOVg"'Naa?:A%kOi&fn05epFI=JDEC&0CojGg2nMufEQQ/^S/"Ah[dL)4VJ-Unn?HGN^_,$NM=)i,hDZtt#&1@Z6Fr=Bfgn<0dcrq_a]^rJ1lLQQB"#dkJ[4>>:6"R@MM8rf-(k[Fi*g5"ihpXWD&[T^>@/Thd=.BB6TR&kLocD!go(:SuUpnBP.d@kdla$LqL?jIo^E"RfMPFM)Qrd$eU(f-cQ)p1e!L6\uiJ/hu9>7-4d+4/)Qf(J%Il3uRdJVm]KdW3%;Gb/eU&T(N80jE-%jV%i4^10I&=C5LI\MaSPZ(E>cQ!)9eggd.S7jj1YKu:5Kj5O/X@HY42[\I!q/+Ato!o_od"X9pGD@!t^d$MRJ23SuYp/^0[W^!trka3n4A'AlqaZd+;K0gB`Uu0RAXDIL$'-;\n&?BS?H3\V9r+WETB(YWlet`-[0NDlPo"B8j]_q@.(n:0J0$U.8HK0.!6So+'YieU880M2730*QO3!"@_>R9^_&@7!;AGrQa&XL@?gZ0#a\c'1";kC$!Q'I+&]<(7Uu^QpWfZ;7c?q%Oi17]"GYZ#rA/65C`JJD@W@Gd=jSH(bi-dWH@pk4[8B(OFnS=`E`d::,O(C83<8G+^r9UPt1u(LJh5(NoQIM1=/U=ged>4V\@m>[GI1W#X?MZS]H65Lm2W;Pk"3pMHEEQNo:eWM%FF>%4A:M/7f@Rc"<]j:WW=m=>bis`?GI:W+bU\=EqC.6TjNb[/n2DD(5p%Yt&[F>q]UD!.N1\F6!c%*s*e"BiX6Ak?8sfBPfa)3U.$6<32"M`Q*FM#E8L!`B"uZXZ:LP,:THCn3;Eu0\!tkH4A1JY&6lIolpj_Be\&W;mu'"Q\jYYqi)!N4&Q*coD7mSJnJ;rAQ8mra$@1>B/H\c]nGsS59W7g+V_^IMi'[siXM?#@Ub9\jp;p(#@,HW1,D\S+2'`;"HAf9)O`$I%D#+R*DhonFcmuF@0E\\5B1l)A+O<^!U(u26XTV*,QJr>"V4<4d3UV+]ZoZEGEssG-k)AT4=7qg5Cfl?"..FKgL!810G6j#5O#1]^Y_M_DS!=_]$U^EK^IfY94/4X&jV^<#GZHF)R)=O(`c@d;Zi%u>1g%Yq-DF#(=[rj)JP<>L#`_naqO=MaPU<,D?'L)!V`bQKs#i,Y%j]/HU^Y&KhRt[;#r53W[j!YIQ!7Fii>Dr'ek657It?K!N6frE;Y/6]>G`i"Ve6Dg>5ACS0t"lQ\sa%Pd%3_9N]ph-TJbb)^cO,C"?+*".J4!`,=0NFRm051clt=ZCp"8"bfM.poC:hlXV]bZ=3]nj^l5l0cL9eb3`),Pch7G2A6_Q2&$2R@ofs)8O@,XO.8m7^of$)qjb!"+*\UG1gMYfW@[WbDD^.W!9P]G^fY9KMg'lnk*/HnK9jk5K4W1[4_!g$sRRU@R=qf0TeNoLCYn_2CZcUG!DlQT4A3Q3:oi'[7;dAp-:l5Aj$5MQp8$'LtA)7OT%=TKAt&?9q4QFem0;SKocm7\6*A;C0KmQJ!3A4VG,uMBcgH1f#%<]%MY/[W9GF=8ehH;J!5/`LO-8FY=*1h%due'RWPie,STp_J"?pQP.oMIaYJ@Qh\9RdYM2B*j#/&Jb\2*-O,eSf38E\#l[Z)F:&bCMR>T#~> +endstream +endobj +637 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 636 0 R +>> +endobj +638 0 obj +<< /Length 2010 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gat=,CJWtM'`HlqOf_Y&OG\mc2pt;#"#DVL*`IqsU[8OHM;(LqE@28XXQIRl9qBdW)CQUL+SXUAO)pAC+"*i?fr4Y?B;32]fJBDjY>7dGp8]=e"r]!saANpcA=/rrLEcHf8S:Tj/h:611fA?GhQn(A4cRXOup*q('J)PbXG?@F9V*&=AKMMgb9:lI\I!YGQZ:p.#6*im9$f9DhQS+^UjX^jL_?J+bK\#b60L9'`FLcRQI5I*H\UC#u'D=:ctV&R41#Mh6\EgZ`K`Jh6,0'fA+c]H3X"+.o,7\$FTm/EFF/`nhVAKt=[iiGFq6>hg`2'h'"`o/B3>`oap1lnF9!>5WQ0/ItSq`8*T"QKs'mfK3\JMsQ(#ccg<0j#Y'i0[Ed+%Db&P\DHb-RCT^pD1)!Urm[`s^8ElXmiV`4`Oir@Q80Nq^("*X`)=`,,[]?uI`_t?EQ0)%T$-tA%&nt?&doqpSl.)mmJ7C]e@ZfqikgZu((S,;/Hk3as#1]4ob#tCuY2riI+^e16\7jR+D@98TLX9XI?V`#$:4F:m%?6/;%_<[4,:S/J/?]sTglgpfA_O%haDU!p%`JeF7h/L5ciAY_qs,#jakV^TQ\&FS6!USIamUAeE%o$1gMQ%BAV.VH;W>=(jq.*9@!rqQ0NQ4/N^-PLKS55Y?li#sl\6Vh6lW/V>DkM(6XYZkiSb0'D;X)W55>"5rY4YUPEaE?dbI?EhL7j:K%8SKF=X%Wg.1Vo+B3?as3cqkX_8sS9pU(KUgQ_,W(KYDc>IfPBB5sm*[F0bV!=)F+^W4RY8!$Z9rRoETj2cI(`"rtWktVTgGsU&h\Gl@nGo!G9U--,G=#IX::91OS"#u:Eo]\md"n!lmpe+%Q!=@[eWLmh,hA'J;6/W\/E[j0u%3D!d+r3YdYp%Bno]kVQ9-+*`AJQ)d5E!b$js9OTA.t961fP<28^jtk?0N2hCEj3V<+S`F:G[aj]\s\;,dA5;6Y&ji"4^ +endstream +endobj +639 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 638 0 R +>> +endobj +640 0 obj +<< /Length 2126 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gat=,hfG8H&:X@\_0GAkSV\(,+b''_:#gDCdkn2eb['CPQVg#.\RM4^PBuBjpfe;3'#o+CiJ%6WY,'n([k#beUU0\3>M)HS2.);YlX>Gu)]ig@">J.KLj?-\?WhlLbbg_.oBG)UolToMqV.J=%a*#4=R('UR+MDK^4U7ZPD\sC>e[Kj/nXV7jH165^JBMLQ<=i7"0/3kD-`#CjXUe^(41f,22Gr]LV+7^B`T[QUT%S`#';$5e9fKangQ)`G2'^4\it/HXkoZ)o.ggUMrFt=.mUp92E3Vc*+-;@>(j5)^"PAuYe?gmHAE/3CFK"%Ag>eq^8X'Rd4.o3>9.op_Ii'jsJ,Jk\2Erl/AKJ/SMV?28Blm`dl=35\JNX\6\jd.EI&V_8akW"+r+Hbi+!eUU<\_[]S_9go.@CsbA3N*FcY!2gi*;*O\o!W)i-*Pd7JDqH26(>I![aHrtZ@nAWoo%g,pAT^")etOuU=W'*42T8m'/i?$27928<:BRr?P]>SQX+a6[-!+T9gQJJ./^\=SI;_M&Wnr8c.2UtKCq`+^MgE9kMC*tDiXh![cG,7=W!fMV3D_;8PLUubk"V"uq4V6\rVV9+A5R):YZ`DSSF`I9CY(_3Q"N>7e@c4T=TJWO,+4A2MLib2J4t7uOB,o1(&B3Q(=U]DfQB)KDRZJHe3^9^AO[EU7F=)u6gC'E$`/aCG3C9pG_?8;5Qb4Nj^fu64UU"tp[ZUc\chhf]oWC,X^b>71Gd!(ZYpa"^C`[E>N)i5O$pQ>c'Q'WYDM3HE'qugJO410$e/(\P`8eYmtKQ+3Kdd%Jq+8i4F?O"fJ0^4RKj)L-07.HR8e_5k*&%[I*:)`-55UnlL8FX*6'kHmI(5s7?mYGQ.9?Q*hoF*WWU]W5a>`O[X!Oj"n";EEU':QaKD[)fr8UE*Wk*P5NJL5;=C=1U0e'#bLU,]6I)(\MS*\LFLG8Ae9nr5Y'TNl*pV#MN'H4Fi+V"7h7rY8k*$rAYMSLRe.FLG;a0Z9h-1C'/!(l8Ts&J6eF5J!<@!I?:R>NpYiE;LnRgX`>#eD>9^d(3Q]UNkr%1tdCd-#0pc"ujHR]'e_#'WF8^aArpK@R_pRTg]2/jIG3dWR:QTbGPUrj69u1+KhsZ1M03W?!qr/.?GIZS4p8Dltn@sA0`/]n+LV1:M_UM*.H"!VI.m:rG]?M+fY[#)k\;n3!6YWUp[XE)(9P_DCf1GZ]MQePS7hR+uVVYBuj.#<+r9jLMp%7k1bA"_6PJ;9#+kh5nThCu[GqulTf0O@=EW)F4EU-H5`Yeoo>6(G@df7`k>)i~> +endstream +endobj +641 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 640 0 R +>> +endobj +642 0 obj +<< /Length 2352 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gat=-D/\/e&H88.@0Ar[!&5]rU-o/5YbZ9JFD]JRl%!5L$cSiMD6iBjV/A!R^[EH5KdYVq1AF4aB-)=\hE?7H\[X^\IEb9H&o2SJ5HmTf#BXLmLQ3dh5j;E8nSE,c[iG?dFLR(3j3a7ans?-?5oKq$Z0X:T'o0eZ^PXT2UjQU0S4BhXJu,/D"fX4Yc&YAENpbbSGCJj`j-`U^i\TrTc/do_amIp9f2ll'%DdmP(+a&"?@U,^CNgqG@mJ+(Vc]9ohk/'on4<1I<&HacBi?MWIu(EcQBnmD'p[6`C:kD8,sh5cH/+4`DLUE8^V\]&3]3V/g[-nF>GrY1g)j^Dd[7/%Q4a^[R4#1G)W)R_&3At26ESM:1.VJ#iM)(k&mo@(=n="W]0]q@d:C!CtJeIME%"]`E65@RR7^9pS3j=>J!5eV+A1"%9HYT?M!l>,O9!dr1BGiBaWE1,dGG'-<7pNFQQ_0&M?@`5l5-YqlE:!oZDTeq;HWjt_g7:\XFXMr1*[!n9%$"-F[mF-Bhs'Q/pkTV_Qt7$L@?`k_*/\6GicmB*TYc*?&0YdHfo&HHtcpU-\gH`DKM"mJCZPY%J>4Qsu3PtH,57BE(%%@qH@WKrMGEdmW'm6D4C[><#Fp)n65-H?o&+8*-j"*TWr>'4$#hZFOr!1_c)JQQ5q=d;C7k'7*F&YKa6q%UX7!2>/F9F?=2#N]%c4n);7pU#7q,J4]<=Aa=*]h=qfDoKpXSruA-i'K+BdKof[@Rseq"$l>K&'l1RVf(`S)HbV./d%8aY<&1rAs'39f.PEkSJl"I-(V!kW6[MGDXIKheCTZQdAgMYJ$/9n%CE/S'Gj5r-M;+Dc"`,F9p,2QQ&sl&Y@\]cNO4DHs!a_TYt-_neFU,ECZNYeT!jDP^^K-NHGJRp=6Z)4lAP9f9/d-'Vnb31D=o7(<U_u%t`LC.a`@'a#`+n;:8nA25;3a3XaD40"F%"AoM)&A\M4[<=R3RORF)9SRf*V01^;tY=f'(XulH6rGVnLo#%.*%C@G*mcA+:IX3fS\N>Cm8ofPU8/^!t,cemTCU'Veo>jf?*jMjCX2ll-R83fqNuHVXNt:Qqq-r(U*SuqYI\%aj>@&TJ20P[sG5H^inXnJF3l[(j4R3VuV`3'up<'3h1q2P?,T&^,'pBW*-5_ZhccKl,s!U?r]_b#%sEXT5(JAd83JQ4hTl;J[\HW`W`&17-c]nT27fW5icr3e#[;"%;iP:ZUhG%5fmFuT"alk#;h\iOX_+9X86uMB,>p?'RN\e^l0)[&X1Mqi]BB`l+T55O3Jd1#YCP!<>c\cM5c`5i:U5&u;fs`P5s1P]?Z<@hiBsda53N$^=b.cF\Y+qkJ=)HC9Dl,:?I]Rr3f[Dmc&jEtkG7G$`ZKFFGnISj:fEDI@*Y4D'iQq)LEVj3Y*U\V)$E](Nq,S@/>/!8h#G[INprl07<8QjclOjJ^$uLJnJ40T1L;"r][B,Ps):liGkfR53[p50aR0U($>1r#!WASX1BL[tcgYXr'fg[eAXJ)aKLr+Q7a7"@N0<7%@PM=imlh=JI7X*Z=OD%^dBu6-"Z#V7H:.Y;DGB[df2@JuAV1YlGV5"_!bhW0">-_G+3!)mbUR9c<\LJ^4=u0Oui/R2`NOF*?IC+Rc6U1!!]_f1Z3u,VmM_rQW_5c%_N4[mXgrMKp6;;cAe[lqQb0+FU90dB3n47B&n`CK9+)s95`W>LL1]7Q!'.T+~> +endstream +endobj +643 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 642 0 R +>> +endobj +644 0 obj +<< /Length 2048 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +GatU4D,8nW&H88.iJT1NkfCcUhXsOUgpLm#3#,%Qpi*6+[D\QQP%1Du6UB_PhtSe8lSnok65]T.Ap-<*j7fn:kTe(OG*-L_(-U,Kp97uB%lPC/Qt$cI*8?j_NGg2nak*$(p$B`>o?WWDG8HHon_KT2!tpuPE@%8d`l&"qFt#1PVrF;M_JETg)>9.Z*6U=Pk@r$+,,'Rg,RSY!I&0c;,3!lm06X7?H`$rdE[fD^Dm[9ISf^hb@K^-%l)a2)hKC;in9etSaKot+E;9(_+4mj`q;nM!k>Tt9eK(3)_p_jPhEMTcM)8mF$Z11)G*1U:$0+95TZq63%glX[$At%h"(,sj0s:="Zej$"M*-[#"4>KNIHocH88O"mAHjHRSh\/AE\)%&_RSo[mCf-Wf'ndQ&IR#U%Ws9jY/Pe"NMH`_\]85BL_63D@/0+08`6_=cJ6/Tc'RDY/rW:tZ4(7#0+@BJ%sG2%dLM`]cbu3@k2SFX7JS<:o-hi$(!fsMFhfV9q,5j3(A8/O'tIejR:(k?AI4oj_>C_pl_GMKF::k90W:@$)d/,"06!??i^hj($r.BDUggik"MBigF'K&cT(3WBjV*^HE%(."(+-:QPO^\;'NW9UcP5qLQRa/dR0_kP+m`U"=:CG%WNPkD8dkkNA)-(YH^(E5@_oNNNb"O!6DkPYApK3d=P)JIo'XD+HMqZ>@rV)\U=D428?n(YU(oZlSb#qgmTKb$*>O7:"H*h+:thXXSWZC'R-0`1'g,X+fV7Rh5uiLO+;I,M,0P+J-$UQ\QC:DA^Y_.L3_LDJ)769pnC^:T_aWO3$CTh?*]Amr(Z'q`Q:DiEeWcG."c`_o=VreLjA9+6*Ru62pH2`tnQC/(n<0u9V(mZbJK78DXie%N7944.PT<=S;aGsR8W,:)]LM946UW4k!atrm=C266/F)IT?_/s;#oO-D9Ok9c\iQG+>hl-mDF6H!3=TsbM<@H,*dP7Z\A]kio-G?s2`?.8Y0mS(H3Y%>;P4)8)V_P!Ya_anM-bl,;Qolm;#5?iI`>]!X\DC$fV4\f]iR@#A,d[Oe6f0H8k\=BHiO]N.&lXeIR9D%2o7O`@pU?d#h'OEtn*"XGDDXg]oJ#W0NlD,bD]MFE^7UG)&b9I8srE";Pj(`jhXM*tL#QQB[FUA$$Dn[=/=SD\hFXm"]Ftur'`We+5aE2/Qo`GdjT#+`VRcQZhAn,SEVsA.ZITu'a#cl/uT1bO&pKZRpgU0Si\HL3]'Y5DX7@(XS58536>C'N%bEo_RN%#M7>uQb`PEAbBB28Qk*]f4PEiJ@!qq8k2.WAjMV'1eh8dVfb`[RTScEtJZJ1JnDFgq^Ns>A9R@S(XOmG,Lp#ULsMq)BnMq/J,(Ke6it%A@^&&eVX1HWC;NF,mB)4#7.Be4iWkP`90Q=RdGb2PAD.p]L&dor$..At\73)[N8H:[*VI9t:T^"4ag!\bVYn3mjk=Vehi,Q:HGGo%NAApk.TbO:6D@>-0e)?O)*0G0~> +endstream +endobj +645 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 644 0 R +>> +endobj +646 0 obj +<< /Length 1697 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gb!;d;/bGR&:WeDjNp%dWAV+o-Sa%`[AE5-:YX/#)a/\N:Q=,lU`FSHjE`+9]L)n]oZ!sB8QJrZ^A61e8FlC4b'I`KC7P/OY6@&?@>G1B?i*l`#0SR1CR5@a13-Xi\cr8]n9*3%Do"*@A]81l_0_'REdW_9[8&V3'a9a>S@ID=\,Isg3Gej7+Tg"cB0#rGH;1`jUSB:i//#i\Bb?8RM&R7mWL(#$j!hq=&!gk-H-,NupK)_p=n8-d%IB=,,SiHU0J`m%l)9[e+?*k(QWLr9f*hg"fgr\Go]'aQnFo^Zm=q'mCE_2,_YTS%)CLj6k5"sl+5TS3U3eBi`fEi!(\E]rQmqJWN2XjsZ6"%m80jIA!"[lQ1TH:'@+p4%KBH5>V?\mc:SJhdXCVI)(+1iPW$Y'UUr=k2l"gJ,=F2g'@b&J^='c%"963_Iuejn/B3aY9QL5WR)MfGgT9o@q0f9_FnRRe1TbttX8gnJ$rRrEH=*@5*_>rH>O3?-Q>k2OA1n&<@:DnWbHh$1[UVd:$(R\9ciIr:rEi(/S/sjKGSA;Nt'394bd,R"q,Pue#*K1lb8H_H*=677^"Hr.Kc#ulKp&5.]O0c/2Q.lU/bT*hX&EQ0+hM\ifsTXj`K0W*K@ldU(i!>F;[@@$mB<.%Y9Vj*IPt*[u_hQr$]Ej!hAH(J;he:d/om:`/YV5$J'"PGo_t;uT`/o9@=FGS&l,.3Qtn4k(3;GB%@PE.@4]Il#u;[@#s5.E&g$\?7s%4lLF>?n1")'H:S?h\#084=Y\a"dcF[)NpQB&%a7ZYE);a.BitVT"L/CDg(CB&;-"gN.,)C7DG.d\;m4'0pG*bd^!XEf.VVJ/rBqQe&;:.or\gnXMAQ\72a=W4Mj)'WAR6 +endstream +endobj +647 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 646 0 R +>> +endobj +648 0 obj +<< /Length 1900 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gat=,gMYb*&:O:S#^K$mRMBsHhU9nj\nE^UofJUur)SQ*"Z%3!f)UWS9)QOH.9_aAPhZD"\/`cc"&Zq&-cQ=O`L\n^JjQZO?/t1Qa:S0"Y+/>;5iu]NB!t;^E`iYfW#.@2*]YHgFi,^-Mgp"Ge(WP+I*jRr`F,fcOMdKF/U\Uo^<%Q9OXd=p28B%`gIRq).4HhTHo1Xe[MA0'ZY>fV1l99"sU-!:/(N(bJD,$$./QF'/g6%%NCR8"Za'">&(Efo>D>R;U7\F4CcKq'c.T.SH&J8W+Z)&od;T]-rV+`#2Fr>dp!(aOC0A<+<3SWYa*DImN1W^FIbq;undrOAdAbqU^kTY5K0@I"_X=hq$dTEfl!'.4BHH,b:.8jJP'"U`B9LT^JY=S7O#pcPGP84S+;#OGOB&Q%F=h]s00Ml%;]iuN36@OGb1Ygl.cs[[:?c_!!0'BVKt=iU8s0;/8>aO;XKq>nYgk79X'l@TQ!]L+&cZ\7d4X,UXjEWCQ*Xg/4jkCEfpM:\F$2/,]5&]W/\XEOnhXN"kmd.hnEN+R;`khl)j$oT\Trgsbqd`\EILUpHH&;YE(l&U#bV$KsUkFIA8K^/F6^D^*f_<-b.k],,:sJI4DI,Wg=/`6G1W#l)c_9FtG,p[-OTT8`aUkdJehiA'!09-?:oQH9Z\F%_gO$JOi5%[PZo(%CoY7hasbqW_D%6c9_\M?<6,TZgp*OnoZ^IKWE!,[fmoUD.Q>T>gq>k<)ZB[!P_74mN9MF@%qVt:*e/"+f0Y9[eD(LSOB7A,<5."m)/DHrU8bP2d(5b)u6Yq=KhfEA(YC@)]JrZi>+UWSe"VbK.60lFQ/fqKiBP2-&.!\".6(hm3ek"j$je(RKZ:O&eU)C"u/lOQLG5Gu74ko:Ia3)Ws:uLmg]jn7++Kf.-aQbU,@9UC)E.A%u4sY5E?r6%:YkS$BWQJ.C4O`;L$GHa+d%G.YQ+a+oQ>?3JBri;ULZ(4E)5nQ-FJ.YI!QEfF7n,P:MD\HM.Wi(4CK/:d`kJFnJ(q9o&"-cX?9Dbf,&Ja^p,jYkP$HEtk21T_6g_f'5YNZu\t&qg7@$:(O:$1&pGL-*_RmP@O$pt:1T7t47M7aEk:"'0C]Ijoba%P#5"4V!g5-dMaJ*]>S?/881$.:^6'U[SoC0cs7&9h+MPfR&rQALV_H2DJlNKA3(W:IEc`sOPQ7HnpZZ%2fTcTdP<'Wlp+*&8"?U"E4ZS5!]T^4qqLkqMR.Y(Jjo4b7f.pss#")Ui:5JB%)J`dimKRncE;9U6#\<:Q&ZV%:21:A-q==/:XP$[dKkm<9guoE;'?!=4Dm=M+Is7CjQ7[^]mW&N,iC#!*5!/d`b3C:53*n"]dGqp0o2YA;._gg=j*KOs\YD]q&:o^H$W_%`jc[&#lpQE41IWVu58_OuR7i:PU;G)2[(40c1-XlI5]\C6%8f5Xd_Z[_;&c":n=faNRIK8HbG@G8/5oea7;^.sqq6'U*\9-"9ICqW">_Z1HI[gpTe$VSh?:`I=KkCB-361fNVVI^NF&Oj,Ll&lf=?V$$f-$f(q8<6CbD#E3grArIN0n!dV-A^>8i;1==s/U2jiW~> +endstream +endobj +649 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 648 0 R +>> +endobj +650 0 obj +<< /Length 1735 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gb!#\>BALf'Ro4HW(bsNB?[Y_>r'ls3Xnj48K>e/V\!LlBE>M-,*F'\3rSM1Oq??45m6qU*C!['XhHsmUU.TQFo#1V+p;=i2!n[defbf`5@P4^!HbQ$*9L@uL%X\H1_8#UX%,UmF1.B++S^pWd0rq:`[+j+KC"DYc4s.,S*TDc(,h_8FEK0VGt8r(s4!SKh(tG\SdfCbC+cn.2A'8(0#\'UE0YLeCufUq21c'5\1Q4.P\cf@J0J//t6TPA?N!.eqdAg)Oet36=:41a:H`q3tRW]#MVN45WP72e:b-[>gAU8rCq.-b_5'3bsrD6?aacgSTNO5HD3MZ8M$kQU\tMpr_s?=+$-V*dAoBnXLr4#*K+qR7`A-1L=lO-+*S0672IN$9*srehRN?7A7QH3&(Ht$Sk?56k^')I8Wcj"dPic]&.n(#@M?Hpe7A!C'b\b*YR6_=fKQ:Y[:q%#l[85Tmlh%YM>6gnGb[Q%*c,ukKb2A"Os1OH#`CW_EEo-E>i=Ycc1YO5Mlr7h@54705h&]Y6MJR(N8:iX1,^UWiu(&GI8G>T*o!pRu=0SC70ANJ^2G5V=s]UM(N;B2L4,R*M.<_\Mi@!rnHhpS'dRhQc$Z4jnn)_Shktc,G$derimrc\8M]aj,"31jYR6CmPO=;-52ACeG8f`CVeQUGD-4Hc6Z4F,0YI)/n'L-.@rNYR]HTg3&KV5jR,0A>nE"9BK9H!G^S"P%ZD*lT.oOci?>gB*"0?l>L'_.OJ6m24Yobd\CA]LJiQ#s0ZoLC1;f#M-6+rP-8=SMAhfc"0">SAMuK0U1(MOP,`%u:9N;DnI\Zn^91GH]ch'%9p/nP+VUq<^Q*/:W4C5r)(fHTXim$hlHlYVVu3]FZh_B"o+ZfD#j:j6bj,E?EFNdRX92UJW&>**pV+C7PCCp9qQdVMod@)=pCKake#J]h!F;1c:ph!B7k;UZWbUM@K*8'+Ip]s=FjqT:M2KE!>1E8@b:JKO9?eUH=uAL%^A`rHPFkbn/p_>)(UM@Om)&ks%ma06GZWBZ._^sl#fs$Yop)LJKjBVL +endstream +endobj +651 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 650 0 R +>> +endobj +652 0 obj +<< /Length 1217 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gb!#[>u03G'Re<2R%fi]UuaAhA$Njm@+;@q1fHl7FCmlsB+M86FAED[t?I/3/nUEWjAs!9jTptsGET8JB)gW,;MTF#bU[Pb5TDdOG:U-EQP=$V3O.k.g]"/67-k>d8#)'O[d/+0IQZD!'-%Zn%>31l[WZrD*aS(WHh__VW62\MA6djSZ+IeCF[k))=g#o]\ekOM)BuB"0egRsH*X>&\>XOUDt!o;k'dPJq>r92(]r_)LsLDb!]+,8BFli>&?*pjA'?7e__C<(ohm)dnW%>^W9Z%3eZm['9t`-\=ru4$^XS'lA'n5i/o"#s2Y=H?RmjpH50Y[U`1.%5LQErs+B:)pZ3"5d*#%(/$:P52e&afab*E/D;kou)8D)skmCaBrf\Xq-Z86+jI3r`on&n>L+b5P9bVYgYJ;lVHb"4:>!0F,(27=7-;"-Hpc^\hOR=du#)U/PeGX>%_38Dfi/28ZOE*@9Snda+dZY*12#HP(!(QRWi/LN!iRGjopEV=8EECEQX[~> +endstream +endobj +653 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 652 0 R +>> +endobj +654 0 obj +<< /Length 1747 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gatm<;01GN&:WeDpmBoC1IkD9[VVA"cEp1-Q0YhL$,)\:knkXsVoDJJOgNa4^Y]sa=>Dj$mY1tng+2Q>]DLuQPB#d=CI/HH&N7Y8%Q:IN`5(jcL-n8h@#C=])rlYBl06/po_2bcjo*AHK-TE_1&_iNR6aB;>Nl`W6""aA@I=hej*@"4)98!':S-G>C$8>:;+lKdQ@9Z$n&W'13"tPY8:OPZc]_&Br^(lX8aG9OoD5p\SYdUS:b3Sdr08q3J3;K-Z=B+N#Jm2;Yt<_e=,',`]St?C],"*S)&bD)Y/o=]@=D'/Brn%leCfqr[tUl4Oa;l+%lf7FlbT%pGgF_+#ECIXCi*A!'g6/T%`V4Z"r]1a#l6l3p4?\`VL6U(qXC$asIbB6.M_E(T+r%=6*L1MlWHO&95baK"K#q<:*U#YP0R6Ys2HpK7[XIp4?0oK1XbqEiu#&P*&6WoMHNCUI,"=2aNKnVbVN_+:Z\`](gi5MlGr@u=Z0@^=/p;l,O);Nb@5RcKEH!Z3EdDp&Fu["qT>*BnV>mUmQ!Z/9e;I]E%B^Kp;0(4!p9SQcN&c;gN3/.g=TMTA;H-3ef,p"$dJEL-g\1k4Ei?C`Q&h\K/aQe-$a.A,8Jj[E>e(J]hArVOT%?*E1(haN-F8g"RUo.&SjT%FZmY`j&e"I9h@aN&_NcNT!2F)agm@UI,/"tbU3QPGF?PBM[\Y(r.)NF,`uJJuY,abdS`&pZcn('Q9b6U1\lM+QrJT.2d6lA5A@9[)eaA>G=TcsRJq!FoZn0Fo0_MP,pnQ(dbI%mu-pK(2BYj2^@*CVB/PW96lf>7Ue$js2&)[UZ%TBj6gjL>`C5@ZQ=,p8*>eNi-EgcTO&U$r2'IFj[E6Y]IX.?R,Ko;,=h>P@MY\i<(nXI[Rb(O!kc.9.R3fm"ae.((o[h&t1DJ21Z!2c%i1e'"M@ApQRT(dI)63^]G];Lpm4ZFL@,@8s7upDN@KQQ(&U-0#JWoSsG;i5h$cV6_Y*5'SVU<*L!.[l+ZhK^A]AAZoF:V"O970P'l+NLC]VE4(9n1N^jk'?t=$Qd/'`W0hXd,t?0!quT@QY@jV:+YBlR9^&-,\A58EM*I(SKBNVg\hnOC^ZY=;'$P0Si(BD>Rp-@ +endstream +endobj +655 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 654 0 R +>> +endobj +656 0 obj +<< /Length 1312 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +GatU39on:'&A@Zc/*Y+g%"/h"6;MI$e\.U0ORi-G2N/[hTL@Q#>,42OO06Bk@#If!\E:?"o4&/PAF7_.H38>I(/ni1k6rB>O+\O6Z@koQfa7Z)uogO+mFpST2nrZJ^(D5JZQqTVpsDUg(4+kJ1\Nl9D1q;a+%0MQ6Ak7H\)_,L2[Ce*VpO(QHPRWg(.R>n)NGBh_Y:]'3rA4'h6]5@#kL:XW_RO&`%kgLe&up2RNZG*HL^DUgQa7KP[n`,8rAumlG-9]d.=bh:bsjIi%42FVk"&ZQ"N[p'7-lq=qIO$?t3COZ+fnK7`DYJ2HaD.^F.Rpkg8X*.Wfg/Y$mif7sWtiQp&Fc7isHiYZZB:GC0)@`QR]6\iSGFS8rAAU)\&jb05H/q*9i?(?6Mg^@5gRUPio_?'NrEn1%=cjp8'JQj^1H1LAd=Zm%?qI/3otca7_jVF+1l"N1M]/(?H>@eIuLs"VCqP6>SDkqgn^rE/~> +endstream +endobj +657 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 656 0 R +>> +endobj +658 0 obj +<< /Length 2125 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gau`T=`<%a&:W67@"fA8:he0[Ed7p=&>rB'(H%`(8tDVhN4$0]Lsi*9_["oppC=_ZpX!>/080Eoo9$@@a1!idHo2uc^S)F_aL:4i"5?uhY[t]o[P4reo^*4cNc30\XZqj.X13C_NCeX4nVQ^<7s?MFflb/SFHn/7nRB$ahH;MnSuO;'!:%nS)W+Ab%FIQFH(Ob`mJVGkst%.C?@C21X>`4!>]E_.9231elBp@66M;G<2@GIc%&>-LF5M_jRNaJCM3XJ;Do,iK2moES[U-">"s_'9sL1L2WU/E]($Nqn8G$Y;9.>Z5%+6]7J@dTDAES*tB[V:dF6[7E#h!N(jb(*>L-OjaJ/PSV;^C,-Qmr%/!$$@6r$YWF=gKNJnJDDb`mi?laEJE>+IJ$!rm*p:1l7(WpgO45W%$otV()&5%,9,T;bVV'[Rkd"/S2L]S`2=X,3#c"jk!ScONPUk)-&PMg.im+bE>!aI.5F;OW+RZqXs'\$[I"fa%?YXoZScgdNuamP^uCD%C!Q't@P;F^k\[RHNlKY-G+F;;jREJ!Q0VgiaR/Lq[a,BZlHgVkO.epP",M3%>aVlF/cG+0k#o)sU$\mIF6YP;=4\$@BFf]Fe=-Q(5Ef4*:6be(Q@e:D>e/.Vm$90&`9@ablAjM(48Pg40mj6iGRde(=l;LX6C!SEd7^0k;I*f3EFSD&^+MmHTe][8WXDkWVa4O-_:C:fn3*)I+\&VOW3PbG["UGi/J$?>]MUP:2g>c2_L:LEYD,Hs)n.19#<3iST9hh/BV_ClFj2#ZE1VrqLW`1.`t[`DDMe,QZML?(frdT5Umm,!Rn`'Ip$c$9E"5h&*,X.1pidb+,W.M5P);;Wl$t?=?&`Ic0JV4\[LpHl,!T24[oHN&$Dd;$]=j*G#N3>_*^sN%tm-IH#Lk-o:S``nS]$X,H6/pZ_$Z3h)\dY'rH^.j#7rXJrV0.%3p^n-:Aq6fm.s$>qI03e@`G1"nE6\\8NMlXl!sdA4D,r:D5i4Z$"QclimfrbuXgEa[Ut2LX^!VeO!;]_M;M2Vg=06)F]hC\VqL7#KVhR-MCI9![QBiuK*[KYa0j_%2X&e(7BUG_Cgmo:3_\oQ\uLDR:BE:bT+g=3H8,G=I[Lk7%^3SigFn$j9o+)1ZJ_DJh:R@8_IVVk0r0[EOpM>/!5+c038bmRpAhojqH=0Jb3mXUoVIeh:PC.P0Yc]`DM/MAGl-BUeG>\,-!/eS6]6=Jk$r[[-M>r'WBnelh0DY:_H@"'C:LJ-[K+/FP*gJFN9,L+u+NPWt@3Rass>G82u09/3KVFKo:p>*lQm;qHniPuTPYD.eXk2F5&[O1WACe+Xr](\=\7VC/RFZ\qEH%HW?-j(Z*G,'!GBpAODPs+*l)#r:#7g3;r\lRb(:K)ISaIRqRTQ]`qK\c.BhQVS^7C]@]>/;q;)\4`&?,)MB)KR/e11Ce$eFJ3[KN277^[[I?N>6c^Z8Yb#b0BP,eJOc73*g%uO#;caWL&~> +endstream +endobj +659 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 658 0 R +>> +endobj +660 0 obj +<< /Length 2012 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +GatU4gN)%,&:N/3Yb!tu;],X%J/=43)*:mIAs,3;e0^`dn\?D\EC,dC$!C1n_Eo;rH3':)@ZWa$uZBgiQ^lcj3@I"j'QQS%.E7d,.'F,S50n^/nf=&=$?Un?X*FD=CcR6n3OGZfB`^p7r_Kp\-sq5<20?G46d>Mbs+>LP'U4TnSWP#dGPfS#?!4P,I-q">OdJ$AgO`LkTZ/(l:*;>$kH7=adf7Mqf>@AJj+E.3]^&Dn+"$=I''*c]$eXSEa.1$L6]]sf1jsCeJ(?6PXt5=dT"]^g/RQ",GhPq*6Zc?I2$,J$RN!sf*;e"g'kM-eP.4N"1ssR6RJS?G8kf`3>VoYA5EYWds?&7SMoYe>$M5GVSfh=_Jor#Dr^ECB2Mk&m$]t1<_/,OmXGd<\pbe80pbKZ\pDe2blY*-@kN5O<*'5qQ\@'SaQTY+"BW0Kgt5q$lc+fnjJce.X-mYh%kP1dN?B%2fL&T-fnaH@;tFE^5UV`\9;VTp)#\L"]s(,-c[!3VU_?UNORm)bFaF7q"D25jn3"@l=Cu47d=g&?>Qb?Sfu[5RYPfrh.4shNgU/60nU.oQu=nddS[\3?HL+fW>!8(&JcQb4.Ze+M0rFJ<*dKBqK!9^XXd/l&+DE^iB6rhgC1Or>in;CCpkF>X./FiDa+bNh@<#MS)G+n*sdRP;q'-Bs7.2)H*]^T',h^b]$2#XVa#dPjV2THO&2&1SJc"cE[`eOg"8,3Lp>Qs;"O3\b-ZK[7R.RAr-IF?[J(4B5u:IJbBJg8GDF@%ie5$(ghj)Sgo#qas+o<]bN7qoMhmGF1S`$787bJidl/J"4i3-;Xrk>Qi\585c9u.`SYK3oO0*En70(`OJdgd)YhRJ7Q5&E!)6"s'7Qf`QQW[1io?Q4X>$>:!pQ.6EJ(,ka(J=Bpe<@+\X#*,t=Bg[@h-!3aPA$VILf/X/po?.>Pa)^4_kJgI/EERXUOSMr!K(=r8a5D6/2p\0uA2\ruHFZXQ-l^kH*Z+5hBX5;2SU/kkJX]^-PbiVQ2$r)_^k'3Y>p5FKK3H1K199+Z4SP>W6'b9#&,V>!)7Vp2-'(rluaurM)Mtglim.ZL,_lBYg'%i(:3#\@Lq=Z2PYY?auM]HQ3D!KfC/eXBdPLeAn][\IWHl_Z4MHH/6HqGF.G=o[+qZdp[UpO=N&G;1MJJEYhn8r#j*gnC<`^95RugHd)p;K*1"E-@Ph'%.J+8AUAb`WKUX_#q*d5KShUD=STDWXQSncclR@XMJRfG"Gp@KGE$H?B~> +endstream +endobj +661 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 660 0 R +>> +endobj +662 0 obj +<< /Length 965 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gat%!gJ6c_&:O"K=?Nu%FaQuD\s5M^,UC_h7,!oVLX,aa,XQjJV%5blPra2*hQBfPV-2:>U%E'>E&9bDr;+t>SG'iJ4FXofB@dG8bNesjUl(c*2+#8CLQ`lc>b+VcE,P[>B-dFq:?1D>hr=:kV^LR0nVq8B?5l%/=aem-`:;&j3qcWbqXTH_1g(H(Dmj^+gn-?:^n'+HAn\T6%5s+en2\o1mW^.!S-WrAq\SJLedIG"G&+p*M,s-Bh$FbQ*sKFbWLB]ncSNZ7RK[CpX<-jll[UThF?8@sXN[Xc(UeauV<5/Y1W9HerqX`ES@>[d_-QDmobVLI7b[T\I(gT7dOZB;VQ[N(lQ<9FrjGU$r_UHlY%LJG4$_?`jBZ$9Y-mhiB/\E'0=.h&_hjR]16,=J5MVL@YWhk#OWl45#fi=7Pj_54O:]b]G;>0\#*&oDA-"MEk5`$9@&&I6,bl~> +endstream +endobj +663 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 662 0 R +/Annots 664 0 R +>> +endobj +664 0 obj +[ +665 0 R +666 0 R +] +endobj +665 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 118.0 414.161 187.355 403.161 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A << /URI (http://www.w3.org/TR/xpath) +/S /URI >> +/H /I +>> +endobj +666 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 118.0 396.561 183.692 385.561 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A << /URI (http://www.zvon.org/xxl/XPathTutorial/General/examples.html) +/S /URI >> +/H /I +>> +endobj +667 0 obj +<< /Length 1967 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gau0D95iTD&AIV:&.B7lJ2JS:/`2^<%9t_=l>2SM>njZabmMij$:V)Ks1T_?'H`KRk>:rZo8/tRB>,PfG.2bq9BZNko"Ek.j*P,lf^n&4HYEI^Os_YP12hC/rjpl>de*F&*=8q'k*:-*U`$8Eg^d+6,5j%\Df>A#BT,*5KgqmJ#QCYSNDU[m6J[t1*L2:A7QA:gi*CeJbKmO4=N)BL%u_:23mleQ^CR^72V9d/;;Zq?e4-KNNaqC&EV(9n2qK[e`M2`>GMBe_o0_W<-jb+)OJ\9,F&J>!#cj242(=2;ToZL!VfLFO)rB;iOWIa#LhuS#h<(Z,%bQkC$lVttR&8ID]6]9CRCd$AHo"Ct5Uo9Ja69L;#=fLC!ZnAQ[K,%R"1-T-.[U7bfHTLSpbqf.#0U$Yi!_HEX^pX4/'$p;[>79Zi[h'F].GNRUOl?c/14?,U!WI37^5^u4l2-`\<_L!ml'&^50>+/;jbMgf7sgTj.MBa%)lO0%I5MQK/pjkUYbt3O3QF!Nos`/ns/@Q.8"YA_ngn.EE7o\fme)?iU_2ijbn3S:N7r_"0LmI\acoml43@b"c9AZJmUl^:c9Zqin:2gEf:Vq&R1=CI8qYP.*<)8Eu;*?#5sPF_4\Vr332HfNKPq(UiLYJK"T-SS:HgmkO!2b`M+sG#S>)5j\P(2El$Q^NJU'&"Xc'G)UaG7HQBs:Bn/iRVUD-k2+Va%6,SD6't#U`D?:2\fAC1ThqIkCTdgO1AE;N&-M";O@Z*!uVAdO>R,]*d.HbSRQ"+Q9Z/2`c;Q4F`D88Wg>Wkeq%.aQU-ME[pRW*#EB_ChnagF+:4*hcu76k9@aa]i!,2ek;8cKkFZ]kQK%BP";V/cB"KGJ/[o$^^>q7R@dQQeDU-rnc-!4&jdTW3)<+O52j@e-C`lVoBNO%4JOL5siNkHXnkG1:dj9XFt^X5:j,!uiTFB(BV&niC._gT9:'_DFZ;ar.D&4%#,*'+\]]V]'74R3NYKN+),e%;6lBG1YXD*&0bAkTj_BEHm(QD-.@RQE.^*bna;c1d]OXE%*8C5MC?fomG<9m7N,aneu-hR.G'bYIp1e\-:5XirX^K>Z'(p;!K_V"RmCumX.q!-lXtF+(`bp6Pr*f5tF46%HB5u%$R(t*+,=UIb5)g(Mim]^&NKG_a?VK,3t('bB^!5]Lf;-29McXRpmtc6eA^S=SZ,j"V,(O6du'PJg&4$qcW1JtoLf0JuF!Oc#oM6]@fU2XV'f9(,11m"*'*d,Tc\DN"je3F+qrUjhV77HU"rn#+:RIa12$RAAJf5(k\e.#p]>.F#[8E!#Jl6MmYMhp_bA7;lO+flI/`s(`Wj>r<@%mHTj.HhdE:-^I7E0Dmd*J>9MX6AK(@M_nA'!3H1Q#mmpj;]jfQ(N&*aiqu?9J^g_Q,nUL#UG4CU+6>lRO*D)n5WOqE>1:7G'6p2~> +endstream +endobj +668 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 667 0 R +>> +endobj +669 0 obj +<< /Length 2325 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gatm=95iiK&AI=/#[JRB!!slJU)r&VZ-)=[hl7`.M70fl,Y+Tg9n.R]0CrVAhr6b@q8fM`JJF`:U"EJ%pPFR!;^kpI)i^.cdn_$2_6CVW\;j,Yr4t_AkBGPFT%T-nqpeG>CTe^0:I`(kTXXrOfpuT?#;J=ZuJoF/[&dDY.i^u?\4F$WdZJHR)`mZTC[-)`?)BJ^RYM9=_5]I6+RdC@]W<$4O8nPldM(+?"mYrg]6:f5k?u2]?]HJ,DXq2!!`W`Mc9k;ZFF/E+#3,p%+[anW3!4V7qW5^d9soC?+_bbFW;Sf6ocLd9M[$-4sq;!<8DY-*t5c(**9_YC:daJ\K7+L'T_:T(-b'J@%'\r)WfooKjRXLRecV]heGMNPfOa:EJqr7/a5T!Q"cOX$NTi11UD+qmNR@s&e*$+4("3BG26"q$698<<4I+>0tUSL+;LU2YKJF;5J0OH&1K[KXQEVY&t0Lo:[#q&O^rp%a*mhjYHF#SYa1cD6XV3]Ac+a+KOSVmINf*t=a9c0.RY//-mG[:Lb[>t+Td^sSFD!Z3GL>!R)HKTNMD(K+=7%fa/@EYQZNY8][abTT/jaDg9,8>_t:FoXU"4`(C8l(f2YFF0&c*>3jQ;S#U3@*L3X^iAC?+/8'/j)9iI`^=SL.;#=E]lCG"EX8c-9Ds?#")+oE$+R=s(-LVq',ST(l^@dc+SW4G^WA)1E@*nW=01iUX$-?_$])0dBC\5kP^-SQL:^"f]uF%f(];VaYFG3rX>ikn;IX_^WZrJ.?<^D.&L#Yg.PO.feN!MH,ZR)i82Qm?:-MA2GpisR4Z#BmdKA:2M5+cRE(+/T..3oSbMar-PW^B/liU?HcZ<-p2kiGIoSC"f:5bdHEVeYVk%6p_AY"YignC,M6,aj-Ji=>epqGrX%I:Y[HEtQT92caI%R]l!SVbbKTeT!>pB>TPs#se#NRM?CY:')hlV-q^LZZ*"fG=4kBthY,Vn$eI*4Y3G)Flo@)kbf/U6-GgK7ru'lVd?s'O:1Edh5EOS#aO^ru0LVTT@eEFKJt"=;'d+r`=&s;E)d_@&g`9EFPSJTc9B[d%gB>Ze!k#^&"_dd](CIH#lT1Nu.MEe[:!SOC:#\+9k:hrh[Et042]rD!`V[>^Rq6I7qI:,<4F>6eUk'UCt;j\@]6plZr)f('>?]F/f*V@&f7M=kVkNW,j.[JcMhe3(pc=p!%Fn8A@)@5@Pd@D>"j'<9TIJp?-NkgNmN1N6u4U$gA#UIrj>1-ap\$3!Nqf8%DUCcD;muBZ,G(HBr\>Cl&?h8' +endstream +endobj +670 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 669 0 R +/Annots 671 0 R +>> +endobj +671 0 obj +[ +672 0 R +673 0 R +] +endobj +672 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 717.149 717.25 729.37 706.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A << /URI (http://www.w3.org/TR/REC-CSS2/syndata.html) +/S /URI >> +/H /I +>> +endobj +673 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 120.0 701.85 325.051 690.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A << /URI (http://www.w3.org/TR/REC-CSS2/syndata.html) +/S /URI >> +/H /I +>> +endobj +674 0 obj +<< /Length 1508 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gau0D95iiK&AJ$CkdUX+Xsf.$PZr@$!aBKh7pIUL]04LR*>=\aQ_NK8^V7''8jgV,gd;Yrn9c3>B"j\l:`l!]pHN(+i!b=UEkMa2VZdPsrJ(InBoIcY+uBapgYghuWnDGrYa/W"Ig4)goi)Q3ChDC(3!qO)AdJf#C8NRAU:gnO,'"NG\*iNJM5Hl+U8acq<'Z4='c>d]aU6!5:f,F/)k>&;>q>1fTY1A9740CbeHC8Q9,4PfBJ^6E`plZiA13HBYA?iemuJke=mYr/V'mJnM-Z`IW'3l%S58"dbY]f&D+IfKkLjIZ%jC/XZi\$r`9_jLB;D_Uk&hiF.i7feF/!qhZ[Wd:fW,Dl)HbRH*8uus!Hj-4pa=R[t\t"F*"*uif@#3E';aNb!0\d@l;9&cYj[:4q;t0A;F;8(TLu1M^cd5p:qI`nc4X%m'q5t2<_58O4S0Nl#J*>T^$[/cV(Vp6jl'a[8J/dRN41d>180B`mR*oNhX@kZWLR]1Rocje6OfCC>'a4d9%6)p-]:RpU.'&17&N:^Y;Peb$f^^aiI`jXbG*_h8YUa)oat>jrd'pO:"qLDs'&Qip);Fb7IFIhHnk>[YhQKPk/90?NH(c;@8r&cC`eM!$bKs"bV'O),3KB[>0^9_,n#3V+m5Y=L$6mSCP$Id3T\"`,(-6FL9@BJ@5$c#XsrQZj<.>PCgC,TO[?hXtlc"30KSNZG.Dh(u8!8uPn5a(_QsMUsfJ\b8[Vh6p_ph6(1>q(m6fbXieqK\7d%S,S3D.@FWT+Si0L`=T'p3eZ]FB;SpnZG3KM05$!>YF'^smZc8&Eq_7FnOUC6"J]YC5Fktl4U"rY]J;m4:_tgE#th/6n1S?u&]%>9U>0OKj!`:^(c]m_([?SU)]EmnNMGfSqrH=]\@"T`+i,j2XrfW2hp#:me*cgB(hFTnfeNg=^/VKVJ+eGICWkW'("Jq(m!RX+GutaTrfE$OhkKJ!"6^Q]9AXmT;4DN5/ja]i>!;29n^E4kTG_'n=6G]B/&@re$%&&W[GO.RR*%ld-WBFg3QBr-:[39a:@~> +endstream +endobj +675 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 674 0 R +>> +endobj +676 0 obj +<< /Length 2113 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gatm<95iTD&AJ$CW.tFt@5FY7b,It$+>0/u:"DR\D@a+m[FArj/L>]0rq_XC9'"'Nej+"XG!8+P_0P>5k3UV'8fa?3f@fN9>j)*F3\L>/-h[Ou?&sYYjD=P8n)oiU.[KUKomY4UgKZ^f31HQ!K$^2jSKH0UcNPF`!obQ33kQn63-"%M+\CLS3p4+MA8PHW"DS]s-YHS5J3(k7.CmMZL3JGaLjF9qZqhE#OA20Gi:_Or/:FBt!'lo\c!L>Kk@6QCG9c:@&;#HT?EKSELj]m?pr;\)P3?#V`JS8%.IMQ%"r=N]L_:>[[l+IL(bG0>8_&5j[H4+!E)qmOB3e_*@,.-__>"M&$rP?]*m:QMJ>c[?hp'-n+!bbCSo67f>.GA"Qhs[bQKQHfLHb5trN4]FifNqt+*j&,(=Lbk"pT?(>!$F^^M%j<$XoDB/R^s"o/C%6?!h*gpQV6boW^UN#;.[]mr+W8=]L@tPL2iLeuXT)h3O#^a!;O^2Xh!!GdO(D<[3=aY9h6q1`!8,-a'K/B]`<([^F/KS"oifh8sYS4A!SsP,j_em4%%ADJ!2D?[Kf.8N^bKp@)>@'D`a8kE`Y^Zu1sP,b-XH?p$CeL4QK`qm,IEm#[,6Wmd(2<(8Y8OH^.[AJK5FjP/BE$W1tI]i-`FehZ?i]WXMhXSS7:u/F@Uc;P-q\s\IS08aPoJ_F%!L#M.Ti4rD^k8-'W"3YUSk?aq6I2N01il*5ED95J(R)B\I$aM..*Y)E]]Vp:5PVDDrU_f"jKMg5-9S.`kimKWmP`"TnPuV:&V/n4isNbd#+a9"YM&-1O%':L["s7dM%Un2S,3k9;'1kMM(G0Vr^AY?],Y.OFJebkQB0CIpc9&pa(PE\#:rjhuqQVIO&KpD3o\m'V6*Q+']_(qu6,*/II)oGQC!*Q%,oiSd17&il:c;A;re%8)>@GZun#Y;W'i4JY5M7ZDq%_!H6P$+p_dOZSMu2^VSe7qp9uk-(%hdMe,EL'.Ar+E[6o%'((6;&iHJf65-KT%h$a4fL1VIj,eTT0f$/^MiZC]9FjAR&8mU`V<#7Eo>)JH`s6LY>;)`6IW*n8@L?teSW/_L"j>PB@]8_m@i-jAtpI"QJ6H7&c*9dd+b.cFjD;e+"I89/SQOGHF=Ngd(\r(iNdk@'@f\S%UBkTL"QngR>>SB6&jCn#6W;%4.4?NSC*>#R5H'q[/+fE]p42#[P*kliQcP_:^gRdsfcQ:dtQ9kS-m@f);\JbPY?^P>VNlB?PP&j"5IBpq$>:QFM]md/Q3\!uJsdAI-0-9)g1ZMgcJ^[eIiAIF'c_SHU),OcM`j5UAb%=M][lTZ.9L_L!qB!S@:$-Qi4P9,M +endstream +endobj +677 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 676 0 R +>> +endobj +678 0 obj +<< /Length 301 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +GarVIZ#7H%&Dd/>)ri(U0\Gn6.30mLBZntME,>kO0r,YalJECJC12p#m_*u&HZsgn*ZbJ]M?uh5#b2G0OraeL80V9diO3Vi:@P]S`m,<8R92Ni]so4hmkPR+jKGSFHlF$TI-Cl9HjbDGkgN%c;)F!rXE;[bG@P&l:T!@#Ft?q4cF%e]-/o7q5X(lo6smDD>IL]S$)YM-(3eRE#SmscB_78Wo)AusVO.[]Zm).$kf6a^/A]>u$>qKb9JkGo7;3L$/!iHnDX#Jk@l,1W.E*p)pG:<0jTW]c00n"J8\\c>B`e~> +endstream +endobj +679 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 678 0 R +>> +endobj +680 0 obj +<< /Length 2763 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gat%%h/D=3&qA57+Y<%)!>;O`l>uie2G)9u[_:Gjm;acqRC7g7-(Q;/c%"WE8;\Bj;6C1JiVAm/c4&m"rc*#Lq1/]H9Yt2D]*O&f"V!fnUHoXrQ51pkdQH/%KE#35Q=JH'_c?3`@.R1P9*.^#TAcJ@.%.Ao,V2kfpUiUn"ZK:&^U`FS(7'CbFkc6f$]M4dgc!"mG4tO1H?$[Pp[+q!^1ad1-m1K?OsD;/P2'&)J*KMAbDf+QBjN%tq2(^J\U\7U6s5`XQXAM7UF8od2815]'%N.L9FgGeN/+Fd'*S?`+S*Sm]P5Im0e@8(.2X?CM1RPo#r?!U3@R?'sUXg_$U\R"o31fE?l=phuik"JtJ3./jMa92[2+At6Fm,h+C#Gksrjp4=9<)O5br4:l6Unl+)6eZrNYp/%\%lcZf,,D$GAiJnm6iru?!Vf(op@Wr@$1#q?!3f.g,UM/b!kmS%R&kZTI@T[Q&&1j!#^)Mm6$ppSqG3H=`W.;1X#RamYgqmlO82IEOEaGGFA'%UoF6R-gIB(<B0ot4?B55=ZQjoR)f[$c.X=51-0a^CskEP6N`G2cVW6X+I@TS(Gi.XICc3t/62Su!?F*mI\Yp<"6#WY(2iJ]n.bJ]pDs(U85(0\E]c_'0=5+&?[u!HFQiLbd13QUL"UBr']NH*C.JT%J>)87:1$HcJl=5D;k[\E)@"Ik!(YbQK[-]7dOjUoX@S8mAG>oj=A@LEso!<^_=uAE!js`\+g;SJh=qEH@,T<,Z\o*olmPbs^]*Lt?;jmmeq:!Y+FE4Pj.TR%a3PFG.ckJqg)Y>4u^A.HAO..Si+f?tA$0ol>5OL[lnsaNr_F_phpKrF)h#DA@GPB@6T73\,o^kObR`k`m^G,T+-bH$clZRd6*V^bk:g9Q*k_g"m+=@p*8&BVVM\1%77A>Ft?[\c&2bU$'Ur`23QH%6pc52RW4O2Ik-q0E]'KZ7=Ol_D=daVcIhlub+YO/=G@`V6Z(9s'q-aX83WkE)YhQ%jfbe!,JL)+1(:fj+dk.M^DT2/M.g5`jXl&nGZ9j^3smI*-jae"3ftE2'+IB!`;;$&&LZ1?ZbH1',G!hA#\]mMt&*p"SIZ*&PcRW)7g[eNCUFk@K]]:dKm:sN9ggb?c9:"/^^]I9FG'5[hD^"_^3!6f7>)^O]GV0k=7dkELh@_tFp_!uV?O'.)6RHfT-jU9u3u3f2)u]ODb18)lK;7pe/Jlu"9tD!/6RU$6f0:gqnF"H$(oi#E:'To6XFB8Lc>&PET<8si;Z;hhFGnH)'"U7(GiBi,$TeXHSKGhLIV,kSVb-8OCS;N?d#'T5jnUU[6:Q">@KOdq?Htd"k.&i"J<4]-rh:1W1?(E5dJU8Tr>[j+c6[s@6LBKe9tqQiGFZ^a=ZeXc$;iZ.pP/d6VY_UA$#7t`7A%T4/;E:&L1&)(7395M/=Z4$C)8Kq1"X)p<[_e-U@4MOm+B7::smI,E3"gi2JQUZ4'Eek +endstream +endobj +681 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 680 0 R +>> +endobj +682 0 obj +<< /Length 2025 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +GatU4HZ.Xs&HCX[6HB?f!E)C78d^:RC#a:UON.t9_m!s2@ahb$7s+E;RW#qS77j:+gW>0oL$sD54Po+B7t6nb:+j&31%N$"I,oX4&b^VILV64Y0CU2#d(l,5H%-l5FQC-UK_t8XiTE34P]DFE*"q_EbiR(14=A+rjfIJnIZfE/>kUH1^QpW.%ZZU_^V%[li)8(9e@7jI+%;^1*lY1FH>]#CL(a.],T(]iSs.^IF^Q,?pF`LKp)#Pj,\^UV\TD/VFmm>*uoYraQqbKg`ijD7j4/j'5WA0R9%!986"!pS+FiBLcfUc0#=iDg^(!1Fs36+lV/;ehg5>+i:5EoBl>@k5+@\r8j:8g%kF:DF_\`B.3-4UOH<9jbjB]if2%SHi16Wao'YEN[LU*,H)H6E<&G`I/5ZT+lra!*[;(W^DB]lS9p[r*_*o(5"tUf+r&^ZR3S+b4::C!It4I'?Us3_Fe;T4FG,Kfa"X@H0cnKniqZcS3oNF`GSoAWb3\NHPZ>I-GpP&Lq%GL6Z7!Y(Q=c_YOac=3bW'=&]tc#cBf#0b+3ujJ9m0.CLUY.M9hk3H:kbLbaD%bGD(9;?\oJe$5>8P?j2+^$h>4;i'\^3kXJ49RB#MZJCR56H#2`$.YjDXkm6#/#jUZd=?ZolBEj=cH"6uh?HY6n-Pp5b'/9b82ir)5o4aMl.h>C!F^G,)JT+-P9V5?sKL/6.aH,9=p%7MdMr^@$*DYs93"&/f8%E.nCKk!"d\>:I+g$E>bQg"P5n<'EoaY7SY&>m-\rI6\PZ;KaZ^du\Z0H(+=s2`3_@6Kmd-(nnYq(1"i@AV"joArX>3L<1.f95NrS3ogBJ`@eNgrJ-Hc^cHJ?RQ)qigkcg4akU#`.`!b^kiiF.B5KSn3/0_!T^4,.1EX70_7=Z4\B!\:J\9R-+%4E:0g`!\=orMdZ0/AeFoFbkBMp(CI^3B)k:=>-":)t\t5i,2)5Y,L@dupr(AfWamo-C_N`j<124)1A.eL^0.#ijl4Mtd@"bIh?E&g@Fs]GE_M#`gadhmdHU#R7c=HPpIWf(*%t58h!"[cUo=M?15uE'feb>AWPn3K!\W\m"gF`mOgFd>jJXORA[^.3acLgJAL"K>>OdgJJOr^]A]2CdZ1blcJqFg%kHGNJ0>9p\+rOYkl-2oDKaAFoWX"'V9sF=W7ORi?52\.U9+9iQ(W"4@V#t#^[:meI!IYV++n!;+93pQI@@B`%'nK5GehiLpfpQFq#d>V]LV1`2cSO1[BIXYN7Tlk+881p?Ql3(d(XRob=&I$@@Tc%W7/t_ALAbm\e)u21ri6=]3%Doe.SDMsfA)3L?.-VcGW,j0YmAFMJ@%Wo($K\1q!pT0FiTocS,l#]OG@?XJm7lM~> +endstream +endobj +683 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 682 0 R +>> +endobj +684 0 obj +<< /Length 2492 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gb!#]>E@OI&q8_F+`&3g!+&\=WS>-5aL9=o>-s-=o5K"Pck:2rPslclb%C\P)+g(6Tk-Q5)`@P8!VY)+A/I/r8k&O/uZQFB3B9mLPJ=l7Pqd4&^k&fO3+pLhliATL\O]Xol_-,49j_@VFRnuc^ZTN"VjW]jQ=n[qptXrAD%KM@>2%noI6pPnO"(X5`c')N9,o%#R/i,gf]Pbcd?n+pTl7S-9`)L3u/jj8-#l9Z1%D'c&l3HC\PJa&TOhu;9-FhZ"#KA&?h"'=&WkBV%W]i(h+tS8.m7X4NE]fDYN_l(.6p*iK72PnD[9qV.pt+b(ehel[A#b^uq(@R/9Y823"QhlH*JRjK[^TfZU9+%=[fV0CujZPuWO#h`K@@40d*DP7r^B$aYM^!W6>,`LsWSkR_SHX^,H;ZY4u.)gSs15^m?f/bXrcfu=.n8.)H$WOs0TJK":T5S9-l\;pRO#W7]E4MrO\SmlZ>ik5@OrE52!g`$6dJT[bOmiPQuVVcs%``)3.,Ao9Om,FLX5m;K^*lur+_=]j>-'-Kmp)+@rl[qJ?A06_O*;6=H"_1=1FLqk8+u)b-41=IkB`i&G=L(`\o%(crOOnLl4nASAr2>'VbD@fh"@br\OXOK,>C9K#.-:H#%(A>)[gdM+WiLCJ"E0#>j>m"\VM/'qoue"p5khBQs?Q#>tPcsa&UO%NO#?LJ*_$O4ueP%[<^HXZ^+5Q(*BiPYN$+!+b'If+P%',$7h1#N:CLmYc=8"7ha9rt,?:'1LjgGlB2n-uE8L_d@n>eLkM=fuuf';U1.Y]*rA$<5GK&TJ5j"(X;6V)hoZgDo27k:4Fn,3r\[H$uWFQ9-\6k7DMo0;mP=R47X?&sX1ZqmS=]\'u[*aoZNBkFg[0U_Qm9JTZr"/$FG^ikWDd'_%[[0$UN/!BSFgcO8hmZVM*jFX(<]479r(Z86)B+BuHF2_5#6#!Y:8G"s$0A6[!b_1rts8/+lI:2'5ujr7R"UK_VcB,\G`f'!DX'aPXT;V`0.gGnR(=8d[!^)SA&@3oNDFpTkD=\N8dEM&3`n`+69.7_-6KZ&j76['A>Yh+l:"NPr2WPL2Y`^*7NV:kP&$4.)g%j79!9N&8R>g#oR\%ZX:H`iahH2nciBk&/=$Y7V$DG1$(rn)rH?JIj*f:>0.-X+LP,WncTFd`@GZM&`H^hlcWBLDbA8?(g^-+D>Ng0[Bt^DtiFeeq]<:-'TD3eMKMp9Iqi"/b*;U[^@XZ@;X;s&qNiPiQrWr.-ZpVlaI'JmBIAJd,X61ptr/B")'!EJC.Up`-BP(M;b2cOPmBrTupPgAkC5bR#$LKaqV)mr5>(fD^o:H7O4\=r`Id^YIq,&L/Dces*M!cNMpp!+o%2O_^3Z]))3?MXQY:Ff`pa9GQc:-A3^bG8cK#;:J>:~> +endstream +endobj +685 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 684 0 R +>> +endobj +686 0 obj +<< /Length 2292 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +GatU4=`<(R&:XAW=JU5HJMj5"0G"qA]K(k>p9mN=D$sP,mLkXMKq`sfm=-c8;;tD&YFQ@sJt3M:jDal'c^"g^?MZJ47b2Cd5-SXg"++Y%5C7!(Q=P_NN']In/b@ZaLU>\Rc&NgZq/FF+qDZti;nAYhPAAHa9j.=j@/>)+Nb3dbQG5stK#&8PO!&V-h>;2\#g*K+s,+.o4;i89]/lYd"dX(AH-_B.PZGFL"hc6TH=So*OPd6Kgu>uj88i.G4SX)-U"H^=:o:App$0?$UIN`DOZW.S:](CQk!P#BCM_jK*#XnW9I.dW0+3,(aMj&`-A=dTl/Z,l>\gRp&HX^6/5-[CiX2CQ*RX]R)R-(dN8*[h3=^A.iR_L3\(QK6)+S>O_(M$m@Zk@g=s6h8">;B?q.2JT?hGB4HJoX+`/7'nlCGNpSfn.+@UmeM0D8c(&(AB@a;dP%H=^k-`C(>V+#t"JNgrV3$AVRch*rm:Fe:\H[!Z'd$6+O>0KOk*?7)jfJ1([9qDd=RW3u*)'A[oRLXbXUY(fGNn_X@.[6naZ/i(\@GJ-!(%Y;\#-KW@E$7nMGHY^a[Ut_S9sU_h/&G"eGI;0HVrCRA70(rfbWG/bHgFC2>qrJ^iMkR7o>)98H4Ie?;R8Vh8)PTsEQKt/d<$5!O*h7MpS68_Mrj78_"++W[ASAUW"[A@R**ZXBBQ5'o'2*,$&(aEr=0e]\b6,S2u-W^>b8T9Kof$qpha69+HE@-n"I"h(!%^5\&K\75>6r\i=Nr1dm#P1`4)joC]H5d@NbYbZe]e_qm_(q6q_YA+BOQ+#"&;&qBb#N7JUDU+k+`c28Q,;u::&\VNU^1t-fTRhL3en.;s.<)),dA-Z%A":6^iV;=9;Vjjjdsc"R,,$/N%*5nBIl[[=[#qHSVml@";D1!E@P`5fKt,%#_r"+D/jq_sT!3!cu8OVB-d"q<_:]e*BMQOZeNEmDtU$qu$W3.qK,lit8/rCh==,C:50!ZXQWf294i7Z@7Y%hC78i1e:3,;_keLQaj'h^9Gb\Eb&A)nqi8%9TDO`3D2nC1&bE>IX_gKmcO3f"MfEfUhgQY-p(]*:+P:C*:6#6M:W]uQ6kN^3FBPu^LO6:;U)2&*N!V4NZ[J:Q(r$a4HY0Cn.$9-J?hk8!j?kd&#()#4+MUWiQG*Ql5^.9Xm&'I`QaP~> +endstream +endobj +687 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 686 0 R +>> +endobj +688 0 obj +<< /Length 2375 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gat=-=`<%S&:Vs/&Gjfh86A_*V7n78\!oh7[#Va'[YoaBBNqDZW=fq)s*dHc3NOgE7:*i,S:e^>l-%&fled)J;IWjgeVS.F:T.jB+18%W"3Bhb0UGq#8*f']`C@MGc5j[qE4X3@1uBY5>!^=o>:&UHj>+h5"m8=\Xq\ZENDEOj7:&Ru^NjDhB.a*"'o2qd*/"o\#5OMU>@.=FNB3-sda6dqlSt$5Cn5*G,kQR/m,TjU\-&:CKH,Di/*A6dJ)I0)%SH:TAPr1-8c&Eg4Oe/.F,,:)ONb;pAZnX)OtbNJ296BjiC6@DQ*q6U4D8@;Z>fW!EoeX>P@VXP+CIc$/*YWfq=:cnL%?D'tn(35@..bHONNX<5kXEW)UE]p,qb'd$OK$1g2s@kQh*8<.OJ`cUnr>LR"Ii#=8*!$*d"Kc^FP,]'0Ck?1r^u7KM4c7@G%=+oWU'u.\/*tkOR&,0Lut`Eoc+4L.WhqgT=f-pO%@%p*^#?.`4@KFTuSk/016FX+`U1>B1>AT9aN"6QPOtZ3O3&XgWIf?@P*_a>U.>.6)JX"MPX"ibpJB0_4ps*e:V)(o+=qntH&VHeRVKChJk!A4:m`#,p$Q`jS%'IiqgR3Hncefo/u#fL6eU"/*"E*?MF>??\N92m9MX3`3)b'`__Jc-rL>5`X?.'5Mp@fkE'-ocg*>$feSW-<'TL@/dZsP<2#4L2S/LU3GmbD%d*6dcBCNb,@@p[`*Dl4oO`lsG8Oom%\8Dj:QhKE-N1oe9o8h+!pI_1L=^Z'Kk5t'lKhTUdL%284_^c!^Go?e;-ZCjU-\YBgpdFj)ptn'Ta0E*t/?Bb*Ur*W.>pA=(7)=VJW:@3LQSnA2@p(rph=odq""=KibCBdT*bdXOrt#b3On>LDY&We8'lMO0I!hm=U/cIiKYMk\l_O$,%RXl_cg%WL%PU=!S`(M)'sF!,[uEFS(agget'ip9Y42sM8bp+NKUGjNg?5slouB/hda_Me45(SUR?!G\:h`3V]e[<2?RZDgg+u,?gAZnWf0;h$9]q?S7if69i@n'#oG?i]&7QFXD(hG53*4cqT]>?u2/$Nl'BSGM?LgI/i%,otFSiR02)s8IP][$6+L9$Tl55C^I06E$i\6V2dN02s@)H$luJZ$60Y,83:KauFcYQ>BKQZlO2I/,J2HTSjS^RK_@c0'TKs),,+q'MTnAf-JHOQ.0[$bGR\Q8D,gTFP%m]M;sq4W'uCLks]:nTm7&Fs[R#g3ZP)CR)A%^5\\\Al7bYR?%[/oXSUhiS(pH4]n*g?lk0]L@A"bq,`^Gc4!Ihe<,b.A3ru[$T"Vp44'JnQk,WsqXE*,R1<,Y9V4jrZo$s5Ia`Dd$uEd)%r3s8bsV6V=cd@$;ZH(=5mqe:qX2UNp,1%&H4W1TU/FcY[#$klT?M"k!K@qlK`3,UHQFVfI1?5e%IV\B>`!2u-ET5AR;s;PK4bi#3pjW)$gfeG.Cd,>oLf>0$>nmA*iS^C5uh*/n/N-W7kj.I@AK!/AR61:-OKqg5kg,F>UFsA-h5O<1&Jm9=Ne[4([ALcgn<*7-!)IV2+$%B549~> +endstream +endobj +689 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 688 0 R +>> +endobj +690 0 obj +<< /Length 2508 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gat=->ArT2'n5n\Qqgjr(U[t>\du#1mF]$jd7kU-(4E,#K9k^=+W=4O.!mm=rd,/uj(2gbhLtu7kE?C$DEJa3I!Ki15+5o=]\2lGaIB;lnB?M,4N#)>0_SBYqseL5RJlm)"`#kje?\#_ipH)^ZfSrP4.Nf.c8\+=(qRAJ?lN.g\$H_\WhnT`]WEFm)L.nab;IBlrERE5'6M4?["#HrIj]N+&qn<]cS?fR?K$OpD>g1=8VA9@Zrd'c=!neQ,?ce;'-"HP?/kp=j7en4l)$)d6LVNk1JL"&ZK0>#[F,WP3Ag51Pbk8JD'MYo`GLN^dEdqfm.8/Kn]LTbG7D`?PrGIl0:,2D*I0%B0TI;=`hs>;(ahr70Ll$m+9=Tsi!:<_B7eALNda/Q=2C0I;O$V=:(X*Q9mSnWZ>=PXj:.R/Jn7oe-Rol@CDqGURZ%XJ0(Mb!Gn9]mIKs19H;:c4]\RXR"=5;5pT>s;B\>-s#_c]3>!CCg`ljf0Ko2"&%;cra/72VQlW2p+p.DkgP:LN1QpD!lnolFj4rRPBZ)q_6J.A=kGsU(5RLg[b[bA%3oLt7(^uB5e&nPkY&-4P/Z/E$7<2*sX!*d+g:_W>er.]O9^GjI+EWqP+`QZ40G9o%rlk,3"T(psk`qlOuZMXa6O[X&)X<%"2roaA3dTQ,6GrcTTaYqO.-c#+s5W84j%mkAqm23=Rm2ra?LlWaX\"1t,b!;uBtFI&XF,3_iH>7'KsBD10>IF%Y0":;GMU&)EAS%Wr!A.khsGnUb1SJJ.W&$-$8I#p3;_Mrn?GuMh=niL"dsRMiBa=a_&b22Xqt`CQ9X/s/XMeGYEstns'/,iOmj*#q+60/lM!BbPubHtH<]fqI2"Y'WU8bJ[>a[8IfEN=?Y`3fr^in]RP@CQa7l)MdVdDg.[L-(;rGZnH8!,N/,?ZY:>X7'S1iB/Vf.@.::h:F[]`\bO_6")C(:\][+fpk@7=.]JC5-%Q]W@lW%[>T#)?#5-/.6>Oq^CLd=<*gaR+lb;sJYho*Yce;Nt.o[iL^O)1$]fi:(%6kW)_jM%1!Z)7AKpq)jGq82]h?+]j>0[B!!d_XsGC_$dF/>XS#-X"RPqa4\"4e#5o7Opm$)$GuaqjluZ@b`;O9E-!r,o>C!lJa5gUrlW>MFA86"%X59g`r2U?[noJbH^I4qnb!#(,rA>LsFJ\[/BD9hbfI0N]7HpmL_ZQ\>kE$//bI*SXu\I+3FNQQmYLOAYsJ!p-fA6]eZHA;P5tb0O#&G-+EQZ#PlZb?M^9p'?3u'pI;4kmNF+Q.k<6>6jB*?t4D"#UFMgXp4huBP=bb09BJFtf@6D/HB#9*RO]gXe7MFK>pNW"GqIeqYtMJfARr;=MhJ:I)2o7^ENXV@XSZp)9K\D",#H;!`$mYV+ZLaNFTWHjEh=[^R?uJD26Qp:Ab/#q5G%c(+C,j:pqQX20/lR_iQoPE*]GM42(qcOt>GI`%`!I?cBXal%S'.Eg?/@4&5M]RYE;n$p[OP%:B"\1gGGm-;=e2S~> +endstream +endobj +691 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 690 0 R +>> +endobj +692 0 obj +<< /Length 2435 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gat=-D/\4>&cV3*Tt9V;!Gnp;G:cXa\R^p!H:`Eh+,Zf\'jN>7778XT,*e-bgjec`Pf/oR]kLli(*A[VRGi,I)>V=bMq-Y&k6i*&!QMCNT:XnG@%8@kM6VuC'6jO??Uli._U*"qZaokmilAZh`LG@K;a1/K**47OV=Q?o$bOf4#m7dITbiee"q77Q=X&opet-^g113W:id`_j7Me.jB"dX^O"l:gU[1fG/3OU`@*q>&sOZ=Gl!\;b=0UD78[Wl=HJt^3F-H'\Iau5`:HQ.CNGQ(K$5X\(Z@F%BG1$=/C4\g-RUn5X^p5H)6)q"`YZM>1;ih=SVI\mf_K^7di_9ij!+8Mq.Gb4b_,AAcQ(X=HTnDmZJhW%t\03>5SG<3,8DVe[XY^$@$.^2[K)4+UQaD?^brOmOeeERuU(7e-B%KueF,/26Y[tI]CVda3)+?M?^suL(Jd*X`b>e&R$?Hh/Y-#3scABC1UN;IVTpGh+bE)QLFImEL3JKdIUu_qF16J%s=de<=1upnfF(pV[Z*"Sf#,37e=(e14Y]A?,\C27hV2m-4(F6>PAsO-7IUPrN*oQs.h%W=,)Vt%>1lQ5Xg09@tbh!MU)_%;:#[X?!K@hO&heM>guhBKPB4ec,+">^_S41KGIb-%mU%BLk6Jm\(Ybr)8-(Y2our)8hH#l-cSXR.[=tX8Jnbf'*:I2nDunhhq.pm@@qELq`NlThoa%gQ<+1MjT9p@p9@$?E",0G.YqFY0To]\[A^O**PE[3r0oAF]p6s.a!Hj](<(n9!8d'l`XF170TC(B&VOh`N42YP4FH'n0TjtBs56bhS->Y(+L`NDUg:KK^7SU*p\r3!ML/["W>E7#+`UA]D@,"=In[D6Cek^T?JPtE\VN_TkH*,]g)$1W4#R08deQ6di$bA/#e>"UK&%pVS^8ZrCp[jXPKjjf`BtRaMo':%=pRbM/5Q:%^[9ij>?EMg<+$\Pn5f?9,]STIoK?.&PT]+aq-`XNI9Zb4fFLYqj(Vkl]iRD56/[5+1RBW)e;*lYX;ECC2ptmK84KQ>e/2u3:dYKMCgt6uNm)=nM]>Du9JbB09>lIZY-"0UdBe_P$oSQqAkUB;12fq*:R'G:iT*;eT"H`DlhE&,E8o"=U_FIM*mibn3i=%gc?a"fIA,/gjRg8V,WF3Qn;+L0aZ_^rNA]g2c+/<6lm!l8[gfWd2hu^jdGQU09@fs'NZcP+Z-+\q'>6(Xggsnm4dqIK$sNo&WA&mX?:0)_'Dt?a'Y4T*.)1@jX[GMe5k1pMLW7fiCb4*6b*#k1MgMaTB%O31S+C%gfjjY_eHtN,732MNk=)%4:.bg7.5/.R:)(71a>B!G[gRGYi42+LlTD_s&b)&W^$d8VL6VF3OR"J1o3Y.1!"h:frVq*oLA!M6UQO/S.1.9f>Bha>!D:5L5)0%j1;J+7Q`jK"lfGa9CS+res%5MVOo#S-&A'"#hI,@)R;]≈%/Y%Bs*i_G)(a?67`&c%3.bMGr`nU#?-kH/SS]ZWh\sPeul,`1R#\>l3f&)Z?i)lC2FQ`kfHQo[bH#qL;@1?!o$-hdKeLOfmaO%;(2j6%iQ`Ahh=Q@I(.!\#b4bC3)Yq=#G1<5K`~> +endstream +endobj +693 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 692 0 R +>> +endobj +694 0 obj +<< /Length 1975 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gau0DD/\/e&H;*)@2'Q?!!t67+sggQLUKd4$u"6=*ql9[#$Rap,;$;!4KY/d0\5"[-Ha'Zj8T0\A&V-FKj%W;'&G,\6u!mX=GlCDe#.?,XAKT+LhIMZhkqTNE@Zbsj7jgYiu\:H?@Z]SK@&sHKc"Y.o`=CfPXk&h2*V7S@U3oK*$C6eI:m%!s+0?Q:NIHTrO=Yp>Ai_OSlI<W.J=_VT?SacrVjakX/#/gfmN&hHUcrRg`Zt75YhTE-Zgi\Hf6/'fBm2#@)bhi5\>s_?$$s!Vuq,VWO,mGA$7.b_4DTm%uX'>USV[X[Zq$9W5j2AY>t13RL"MiJ1"9U!om8:AZ@#&9`fe9i"QX]D_tU"/2^b@=0uQ3>mda3jQS@*W2'g.n(c7[H2Yd.IRr<\fai0Om4'al2S`b%Z3(:1e[cL41.D$PTI^5K2VJn/hLT6#Z$iCV/E*d+FT76S4mcMD?e!iR.?XM^hZet2$":6LaI!<2\6KW=aFBX3oR'IN5CRY'V)MrLj1p1`al4*K7@%68'&)i4_Oo7CU&+<$AqohD91RCi!_@n9k0pEt(\7.Re];0KRX47OD,`"`KEjt:7eO/^L![-]hY'P7qA+(HN0&Y4^$dU;HD>+V=[:8X,qCsn-^ioh."(1*?K<_qM$Al%Lm@Msj$%^in(Lqk21@(e;[hk5k";_[7!,Z.cT^>>c%a]L@g8#+-XaBLbo:!it'T&o\H]Ud\o3g;,hY"LWFkAK,1B+XA#E6Dl+G0QsY`O/!%Gh"](S9l*_EcpI"9\-&$nn*UWKut)cIg9.Z_H\U0SD9LqkJui?k5[IF)@+0rcfXQ"6)ZgV63M#kc%WHfC0irAC]JbHUanegD.n?n&')bC2M<%MMh.s*k3SKAmoh;h@;_,I.,%Z%lUUT[4uD(R_Ap3iI5@"Wo(acBl6e7H>Mi[(^L:X[sEA)_blAc/%7(%;t4i5?-d"6*pO$-Y3^"fAr59#H_3PSlg(A:oqJmpb*oAAAX9rh%"hp*C3p"1KLfs>ejkt8obr'a\NA)4Glt4"6sK;Ua!,/_B8f7rmOOu[hi("M),Zk&!uAY!7_rDe65CWd.$r.67K1g7EH,HZBf[2AY)_Zj,Daa/*_[ZX&&A$IMMHbK@&;hKO1[mX@=j.5S6C'+8IR7:PB*#@>nB+/HgV7"A,J&=:`"+^Te"Llj"qL1[?5!JK]66N~> +endstream +endobj +695 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 694 0 R +/Annots 696 0 R +>> +endobj +696 0 obj +[ +697 0 R +698 0 R +] +endobj +697 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 249.054 561.05 307.706 550.05 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A << /URI (http://projects.otaku42.de/wiki/ScallyWhack) +/S /URI >> +/H /I +>> +endobj +698 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 299.158 525.85 348.35 514.85 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A << /URI (http://www.modsecurity.org/projects/rules/) +/S /URI >> +/H /I +>> +endobj +699 0 obj +<< /Length 1862 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gat=,D/\/e&H;*)+U$HO!XUAL'IES(;D`/N+9e3YfRS)](n%gdb*#@pDM)BtI4%[8;k,g"!X.Xqo#Q0&GL+ZT(:2W--3;+7$l5mH(p%@0#iQ:!3!o[[_]5Lm)D&>5?S<4b;SEJjU87hO,qDsJe9:blX=?<3R^F/PR4:,M=fWJ(o7l#9A]kF)b_9`K,?@lWjih9.ne%ACc17/:SLE%%1VI"Yatnu_"b-c8hgc7HhIcp8RZ0.U0hl/BVfX$`<\0YJAe?mOq@(dt5pRBeI*6(Eb-i[8DH8(p=/HjmPJggT=]N^*Q[emP3/HN^Yk==6l7h%76u"_S=f%GijAU[rlRu1n8G"_+#%0pD\a,ro0i*(Or1K^DCNQ0.*A,iIkr<'n>KeL(tt$M-dI>#=f1RV,7T?Z$G>\A\Dg]c5h=1"gXnW>M8okeY$+i7FQ9S3MHT*S[E?$?+JrPHE,LnD>Z_*erI2pPr058jZ\BY$P^]:b4B._Hn3f=PF^&;,pE41EUq[e8m/=__s13C;Dm26)Y&c(5]j0G]3H*j;kL6)Q"k);O)17jbHY1SH'r0%R7+@f3j9jgN,4jCCO6ocGJHB,iRd"e!cO"&;teYh<.DAW>c^Uef>F`TWohamD[^%qSOl61urF?ac2+rZLpmR=*[c='G74XEjBdQI-Q=ttB^=;4Vs8,dVPGJ*D'k0Ytacs$gE0Rn)[^NSE*r47QKh<3Q!0`08\kl&5=5!qDAM@h#m"RV/!dnHsljbFtKiJ[n,$G4*\-CHNgDL/YfZ'sCUh6f,9Fjn<'YA>?;L`8VFVJg3iT#lXO2]Y0KY14YiDRrS"8"A!GGp#1YaA-e@V,I_+bo@:qQUbe.+)j&pa%5MG5=Q:?g`aQQ)<)m8o*L!'9-io=R1!LdGilgB9'+o%6l%c[eZgs%k:)&7/lhRFb:_Ze=p@NG-_KgakWG2S"/RL4<)WUEk7XM+:o(r?uh(Zt6pfu&Ih_mRqZ)]>\,C&*d;)!:J1Rpn,$02\dlebR"W\L?CEh#9='Q=X@o<"UG^`U%IX,a0acdZW,(]8Z4N4l2FA),K/*Aod)\^9ELI55kmG(FhH?@+o@q(J/E;ogHjOT'V"8kFgm[.5ZY)mUSS8Y>IP+l?"k`#+%E0K68O"aZ=eoSZR5m@H7a`gQ0<9gp~> +endstream +endobj +700 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 699 0 R +>> +endobj +701 0 obj +<< /Length 1882 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gau`T>Ar7S'Roe[&Gjmc#q(n1-jAg%[X)3aFBoOr/$KJ8/5rtW=n3sjC&\'k/sJp'(:OAM^R1X=/j/mg*u;3OJ&9jU&b"5@0XUd]@Ih<9mWB?f'cYTFF&CHW!RmM%;ig"iuaL:\R?.WQ]Q9YKE>sP3l3=#go$l[-u.;SgI(ZYInYf.&%l4]U*As-lYbEA)3r[W9^N6Cj__NFCR[Y8Xrk5Q'@B@o9@:T!0uVQ3QKERKL0N+Xa'`\9-oe-:=@_W'56UcSX0N]\90B^hc+072`Z(J@*t\>n\FYTdp#>C\$Bal-R0iC;L#FXIV?&7p0n^XGc8q"$_gtg]h%VgfEqNEV0DNlTB>m+^OMj4^7!m7hgDGX]Y7[0;GD@A/4?UH9]r3"WlM0f3nSW[#9XWm>Ohrsb'8jn$aiis39>sf,/f:QMK`A"KOC\0O.n@.-30!DgZgOIf6QWYQIki@(oZ,`u[WH3[*'lLH=s-o(prGNoLkhe=4rDa"#Uahq%qY:\>(jb2/78MI*aIF?;q9McRQ*7SW`68RCp88AEIQ-^Al"X#QsjXe]t'77c6$:[oB_tA43VI&cL-KS.HJ3$kcW#()@.'*p1$Xo_)p++Z&eQQUj89(2QBu95ut-`o%BoPH!g8>CalY^3qk,e:6I&m9Z\7U=1V2n_SA;"b&/U.:/Y.'[m%ZF`"`PLG/W5SlBJaOj>]b.K]+_aTn.<"BUm+DARM'ubk>dZ:a1+<+In<,!YT80,:^jQX$jkY'%'Ga8D-'\>71FUgS-'Q?Vr&%=Y*9`pI?%V[Rq+#?Yohaq4hj+Mh\7U!/`_U+I4NN)_K2Hr7rTg!%`fQRh*o@:ALsC#$!qcD`:`:Iu1>L`5uH.;&&W'=)`P)tJ3?;b+@`Gt0`(?-/q0BZtFS,1kCWF_'UNYT_'`QJ(Cc`u'Ab4O>so[__LQ,;MsP2V:`O8)HhHO(a&\2..8`:FBI>@ZI*GfL4bl?`*%alke@^HWN6hDk+;f!Z&e@NJYB(S=s28^/:!.cE/^$%\"Ld4uOb*nNX5J16l;VV8E-8C\]f8a2VM!N`.,n2bpol\d,1b[!^80ojAXZXZKKZo#rS@$-^2D?X?/U"L$/(OXb[(p\*IBQg1;k8OA#2BM5SPet,M$c:<^cEE*D>ONe)V!+XYu6Fo,QoHj_$om]F9YV!X'^qo/q#E+"GX\;sb5RpVL#Rc0CJSg0Nm!Z8CRl)s&&07<9rZj%b*.B7j=Hq"Y#d3nnfd+O&Q.gop1huu'lSI*]^Vq)#==_2IM:94LRWiH~> +endstream +endobj +702 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 701 0 R +>> +endobj +703 0 obj +<< /Length 2195 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gau0DD/\/e&H;*)@J!2+^gTZgH4,H.C#cSVcnnJP&&Y[fZqT4X,uUM:\G>k\]icW@Q__DnTZB:YnW%h6H]ED6)nifQ`u$%64Bmi9nS3`t%fF4SloG-$:5hLm*7+3GT-ps&3usr=@>o/Y,BnO0,ip=H<%>ER_^EsD-0pe"()<)b#%%9dT)E7)0Sg&+q>fBE<'4Z%$/2Ohs&qM!C:EMZ2:[/H1WB[!XGT>r2I"t/U<_D\.h%`<2LW:#d&dcS&b34/nP(7q[m_/m7/<,r%W0t#\Q,I4,V(ANT[&iUUToeNlNl3T,n[R!d9H)PBSRgXg1"-J^^.]G5C=doPXBi_t;r/H@'l8[:Jjp!\TBLf"@HV;S02hANITW'bBcI+iB\r!T.feQQn]sblg5adI'f1uTi+Z>VkDe5ar-a&+r/EdR+LX&pq9R&-Im"&;oLPB1?%#73+2lWerTGp/Kh9`2i,8i7uO%Vif'U9ij-Fe\5nO7e;LD>Pca`pE6!tqJb4!l&t`8"?U(@7+m$TmN!N`!D6L4B^p"\3JY>;!,W*9iHLjWl9\XYngSKX7OoJ+cC1\4O>p[F+*(SXP(PX))OiG#Pn=tJ"#MY>s9u3cPBL-SL%(9MrK3Mb8AN_I1ug(:N:928Dl[eik1)?3!cu-GKH/Xb1--p2K'TY.lS`0&9Gl=f&q:You%4Kf[t1AQQ?L\!#o[.FD#TNu-s*V!Bg^)oiC&H7Y;)8^UO\^?iioHtV^@&Y1eX$3<#X8p_nhAPb2%`XpK;"1b!q79SUP8EhJP)k",L%>FU_!LK%49lEnt$\+YP/qUsg1;R+Tp%BaqM'[aW`N#cD,rP_lK7I^f\]9<"SIjtK%kCG0,_ZtZpI9!/HgR:qa20Sk)9,pDCF+_VEXga"g9dK<@sQ8HcG,'Vf3(CCY-;geT@PBqG30\`\'?fi#M4dRVk7[^o(--9f&UfEl3$/jC30X:OLK?sp+C5MbL;ZAc0rV]]1^4#["17CsZm2Cg7]oNPcQBlrIhE+p;^G?G4hH,D\pc?op6I:=@cE5&#CN8YW]uF.E%- +endstream +endobj +704 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 703 0 R +>> +endobj +705 0 obj +<< /Length 1803 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gatn'95iQE&:j6F'gf,i;]oL:;PGGo>/Yh?ODUJsfY_=1TI&;=.SHp4`Qc0TTd3g;in-hHDk?J-+7o7ep=n9BFE[68`:oQFM3!$;nm`A[!@@6gLJO3)(+3HahN$u*&0]'G?H^N9ObX$8cPEVbp;"P_?K[\`'N4)*B5=)>V5k4n2nZ)#=h&3L]/%_(E\"GXdE"n]7f2^,P7#n'\Z8NL6A\%"]@r%G)7`hDokIKl`A2o[Xi;M5%\]&_?>Q>:1,=s-&X(ZP>HaWepq@o19lqsl:/T)+/FT)Gug\GDD:d'lm=+.M.\e6,Ttp?S#ZD^Y]F66dYUPB:>\Q=fUqb-e7g3fqPo_]Kn*\&8HRN<,K.2d`CB+!"qa<9+pnXW+SRuu?2=g)r4rs]A[UW"eqId6=5l^pFF``n91S&3#t7]O\uh>]1;s$ne/;)Wm,M6`Ak/E:g3DYKCHu38b3"5BKu;P',;?Y3qoA2QVmtmIVc5DfT:[khq#T!94?@?p;7g_/3>/5`l0O9o-g/"_K0W=;,7`Lluuh9(q&'&4CKam-c1K32l0[ilLZt;/l-8VV/#;:dbn@U0YW87?\k`Pk0:1ihg&'fHBgSNOh0n#l9ial'-C:(Rm1ugsE?@)8-"X2T>-9N>Ah-Chnd0RW'mkui7Y1)S=6`tan-*BfKt=WPfF=9T8(^k=.rWVrqmib2Qe=;rK!r7)Hc05TY=GY5MM`5$c83efBMkO;-..s3&h72Ss>re/:q,%Y@GS[@a/B4,.))OU@%NNO*)it=;L:d%X,*S9_eaYDIf0,#4bLd2V7`3UGFkCKhjFGkOb)2Ldlc'5H\)V)'YV5A!,MWZ"!0FTU?D^urGoVYT7Lsd=0N=gK)mkTh1f;dk\8DKr\F.mLF'cAsqm^*N(fh&[Zgmb5_HS<>2J2rg.kH]A@En.Uf3`DHV*afELSIf$AprnM,pSIq5LkaL+kBUAOVg-hB;-i19`[J84*=KYDi2`1"=A*s(TuFS=\BPm,E^5(B.%Al8/!AeQ*XIbQnZc]\dC'YA]Y1+(Z5c_D'd&2J8dY6Bjo;E[^pq79m-?JPUu/"*EG=8ESYR*@f*d\82EoY!:KRWAlHMFm@?\7/,3pUs']i9;G:+$Pe21M9>DF^lAkc],ob".k=Z/GS8%[Sj54c!d8DI9IDrVj?"e>>c)d-#l*Ah.emfR%*FA*;5oI +endstream +endobj +706 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 705 0 R +>> +endobj +707 0 obj +<< /Length 1617 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gau0D95iiK&AJ$Cka2>V.m>9@Q:8,o$Y4f8^,'R%/9rZnl0bb4OXZ,2U\KtGa@5]S1E6n>H-i2GZX5n+*8hZf_0e*JKCoWX+oL:A,(N**5s,drHlN!+;9:#_ZV''=ok!W:0`M6>7=_YjmI`.>!>$tQ@2p0(?WEBVCfb7\EAM;!\!g0Q@Y.nAVf'uK1:SY;5u^[sK8\n#X`h6KI9am9j!'EM[;qD]XS15d_NV$(l)aaEq9m/dZ&i1tF28*n9WpnB+c:[IjFkMJh$`8`BkQ<#uA[](dgOEMija*I4CNTJD34;\t:#!jqVEEU2fQ/XC>*f&&aS'+r@>@h>kS!Lc"GpG+\ETk&J2/G\t@qE*sEF9n:2*Y6ZjD$Y1%XiCd!;V=aDj1>_4'>ReV-Y2P4c^4D\`eZHX$_Fr)?Q\4f9gJ[!`LccObegdF5ht1b5F=N(L39/>a4nQ[YjOF*Ec#OBsT3<>cdW^"eQ^$]9nnf*aj$.o6er1SsDhEh+&g#T-,:i_T"elGHD`,JC'C$0pl+SEd-(H17WK?D:Q)ESu$`XCDY)B=0@dsTM>6e%,`+>?RrsAgi?X6+s5PMWPu(GBX9]fOX<-PuLU=A(_"BI&D!d2d22"+'WUBn9es9n>NHM/X7V%iIni)j?_A]7NJZX/:oVoMY#RPa0)T"<]LMN0H%_fa=gG(EfmulZd[u][-r!9%Q_"RW)1m8'4oVD=^rgm,7=\f%higYTjSP+"`D<7'L]->]2F3aD*;$=WAl+=]A=[W*Ha#nQ^P!-uU-qdPJGK-u\_AT]+6%3@tW;Q/G,9*@\f13.upBc[5Lk=ddoK3FLInr'_+(:jMm%+C1PG^aO.;m+SS,mD(])5e6rcVO!Y7q!Ye>dXXY-T8$m%1Y,5R=>5sNk3?NQ*,t1`4!p`OAj-R0.MU##6Q[$T%+3HVoKAYMmRFqFa8;dYJ34rfcP2s.#fjXPu?YVAG`lpTmUT*.cm7Zoq@hA`_0&^Ge-d'!#lZB$`-$sl[FVW^*R'*:S]ff]@$/B(@Du&?AmT;KCMA+,DmamN#\Cl)o$l/`.k2,8_H.Gc#h8Jnk3o2dfVUX90koSK:g6"KDOI:).T:`#,KH:neG9:JkBnd-^c+ms(]@J;hHfL[j#UM/e-Ba%QOdHt,M6tn0?P4$9G*8a%+jG[^@V4UR7[UFkAYu5LAnKaOm_%%C6?mOWs-T3a,Emsu8.P8M^NHdm_3>@N4\=W5FB^r4%%dd];2bcnYa,CO]B]Dm/qM-(c>)S&k)i!?YRWmtQ-u['7r`d8`Vs.*iO0H3[ng/c>e[-+aQ~> +endstream +endobj +708 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 707 0 R +>> +endobj +709 0 obj +<< /Length 1661 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gat=,D/\/e&H;*)+TrbD-QLNa9tNfSSP%6iQD"_4>XhKkhE:BR\sn:qa[WF.P_)k"WD]WLbFHfkXg`W70P.mo:3hnJhCIbLrrr?,cT.1?*u:O-`t2SrqKZf+muIIdWsMIfH]i*drl7gFR1JI`9cF6-3:qeb89KC8mWffI,"A5duh*FN^"dtXtJWp#l]T82'Lgour\AMNsB\1G.o'cYg0'f$5QKop(R,n4q0*%s*4$6]U@h8^'p:D`PUV0kZ`W^&c'@'pAC6u5s\>"t4(dl7\5I`L-!-R4bF$If4Y>`KR]>&7NB7G>Un:!A2%/t!0FB)>KMhLOgpfM%j.RdI'GHR!SFQH91ajp/rj8UTHWWJm"pVf%=)SLd#bS#Dnm8(tj*JC8)K*+P5\[o.S[ss2<#oZXcq&YXY']X26'7nB%m]Bm:qr(Ifjo9\$YJ#rq5:o6Z[56kl,BCl+SeJ[emrrFhhsnD613!(Uhf/aTpoHC'*RW,D?b3rN$Gh:(=b7FNRcgfQYF[1rq]'lM4IZd"#'p7I\-DpP@WWk$h-R@D^4]mk$%gmZ9Y]&X^%?ij#@qVOnCs^an@%'HV)_'X0&pS'BR(0.^Pi'W(mY@Hgo6c;V&-c3CMVR;9iXr?Th;>m#[+Q)YNqOQ*CDj0NpJ#36[(WF<`E'@LEJRF&[:87_Nuee-,H?51WA=a!tgF?a)b\#L4\HO#r?oO8e\puG2a:s`/hb;UKg\U.8]\#Q^%0/rE[t-I[S6L-ME[rd!2!s,2LW3gG[7Re]BmLdk#%!oVWCpj?##POTiW^:L`Q$@i\R7D3ua1$4Y/[OKiMTTLKlB[jMB7D(U&1LUlFd$(9E_oLR#8$+DSF7sA,bC1&Brj%g%O$"Xm+_j-i@3=rpb]d8YTd*VIWDc;Q2U^AF!gXRK+.'eZVW5UgNK3AeTd$_1D=aZuOs)FUo^#sbp:?UNPEf\#tNB7[f@0Co>jLJY0,_iJ:6,R+?HDUZeaNC[mL)#l[UXd%WXH>AXs9?cC3BuD*6g1^(X3*K.q+P1blJQ_EiJu[!0lo#GaZ,MP$^.AAAanHMJ,kfl`sQ\f6)b"@j#MpVpJCc!#B:2rWBc5't4~> +endstream +endobj +710 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 709 0 R +>> +endobj +711 0 obj +<< /Length 1815 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +GatU4BlD`a)#ir1Tjet&!!t#Z3Weq@O0$NZ2JqK&>.-__l%Fj&=,2uKfRMeZK-Dbf7oKOF`5d8IpNYO^IQa>%r!ULS%Zp##=#8I=Rpj?k5OA.J0]+14qjoT>SNfnB;3c0IlMTbfIfh^W_71.W,+,k?GQC0Li--qp72Zn^?-,4@(aSpcU`U`%\Li07(9rg]o6"??o2;)>kCbc1S4%@LP8/nq;O$;Z0jGf<>u*VB69c;mIsH*VFo>a0edT/=,U9QR:D2&)L^q&>o+4iPY=;R+/+S#"f4fek4I=g#I)rYcV(@NCI(iH9O)AM0$Io'uV^Pgu6JZ]CT7*,Y<=E@ZaIo-]c#Cid<6cU!Cf!;lRV$.:,DXJ+f=sogD5KY7VJ;#R%dWP656>fT)gfD"D*]fn[^3s:CV-(i5/1nBjm.kb=WM^c=BMCgs.pZ/X=&Bt#F]N57>X+N`?TfXPLVe`3]:-;:^=j6%iqnQ.^+He9$[ll\(W',f^.d:ShOYpN[q&7.ZE@VC(gi;-=0sKB%h@,;I/\_lQK(c.ifU@R5%8]U[cuqjd3S7IPHnr^52%NosDd&XQ1TbpGdX5OJI0+LXdX'U52k47m%@YHacVd2RCXP7+\MACa#aAfESm8BrNgO'c^_'H@qoQ7YR,7-(aAZ=+a"\ePO5%CqaR+ghl.+Cu2Valr_i:[pCe^C_miDT[`ON$(hW$^**$jK6?mqH1SI=J,."TRrdj+%&$8TiueUS1jN)/su"$WR.!$J"*@U(a8p!PaJf.9KJ73'eDBQX`UN0XgtOet"""bBb.D`3RTl+#%jdp=l>*D@*_6U[Uu*^+oGq*?m-ad:l:biWo\Vi.:"L9lF,HuGO6q1SgdCK[T0G]oXc:-#&o@SRJ7qtJ]F9Go)gq>NF%A/`?A%#Xu;dhi2_r/dB.];V;t)8duL9C*]nc+jKaib)7>NPO<.8j;X88lnrg;c#Tq8X,7@1l[@tgMPlQmWUbT,4%#I&7HD80&hkG;YU@4kYNflsk4GG7tdDTm*#O43,LJTH(!iAci++)2l>6~> +endstream +endobj +712 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 711 0 R +>> +endobj +713 0 obj +<< /Length 1905 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gb!#\D/\/e&H;*)T`r?fTFNKdMD?kn/s0aLgL&G`Q4V7p#<0kE1[ML9]pC]@!)[`Y,hBLL#QR7Mq(;YWs8K:9'i=dJM=lq<6pUhslitbZ?#*Pd08c#16qg#Cdl51AM#ES)43+O1pEcLr2*1(uFG%VhM0ip,%J*-M.e&]TpQlnudoQ;365(]$`8D+]*n+1.%''[D=?3dptir9E>7noA>'NJY,H+Lh/U1B_?U>6B4D8.(u\#k6TLl/gI^B(@*Dl,@bHWlie-4l$A%7[YE,5cK@`'j#OU6'oQ.pRoJZM.9Os/5/:;bcTni@'>)2/'*7S^[qtaRq/Cq^T#O_EfXf=UW=)YK*!HojOL09<:RkNS#jY5*ooaJ@BM\PQ4k>UETK/Y?_H!4%hgkXAa@IERJL/:F8P8ObG'6`JNs`_6f4nOWR>D]+^h+iXJZ50$FOIFD'>S!1PfY\ZdS^q@DMf_^;kQT2mVWGE;a9!7\83o1Og\Gksg=uL2a25;`uZJ<4HngK(?3"D]`d@f^H:HM8R7;V8drI/.UBJ>K^c[VQrpkoEPXIcNiAd(2lTOA/VhQ\V?W.ACYnmumF\QH2DUS&h0:FRO\aKn1i-=et.`AVnbq0.ij>F"OgQG!Hko%_7Mg9k81rFAU\inhm_$W=(u;*IDQ]QL-q,;@iS?/GILKmo6G@&cll/Vck<>rcKg`XZ>5(Uqa49b7.oZ`X8:'F/_eD_*[n,doBuVM7Q2&P\/p'FgK8jZurum=,8>AV0Q!#W:a@>VXGF?mVXE,SZTo4m^BU*b)0JOodj<`7,=oJkc.#U#HR".2:NBZD9ZBm*)%JQp(V@3_Is\7[m6jAQJPmWOF\PQA1#\*8C'"38sk:GQIoEZCOY*@1X$S>%uJ#pR=gWaYH+ITQ`!tS3P3Ijs3)[g<SMMFo#E+s#Qf)M9DK#:ilpHej!2KmE]>(d_sUD]rR!;b@%8@UD!f+\+GR2C\G'87!qq"$el*"D`ut^*0"gZEmmRdAB8?ie6P0IF0N@ll:A6tL"AEA!-eXPO&MVFAp]*[+>a0"-8W^meFgN7O6fej$&J.i-XW\:8!0,%g0hI$!?L.%E@<[>N^lLrO,/.usHQBjoU:tatKFW2fRe^A]DqN"cE;s$`n7D,_LX1CcEcQC,^E!CADnn:tCY*1.WCJirMF/R;B_M*GqAnn.b*hi*D?O(RJQB22\#_m$cDh0uX"*I6VY-6Ru+LthC?UXL5:B~> +endstream +endobj +714 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 713 0 R +>> +endobj +715 0 obj +<< /Length 2267 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gat=,h/D".'S#RY&bUiYU0aAYn1q869tf;m]>:k0bLL,9"4875NLdLKrT!>QG%*O0fX=BckD.CRq*)j3R9dIOk?AcJgR9]IChn0E/K=\nKcM,Jd#LueL=U0VrH%YAcB@k.FlV1>_@_eJl\_mF#upSP1(tjC8P*K&=aih8;WQ#;".V't"@LWhM,lC:`&cFBK=bALu#+4a]s@A]"T`5gb(`fj?la#-is=eq`U)f'6\aG&1HhF]!'T"*uMuT*@QJ6.2Zo-CgsS5\KE,4@Tt.G61Bm8`p79kQNibRSd!>?C8=uNR#o9No]ZJ;fuSD5*.AJh,NF_*m4hH]4_L![AcjEnAfX[o8=O](LJfObk@'U;1*&K+(4/VO\@;3,Y*DpBST2E\_>6\3aR.-1b%BRXfK>I$'K"[/H.[\MX"lB51%4G;\G6%Kub;*//#h8Mtke_F%>UV,jB%%6TYpe:e3QO93]H]I":\B]+b20[\kXd_A,eh%#E(+D/1U%cIXtaO"L09ae@>B!.r)NG.Ep"23CI'\C;u16U1rXW9cR:V:BW>(C2Al:(>@!_-M.XmY'%Y]PS(N,94cg*QD'Gj65qrWM'b+;)q3Z1Vn*F6ISo^BetgHukfim:1M.oV\a'*[pRo-OYqNc*cSd!Y>)R/$^HLNXf4:.>TG.0:mODDAJ!(AW';+B\-`M:8QR&b*c6/3Q@S0kUGu&mubFZD!XC13)/!dhYrB`Eq(r`V"9Wg%CX+\P#@<,IO&#@@h6>iA%??C=a0Xt_-,4d=Ie]&I?JE26s-MDis-#g($bu172Iq)LA]b?t$Vs]6;%i=kUemWk&mMpR'MqXE4A&2N+Ei\se_0c2Y6-mLi8*A1+bW3@VTpakfA2n+QM3pijm[g`R5k^q'ZJR/e,%-70eY60d+n+EZ!X#.jMP2'e>%PnA8^UR[QJ+OCLHEV)aU3&@NTLecK!Fc$gYNd%fA\HHR8?A&bfSY!:1cKrs07k``I7kkbcCXjm%gD-Le*Q8rRgZtlkoktd(f+lsC!jWJd69?[MG>jo^@iD;YQ359I,sUY,+^FRF?s+"-gC:D9j=cf^5^ea$)hr3n!61Zcs)r;-5oTiX*_r0a[<::=kh\Bb$KoeWM8*6qOa4th1A^Ria`/@Qbe(YX6&mVUZ..VhkQ9;:0ZfkN@2mMMj+-1PiWh271p!op*PnT-D.da932D;04ooc=$DVLAUF(IihJdIPl9Q-[lDQHQbYckTQ]3[*&/]1iNYc7YX0Gm&N);CkOAnJ9_@DdmeeM%*LOH%b&sJ0nNg:I(oG[r)8_E9%;*[f9Q]&is2Ri^="=?g%%P3ZVMjMal]NoJVRX2&"7Stp$"$8)]U3!h'rs>9%*ap%^X:~> +endstream +endobj +716 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 715 0 R +>> +endobj +717 0 obj +<< /Length 1012 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +GasIf?#SFN'Rf.G=?Nu(FmLC!Qdge6AR24=[3_"dXj^en"-Gp?3mN8*5:7"o:$KS(5/*ZPT'P1O"7*8u0STkOo)SoN!_"RFXhe1HlJ($R8K1=smFCAl=D)DH&O?E`PIHH]TTY8QH[j1;cS%rB)lNXt,felp5F/YP-0ZD#7O'+%9ZY3cO''0?Ip.Ab.H5n9_\)F6tAjeZ=KRg9gIClM`t[6L$02<\U4^clHcRdnESj-?UrI1=tP:V!>math>?mG!Vq9d&u>S`==I(Y-@@41>X>LFCg<\mn_aZEb?:o[+Q\$Lh?W2dWqmE^Tl"M.Aj",HP)>3_sn"V"ZrT*d`;m4*2LA<)52FMm[JC=>"=,,!7@*"#EP[*XVO@ZV'*FFSdJ2U-uf9oulEcH$PT1GLo':;87%jm#Vb`HFBF9CgG+Z"$5;]BN(bZ_kiT/A6J6k)Qk+%`PSnm_NlZcROm-L%M/B]&F>,W3eX"H=N-,uMUO=!(OoT59=?o>4^)b`;ChE:PdRm(o_%5:nq_@'4%FD]LpTZ$/%1mSPZ6@__[c<_2lfN68, +endstream +endobj +718 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 717 0 R +>> +endobj +719 0 obj +<< /Length 1698 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gb"/'=`<%a&:W67@"kJ^>A(i:8c$O=X?%ru['ppH@m=n;"]-!%&n@!YKbKh#$Euf7bc>\gXUXmr'lY)'lbJnO?DJ@H+K/!ff5L2I`#NhFgI.`#34343iN<2WGuujta,G>pD?[4sCr(Vm>'!)m,EOSUB-H<^kGnT(!=mdAp=f[,I%R_bCq&qAsaf>/a&m<#1aC#gAb\]beV]8q^jR,lJHB8e=p-f1n/$T7Z7>S8=n$OHF+!2&YX'kVUV7EBco;LNT>MR=+=cRoMJBMW\pED0Pin_P#Y[tM`NBZo6jIA+qubHbJr"I>mM%p+fO=B/iDpCQ.X9[0!kK4`mS>18BS"`E^qr.gH[4RVTbS?lEZP4#nuK[WUg/W#!oGhA,:sk[\^"9#'o8SVBRfFRZ4"'6idUM!6]/)h--J&FU%Fq&fTVKqB!0u?SjXGZ(!!j$QG8$(.hhDRt)F*Q+_nT:5X'E*U>4GgTkL/@%Jod!1MFB5!V;qd7e^R&,=IPd9DlcATUV0:A$*9p2tT#OU/4om`"Aa:PAc(;r*+9W+nih9^aFr'Qoni".f)#Ve!N/8_$:_\G+AATkc=l?qRA)f0-e7B$Pcl\B!0aji-8K$j0L`CO68ahehBn_q$Xg3WW#dCC67kpqbGDRL4cnT7:jl[e*nic;m!Q@_+Ni-C0hXZ1TT33+1'Ali0K(.j#V'qe/#p4H63iPoW.R9[Y0d^f#6@UIbTdNbJ$lbf@aEi^j,]i8\HIZmGU7U5Hf89A^Y$l!"6:I;!<#^!cEtNdlD0&`,l4K#1+6Hs7Z"qE+d\_T$jE""+Fp`^G&RCECusE?8Ome]Pi'*5-M"9JBL(KR"4ECKq=A#b0,Y4ZMVIh5kbJ`>I/WT]ICkYD,Y%(E:MYK+g?[Gd&ihRm3#2aa2FGm?RN+r,WOMoAPB2R@,(;:S\N$%Udc45L0E&UihfJW~> +endstream +endobj +720 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 719 0 R +>> +endobj +721 0 obj +<< /Length 2327 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gb!#]lYkN9&HD156HF\Z"VP#-7mAk:S?>5OWV9h'LOth+>Gs)6''1tMrD'(8*Yhgl"q2=U'YY6AG&Ir\[@K=D%K@CuEe,%[/d\9!>4/N-So*/%lYgS7433)@j%'cigi71=KX">>30NU2=I#3*6"IWQd7XZS-)6iP6"%hfG?OUo\o<:6f4Y#s8h,(b3VY,T5Dsj6at0C"Au0m)TOh0o!_F)A9iM0b[+trP3STjY$ALNL8't(V/\A-i@_p/hGO0mE_N=QXTSr8\J&n$ucsf#IS_5:Y*@HH^:qp>_SG%t059XoPq(B2"\o9tKH&bl[CGkuGHduA5@O39;\JHnGJKIOMT36J=kAZh*U"roKo?H:D+,eIgYJ2YAY80'h^V7I1\+m&>TCo\VfYdYN#F<<*JsRl`*Z3s`*f5;D^^6)0*KET;#)Q-G,Z(2UhfA^u5!0aG5noF%%\F`'8SF!)!U8:R+nU<-uQLEaNq3Ys2um]mfY_?qkhksfc"\Z$`as:n%S^/_\9LA?PQVL]ign@k6`oOlcB#M<+AR8.rO-q=e-u#oBrM55ak9KGYRG6SdES*$]0Ek+7HPa397C4_VD99DlI4*eQ=H`P/[c(`HRk!XnD@13i&/]lV*^_T_Wq1i*Hop:.(ZMY*==bl(ZQb,).XHCFc#\>HZ0BpEXk?JV>j%Hc6u[;];0X(DlD=.Vi^8a'j7[G8)=@*uqi9EPI?oaR?87d9R4FBb]'QgYo0(VC(!Y(GU2R2C.mXaE&QYm3_7$QC&l7n?m7)Fqr6!9/)_DnJ.\ZoG7iEXp\go/XUnH.*)_c,*/Y?Sc[tJ2-=8gEXGgH&7VkCR/6/rXU7:"H:#s]_ep!AAWISP&6B[++\%fUU'Nl)$8,!?pBoQTVJN>Ec&2C>(b\9_]n#.6n#Pi6?`mBKG,s?VH*8XO2%2ZiRAXGG^`%cNU;^c56[r)\G"Pa:&/K_ja^RJBHYa=>H%;_8"s)q4!t6;]`D3?!k*[FOl=+cs44DXWDu2eD12Uh2jTRrLC4Vfg5fcKn`Ws26C1E0pg;:VL@"qec93nt\hFtHl3'm%@,1gO@d#q&Jor6tTS<>g'L]G2d3<@;BKef*jD$Gp[9=b%]UeO9dh87D\79MXQ8+YD/ba_klp$">SA.tcn%K06^J#4Q\dQYe(W<;#43B1(G3#i0`d2DS8K>So;'<.<9"f5n3*rD:127%G$kYc)ZPt6@)Pa,tu4FC/Iq^qD9cC*-+GOpJ,hYHl+._`kCV_`)b`2L1:(TZpI#\ljQG4f/3_&MCj&e]k^oJ"psnp%LJns+7jnr7unMbeG'u"7s8DR5@N;.^4rdkQPkPR&C(@448qq8fR]']`=Q1od\@k&e>tEWaG)=0omJH2lNb$_$l.%.qUD)HB[Vr&)"Ef-em4Wj$tNnhl!nE16m$-7_2Ns+lU/t^)M@H)iMm-$>4PH1^.eU"KM`-*L+cOO0++: +endstream +endobj +722 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 721 0 R +>> +endobj +723 0 obj +<< /Length 1733 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gb!#\?Z4[W&:aGP&H"4-5g>+L84a[',\c'l6W9ecMZTB'J:oJ(c`1cSFO8TJhV@QpqmRg/mN$dKY/^T`[g5UPEC[iW`5KL"6QaNSp\3M4<31J5\%7%(1P,*?Fh@eDHYCMuV9D+W'3:_;?DB3DC_Gg>?G31D8cXAO(H`^Q%@Pc*4Mlm=.^\RK"&qn`NI8<"Rjp]"8)]"XYc1h>t:_CfN@WL24UVlb$^`48GaEJSi#6QRW+k,U0>7%^=_:c&WnQ@FQON\@O1?Pu7;'baG9d^9^i`_fIP#>5QDOG^;o-?A+@2,u^hi4HDI&BL'3'oPIP.m]ZEmRe&U#_3OQLK=_BAhd'j0n&uEaC0h/>SqTAdaTqIrQ4<-*N"3#&PVneRdDsi5@:=.!bpq#8cn(/\3]2$S7\UbS9/+^$$($m>H^,^WknahXAZsL`6N1-jOV8/bU`aYAoF&JT8GH;O5_:Q>aE]1,O>fZ%jOKZE&XGf+u?LoPc3\0m5)#A=E,'/-`:W>;&8T01g3S0T?9!+VK$@*bTDN)Lac_fdU5!\1P[KsNU63fQ]4;:bc5d9iBr_Y6rAbC7s"IL6Qp0`?*OVX4"/iW8YooP6fnXGL#',4ihA!?`MDYWnZE&>#dXXD5o>@NWr8cXYMKC!%P[GuHlTpg!l/9Rm-V+:jX+,HIJr6(I3iX673'aW#*N1,1oDgWnX\uU.?l0V@!/?gc/[;9Si'#/f]..`b;slMbhY1-aiWX")naK>N$NjSn(%J:MJrj[C(P.b04C-QGoPe<[$f1B_&)r64?mDrb\!_DWCg^mY*D^?:]7^bRoQX!VKjUspErgB%eF-1>q^ESnp.H(Mm.B12N(AUU=G8=C%f..6%KcE2#YME8g$ihc-&/nSQQ]ZTR/Cp$<\]*H/)]GCL;pr.t68M_(J/"ooC1E&YtMONg[11;U3%BU)7,f+T2PjQ$Q,k2D0rsh]44(5g6h=>tk:2^=CebI\5`D#2>TsJ6as#YhS9MaW)U!N$Ma]9]g2S_<(,JI5&5#QU6qr.T:a?b*e@;n)3_4^(c!Tn5"pABgB0J$]taAF?eZglm_1T3Z@,RSjohT6(8)F\jZ%Nq(B!N[4m2g`pnQP^-En7W7CgRjgs]5'S6e?f]RY1E4U9jE>@~> +endstream +endobj +724 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 723 0 R +>> +endobj +725 0 obj +<< /Length 2307 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gau0E=`<%a&:W67+P_anJ@"BdprQ:41b%G8;3[ui#ZfGI,g<=Md^&n$B=T;^&7sB?$3PkAe'@=HgnT7!bq;5+L1MOW=D_]JZ("mN$%J7Lfd;6#)54hPN)acn3F=)ngj&8j(()Yg1Zipf5&&BXCpT*.D+O2kn\m4s)N?JJM2Jg?UB9[\';N`&[0'B0G[K#@mG8i33$FbYA^]RkYTF=Rhr!ck6-kP*N7Dj8l28Ukc="60X49@PgE-6(Se/OX[@j.2ee6J*\bouhLlcso&/j+oU),",n@?Ies&>?\V_fVCT0GA7e&6ri_d8O2d_p93dBkI-7S`E61UL!bG:C3!8W=[$"lEt5kBG-nJh/EM@p7GS5cZ/I%M&i@D2@gI(*=J^"gNed2hLC$Q52Q5OCFOlAD.L$Mu;N7&+c9dI/gI)B;G(X_`;e:'-THA"4roY43_:92j@tmO-`<>H/K#*Oh@np;o(#%BS09c[uW(4fLS@%;gg>,TY\0ni+@(LFPpIa$rGjdWcbJFr0<*-!3h)HAKfASWK+n]PR`%"7ha,E$&TnPp#+hTWmMMFG#jkNXHLeV.aj_jU:63n\dY.4GARg=gGqU;^M'A9BpP_hh?UYDX=HQA67`CLduaH$!idlLR_tJ8!AE3.3$F,AraFZfTUtY-(HEl`]E*?I'2fK@J[fh$\X2(b@'D6uVb34t7GnQ/s'AUO>\W@FT,mNNj:93]jp%lQh=h^=6BN-g`]Pj]b$:cn4OloaC-4ih#c(%HQ8CpDQ%s]\d+(tT,`%e-kQBce#+jfZP]J2`e&SGq_6\'dZE]'"i+p_j5Yp2"dF9LkENY'o5Q@tD0e+?4s_P:@[5\X9"337;bAagVlRB:UZ^8h(=+tD1,@AP`G5,@bX@S/=TPT6_l$jS]nJU?0[F]H?n`a-IFoerUF+!,p20M3e]fC:fad1Ff6'AWaKPM:i[$O6Dg&-5(Z0Zm^9$sj^Vb&a'>!HTo&OkbPiDqg=3k5/HX5(jEh21aOgSst>WuWjRA:GLJh@t!C"lm8S'CKNRi;B%(jNd#H%@+^Wbl+s]EC'/?32$'08XW&]HkLGo+FU/GmT">?BQ.2DQ+YL]#%i/(o7W-C0o7o@AE]t"igNo+DHI,+2t$O7C;;%BU9$867YoHE@LQ5TcPPqbE<:*7WZeg^^D(d@aj]VG,Q6/60.Y=t`Z)duJ&c/+U2Rof>1F7C0Q;R/YjKkQ$b_Fs_q;CKWiE9e%,PpU3uaTo4mqKki@^mOT^r4KSR?2hHbAOGL/I9r%^/I1Wn)JgjE23'"Q9ab4)XES;)PJagrjB?Gn*7$!R_hK?Ng"r3>_hEV;GaDsmAsdo`U&djo<#5%0Yup4F,%F(U"MNhf(0DIRW!=>j5=m(,<>ed3oO')e!s0u=48=$Do>\e]to5fOc@7mT$bKKj5O/f]:XNL1m4IdX]kHg'b"_s0Eh$T@Hg=?)'IQ\\hF(*0':ATAGc-]=/Tb/u+5Rk"Z8;8X=S].8hkCEgr@I2H[m&0C&?8D`o.*m:`s+kq(sX=+#97!UXKN:$H#g*PF8RM<$&g`8"NS5$!a;\ojk50L-D*E_4j$kH6R:a!&sUji@i^(ZS~> +endstream +endobj +726 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 725 0 R +/Annots 727 0 R +>> +endobj +727 0 obj +[ +728 0 R +] +endobj +728 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 404.48 112.707 493.69 101.707 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A << /URI (http://www.pcre.org) +/S /URI >> +/H /I +>> +endobj +729 0 obj +<< /Length 2681 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gat%%D/\/g')nJ0iO0?bBDVAL$'%.*7"Gcn!4c.htn(GOY^.;(XD++!`'g2M^NKE=Qm[OoYS^j48Jg^UGnASG'sTZ>V.lC-qUXpB9br!`NJ/<=f^Gm@[+2e!EAqee^$9,SoTg%SeZ(ASbUD97D3MZMJnk7%+U2d]sO:DYhm`aXuWO>0m4;4iC\(Fs%JaY1,T]_0#G:k>[8R5H/>i_@tZ'H\Wa'Gjm*AV9i+HWJ2OI^%$%AESinl?If,:roY,-8+=U$r.(RUZ5*.soc,$..>11@7hJK_A*0Z6MO@blW7""c$UCc\\%Z>9)mIERb54,m]r?4h]':G)(gm$cAe(U'M#Ad(-,Gn6eYO:;K@D=agsmf0jfETfa;T-mI=!]A.Kk!"%CRE)f6aUV'Ns7.dZ^r<+Rgod/ET5HV6&9?-r$c7Y9Y(iQE@A&bR(Bud%'Q]:\>\C)th9G?ZYjpeZ!-aWsSj@$TP7$3NaE^Mc24`:cH)Bo?i=0PoC7j`OXf2ZNo99mTA$EbsuZ@4<39D9bUWg3iOK?EFgDP74^bS$Ue>"9X_R-UN?f9kFaIK/3dB8$;_2g0RcQOh3UM3QS0?g/?;KAI,WQPY-W3%-*jZMi8Alc0AFDBoFQoI%R'5g0K:GO/$R2L2t1jl5+%b8E$l&)Ek..q93K,9PQad<%td*7=4,IXJY#b>KLMIoAYsfIU=S78[I`r'?'Gcespd=rt!f5j.B8$ng(:IU/2b+t'JE:MW^N;dU3Y)c\0j6E!`>OaAZtJ,/j+_t)!qI(mtqp;cG*rI+A$47,T)XQc2A+T0k+P#>>>TBm51K]((r5Mb2?D\ir9+*Ou[,_9R?r^n2X*fMV3H&A_6l#Oi;9O(-6`+3n62S0Ug5csOoEl]8(!b9Nf4_G.+4L)5\er)7n:%E.h2MCY^qrZaBjjEqGV2oAP+HiHK+^@f0k\G$@*W;*U"3)Bi\W.q)-LuQn'j)FcCE=uUW!F(.rFjpbE"Wr)hlEqoXW2W#,a>HSBX'"s(Og]1K8jkb"NL=93>>di2Z2746'usK]q8\R_"';[Qq'W<1*qsJqfG/HYK48=[B*Nm4ckihB3K(Z]mBD6)uQ$!J>4@.q;+O;'\6iY"Pf)83V8,Zt"P:&qb@UIqes$'%U)F`4O;[pFc"g1'!AYA2Y>"?8MXRljPWo4Z-QdD2jTM(9CW)Efa8+XKKu&2_WhM>)D"#'E-Li\Yed'25WM<7A`:i?HU+7o7t+4:&:]&o#-3)FlOCki5^>=XGLcDf\dd6tQ$l/[oZS]03;^X\5,61[gLb`c]PCVNg,*h[Ek!b9BJ,`G]W`k*UX',RMr&),kl6'8;ob`&X2H`5/KAQ6HQsLrZ[f+]II!bEs.ugr1qL7qrDnp7$$J?.Pu#F\DWn@>1bIGrBfpPa=dlW'6CZNWf#>3:71>1M:`G#'\DbVc\G_^G>nULNPLd@PQS:-,aCI?9o<"T:e]U\M9ttJCZ/2KG'0S#Db@"-4]V$M(BATR@9NtEd\")IJ&,.UeB\2ciGPI0:9ru$G*,=oWY*""9`um7I(HD13cQPq_1))!lV8$oRAZKiqN~> +endstream +endobj +730 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 729 0 R +>> +endobj +731 0 obj +<< /Length 1712 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gb!;d>>O9K'RnB3E7%\f#pu7%DilM$Cr1(j;V8ph=uG-d@#p/PNpX5%5lQ1m@lp8:JUk+EYQEZpI%'4OrP%a.kD-a`j`(>-!*/\id>Y6VMjbT>s3+)/QN6(ET/<#t`Cs>^VM1]PXRam"%*SW2K;W>)Ben6EQjR?TG]]jP0H/BX;aKZ2D\kmgep/_KRO6%e3mR7_C#sP<$5ps7,2cHMMG6RpAe$7gD8+#+KN@3fObAq)-Gn,:SK^-BqZF4_'A*_k-A1M0J9d0eb`1k+bt(%O+99]mkoFQ^*,%a0qB#",_eOk9/\AQDfk+=3f5Ufn:a@rJ4W@?^AQdmaAcmcNj:_2o@fp=(ck#<3@0>dL6uDfc?j#\'<6aFs@0=d.gHJI#-\R9G3C873L"5eb8k,Hh6c??=^^/Emnor1@(kGS`![B@2":@;r:%*SQ#fJS4D7Q`boQ?9idNAqXoQDl>!1"b:KnU>lJr;%MNct,[.,lXUbG(],BED)'YI)g>oSJcU]SQAXU1i\EEMV)8?-eQGZ-^c_76:PS(SR^bC3kBddEPi%9`aok$/PK,//PQ4!S8Sf$#'`r+eJGVb>4?M4(f42:06_2kOf"XC7=DG3\X:E2"Oh!)N?-[h'POip[nPE>ska-d@<"dn21__^O@aMP=>:<>HO(<3&maXs0hFU%)!r1[:Y*B8,5BJuj=M$DLud?9H&QU%5hF=>AalY#EhXdA)^G*Pj!GFsJW(G9Zb$/n?">+?`2\V>Pd;]#@bG#s;\=if&lIq;_:)DlZTCL*>8r9Pgdftp/Ld'P*c>S%)h:F?97I$ifoK5~> +endstream +endobj +732 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 731 0 R +>> +endobj +733 0 obj +<< /Length 2441 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gau0Es,YpC('"73$84Z,#4QW,^?^:M8^hIE@CNCr1CRB?JsL,?Lb6._Fa$=%s*[\?,ebYlS0"mX5[]%/5/-JmGi(*Urqo,Ej.$:Z`VM'OD6EXbJ:Dsd_Z7J'-s.6rZc.Cemr,t-VUXm=-4&HY@cBpdSg(qDP^^q$a%?fLCf0J$G:AV(hk/r7sPorF%(#\S`3b^Kh#ELcNdH.K-FlY;jk_UKPfu=WGHNqjOE*-D,!4>@.8Koj+WH@TL9gX:oef)Db^\m`#dCI,CG>:4j4`Dr1Nh_67/R)Wnl'=r9YdVj-!&P@fK5+72,(D=mm\%lDQKMS]c%6G_QHT%hcb++`oIlF-`+[doRt\.e@]gn,FBPnu!q_CY*`G%)/\cLu]M(u7Q%7G%Fj=Gf5^,mB7WpJMr"d?C1Fa%!Li);GFih*bKo6]/?G.>p>Z0\=0IbU>1_K`N34\Zp9lefBn+m80Pl`k\N:#0%]_!M=:l7[2/(f^[KJY5a9^:bbTiuF*'f(0J=ro&"^5mo[&t?26IbsIO/Q+O1A,n3iCF:lHm?)gl4rBW7Org*RtZVKR3bGG_Hp(MC:?R]X@n-CZ4mLIiaF@"l,B\N]G[2^?gB(s_Hn*9OkZEYU\IDb^8q*P'#jB3'9&U0oDRD=ZsS#;`reeJ.]@BaW$oAZcK#(HMLZ(fb,s$b[#hBqlk0];YB;3;W@X>j\YMaHl>^;5Pa-OQXW0Ic!D3Z:X;0i0a5(-;AD+ta9LSFQ8dhM!6:+0+jC>%?7-T8fCtGST4^mE%5AB2NJafg+eWhP==e*E%K[n6/LGp=3^3fV(?A`qbnA&?M>WP=+8nhG^h3"G3EjkLol[]W*21Rr5&EO2_@f6@4G2&BU_o?ue%BJSV9*6'h8\ftPH7HP'LnMpLp.jEO_V-\U'`+eXOC3u,7=0gaaC##Z;%"NEjD('gSZ,,>S^fjLV.^Bu!e8"V2$p!Wq:TmcA=oY_(I8c%*>+oBeJ'lL^I!EXG]^h:^6^+ZU76H^gNtlX4R[7Ops^d0Ng^W#eRf>%_@_@Y^/caNKFAW.W+88mC)`"*YF+d^J\.F1Y?;.sQp^`_-]ZmWG()HcIJ_P93@]&M,j@*4-HNTVMojY+bF>^@sQ[*I*in\f(!-f$2qkh//a`o1VC5oJ8tpoEmKh(t7%QhC>#Zna8%G2'XgIp-N")dOUr<]:XsZUS<1pd91;XC%RU.AjY.Nhj@-,&4t#qW;*l;&s'plQ.TTg`!^Ph.'_no`.N2TRqB+-Rj=&@2*d$7?j6fT>4"lln]dE[8D;4;D147UVI`$3,Y?2@k.$7ZEC9*Q+>flEEY%[3]Eu2b/[C$c9sW.8l"+@68n0Z>G4"(ou#J0dlMF;5aVI)1qZ`FF)DKWJ8X+[Qk:3immO-j$:,7;>>tJ%\:XJP33PnSjEJgZG)\O0Ns8%+"8NVqV`hnSgYrSDh%S-qdK$\h*m-j\M6.$8_hk-2`&pkDfOeg\_$rfR,3gl9\c*>)c?^W34dB*=R/'IH-a!A9FC].r8^5iZO[j0GN2&NWrqLPh%j!0@m,6(hpesDI2$e-?eb[X'aU9TjF/%&@R?d1:dVD$"f1sK17TS1Q?kTjdb39'g%EXQDKi.ZS^tf&mXs+1,C')-EW4A76Z?qW:diHmsF6^Xj(Wi'#V8us+Q1iqmj]i9Murln)YJQ"F4Ol'33M)!#$o[0oLRW2EE6NK6%2J%\XO-$l#tEoO$/@ +endstream +endobj +734 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 733 0 R +>> +endobj +735 0 obj +<< /Length 1283 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +GasbZD3*[7&:hOe/#&4WYnH6^c$?iqa0N6[:2mQ`HgRf7O@]j_$8Il,YcFf(]hX/<[`MQM^;Q*"RIPOA1\]#Tk>.+H]>-7dh8hGH,Khe:B,SG.R2:1bpAuR")Lm^4-nX\Sn_WsA4uJ@l:T12t/aeS4N8t?_":`Q>":66;D)P:>#b^3N;CX<=[0,?3NX(Oub&_l+d>jMBW%1d4QpW_F-K?)m*cu@b;i^X'QB,`-T[\I2"pJ'q,7PfOX0JEod'jfAWVn]u@j8&=r&cFM!*=P%_f,'?XX2Q9O-1fYgT^R4h6QqL?gP9O848]An@FjVn+jrOuCYf/p*d78t,r/:WiGN7M=r<:BKu_H9@<0BCAePnjqK7$3,62:,Gj4CBUsXr3mAHb:K<#[maR:mlGa^@^R.ug!]ijd+FJoo'2.W\aH;W@(b6VPi*a6j2H3EX1uY3D<1m9"M?QQEkRdk9,gG8kfT=s/uW/-Bj1[RgiX;\]B7BDPpX7A<"MRC<>'/G%hGp'o1dUP(9jLUf>>8bO?/.YUK-o`%6_gJ]YhAu9;O=IU7t-QTGa=/*,\3o2[nI!QjniKKb4NBYa=u8W@#u9~> +endstream +endobj +736 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 735 0 R +>> +endobj +737 0 obj +<< /Length 2623 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gat=-=c_UQ&Us1UiOAFZBo_UkhraD0P@T[oHP-JG?pIr_2D[D,3kEB34sc=(X4X`E>o596:FreRl``YI]\17f5mOIo1MpdF#;6nmkX8gt(&To=fQC%!>eX[L(nG[U[<],@@Y?([/D>sfUKe(bTCQ7YiT$o>,LFi(-[EtCOJLG&k+8Om\[QV^O6=_5f+tX_&U+5aJ7?1BsaB`\cdoLR+bJU`o=CMi="U_G5XiGJm3)ag]OklbYO\*%.t)cDWAbbl(X.M7VB\+f;n.r4uYQY=G4^T]uR6_uk=j#OuIj?^s.pKl'f,\\f\Hqkq!p/t\WWs02=uC&P63,D/k2OU2U\E[0:`=6#`>H21i]Eat\6nSAF([q19e3oQ(+)\q').jWFY"$4K)1G;l:NfuX&=%F+Qs82ZM94A's&VcP0mYmO)Ghu_9;R2N=L_LN&994ct'p)'c[XURen,;t@pTpqBY,^15bg,2q0-I>)6"EHD@:5U3E.o/!r-uB4CqkJso)=O$l$:ZaWgN][hThWMaATTZ:HNJTJ*,4ZYGuV9KPV2b'!gBiHBo*NX>F_4NIZhK2&(F%#]#km]E.5U7\hfc.C-9.Q&IL+g<4$4q*C-u\gf++LnYg).`1TY+%.?6P-F*f>:BfbVC'p]*=.?5Q]3k@^[Gp.5T+[EZX&4AlY+XsT.$qM->9;g!9I#$pf)AM!2k%688B5?7oF,8?IH+RH-GAV[P(H[le"'B;C=4PNF'*kgIs_Ka?f"F]cT6Ep=4d%T(+6qOr2/,Q`h$iYMI=4cegp'(Ge/!opHas@cUAr'oGcj02KY@^qnFG/r%%A8$dD+TNC>hBZ\>95Ee[_b:.Un08Qfn':uDhoG.?X-Ui^ZDI14K%(oAB+)rl!S1M6d;ijMtQ=Yha?RZYRB*P&F9Q]#r%6s?M(ONEa'EmE;!_Lce\>@@gW]VLk"-M*1+\DK_hVTqd64WTLNum8;8go5lasJ'j-*qOA=NB9n4$Hk!5r"QmFA6^TNQd]GV$&7jMhmLDY>WH3#`,1O#Z_Uj(\QiT/<9XY13K:NoMVVND&S\e')!_m;,)KNZd]RYFR-%TbXkg%4_r34edLQ=GOp-9s/?nM,ml7X&m1mM0d\JdZ1j)`5dsj3D0We<4IZCR,ou6O>gf10">"_ujeb0?]^gI>`AZE5$eO.&hhMtT3_7SJ$ja5q[fN0J=k.!SE:_i/gTIaY.ROkTh6eLi]j'g^@(Wil[lQa"OO=pa"fT#+3,biamO;bb#Qfdo+-">;EA/Ge@sc&QWi:Q2LT7db/6hWmlEe[]83IqU"NNJCr>mR`#>XI#F'^cd^]X,'WC:D>7$Lk[_I?k2DNV[%'E$-!$XH+li&b.qK#ed$FjH[`a3IAmD(-Q.ku_T&E7@hg48=QRh6@a3;tX(R_M/Be'ZlO\L02YB%`BSJZDS0_GO"LCZObr(<="?K@[$b09kKQGEat'>>ZBp;.M#pHA?1cI2FE[o-=g$i@[Y%e7l&/Y(V?26Xp+*^fLYf([u"V?b7]#1E)V!O^9D5**`'^[FS+hkTkh7YGQ%D3Id[(EnjY9[l0q,+%NG\p;kHg_M<,oJ=sXYTM+@K6WfXkI1-9t#&!1CcB$3\NG!)C.,79eK>U1u8oTU(O4Wa +endstream +endobj +738 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 737 0 R +>> +endobj +739 0 obj +<< /Length 3095 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +GasIkD3*F0')oV[_H>TK"@uKbZM`-hQQhdN6Z^pm>m*Uj&5X!Vo-0BU.,":lqP3gH6d&UH.!?Yo_r87LS9N`"TDju!Z:-O@D0L3qg&5O;KBc_P8#L(E?5,7^*Bfl"j1U$4<0?P+=6G8J9n&LK2[,i>?6,ipe5`%D[QoT;]CJOIqn6qSBRXLu3N\r?9JV+KhAG@pe>$mW5dWHC#SUe1[cK'7,XS/YZ#.71G0Jah+7BfuO:1FeU=C,P8ZSOpr<9C@b`0c]kFn7-C'at!d>A>F0=2c8J.lX!m;)s%Q]l/62Y1JP5ebGP4oF6DfAHGtJ<<]tPC`'?:8gLMN$Ja0Ah?lLP&Wstu=!2P!VZC^1d"_iWUf:)$h*T*:FIX)H,+1MM*Q4A;BK,3f0jc9\.U+Kp(]`3NWfNL.#T-toI(@]5?\o!`f'm?*L"koN)*]*8n5geA9K_sJ(4-ReJYJcej%NA@`THC!%MfG!sb5AHl>q:W'h;=,r&1JqWM0aoIqIn>-T*Coc&jJmR;u3Ead\8E/U0VN2\#X;bC7F699-.8W)PpU9FDmflt0k+&n#3/,um<_c+"#fj(*()"*L3l`-]08'7m@hS-aa6Pc9[gc17PJ=X!:/&9Q^pYfmC\]*(RoOq.'Puc`iiF>A(I7*]*:.ibCQ'p-rO,J,LUnA#:dQ:`Ws0!<*+n^HhtfC40nmSiW.R>4U1[`atY/1F/!f/_(S7sBN]GQl.H(m5$M"RiR*dt+@+mVoo4t\@7j0#:mW\LAK=EZV*(S]^a[OdPi4o_"m`F$jUG;65oh:bX-/IjS>tJ#Dt#pW](Z2`Xt.MiNdZ-H09!ZMeJf$NWqV>CSQ-Z@#E&i!U!Xl3`(3VVl]kPllE/GP&M9\HEJcDq.i;2]H]KiiRfrIRBcsK2L/?Ii""!n-ciQ;bQFX3M2[r4U,,7O$XJs5VMi$sm^/co.N?*[7rq#Zf+'^q."P5=_lB[%$Lcs5t2c(R&i9uhPo#5T=Y$s66IHIE(Qeo5?ktN'MB9n(83J8dI>8^l38q@2'!qX!Z!R[G&&pO4,h5p[sW`X=$T"28N4cCAo'29^sqP"X`P8ELEk#=0$U#aPI]$58#Q5<-XQDL?dV:H$U>#bZg'T6G*R_?<$kakArsSo0^Ve'qKG8SMYPL!9^U/f[\G1^p(rOOet6_EaVHJ?)9J=FuRhKt@V?X+\oDXM0r.rq>=&:[e;^lVg&>f9&_](E&R,B>GlLlk6=BP:`chkeqV_4f6+.`qT:U`d*pZ\\<"F\h]^F7U,p6U2Tg#JcbsBT&E;HJ6+/0M!n^dOsO#:bfIEr,$-;orW!m3DJ_+[WLt\lU9eNOOX>jIMFAh!g)=o'I`r`,s?\J3o@-U'[.UaXg.-Y03,%)4cpsGY9?L:phFM/$d>YO34HUT9^5t]YtP1#<2UMPe9.1jb%'OQs:&$E7+aO]kU8h2:K4FJ=%b5.X@]Y;]9hmf:6\lq0^5g0YiPKF""PV=5YEsf-cS-%N1D\TO`5O3hGOYFUfJ?AP)gNt>5Ytje`H%:N_@-QNtGl6Z;17V7mdsBb56[n/V"Q.4IGe]6"a%oJcA0!WrbCMPL>WcT1GrWeA.Wa:U=&J4e;RS_`/@Hdt&TbAEXN*ED,m\X9C.Zmr_TdYVgK/d+iCr87-m.pcNrV$-cc[U=jg4"MGpBRh5M%IbV@+Nkf2i&Krg`OY0l6+uoTBn$?+7<*oN:93dl/-\K;U[S1s!$e^SiMj]p>d:s6FOK0KAb-+56\@VeIUd(q/S&UA.>akpiNou"rS(H-&uG]74H+D7ALCc$SLNTbK@?![or3La_d>cri/9=(*ItsaAq9GN2RoSD=IorOuYQ~> +endstream +endobj +740 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 739 0 R +>> +endobj +741 0 obj +<< /Length 641 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Garo@4`B(/&;GE-$Gqu_QmF=]ZA't4'!qgoVN!Lc#\a$E'9P_=Utkb&Qa2eD""L[6c^jL\q[d\HjNB\RP[]6E-6[&p:djY;/R)@[O:i@DJZ9qucaE!1/_m!&b>Xq/H-4M3[?h):aM)lWfc5YT8^0-24qX/&q-MRsfD,2fJ#[.T?%Xk4:C+F+b9KEsKMp16R[ogVF9eFD^8/T:csZW1@AD2>2/:\hE$G<%g52[EOD(F6]W)%a.,p5C*2#3-:)>GX_"0@uTMqKXY,SUc7kcNMq+acIJ=t"l)Aa3m\(S;$a#n7>G\qN<_)Aa!&!S?/U\Q$PpV4C&PJC?T)9U/2Sd%I;>RaU5PgADbJ+*[MW_g[hQ.<8#j?DadFZq[k6g)\_L3,lh.h +endstream +endobj +742 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 741 0 R +>> +endobj +743 0 obj +<< /Type /Font +/Subtype /Type1 +/Name /F11 +/BaseFont /Courier-Bold +/Encoding /WinAnsiEncoding >> +endobj +744 0 obj +<< /Type /Font +/Subtype /Type1 +/Name /F1 +/BaseFont /Helvetica +/Encoding /WinAnsiEncoding >> +endobj +745 0 obj +<< /Type /Font +/Subtype /Type1 +/Name /F10 +/BaseFont /Courier-Oblique +/Encoding /WinAnsiEncoding >> +endobj +746 0 obj +<< /Type /Font +/Subtype /Type1 +/Name /F5 +/BaseFont /Times-Roman +/Encoding /WinAnsiEncoding >> +endobj +747 0 obj +<< /Type /Font +/Subtype /Type1 +/Name /F3 +/BaseFont /Helvetica-Bold +/Encoding /WinAnsiEncoding >> +endobj +748 0 obj +<< /Type /Font +/Subtype /Type1 +/Name /F9 +/BaseFont /Courier +/Encoding /WinAnsiEncoding >> +endobj +749 0 obj +<< /Type /Font +/Subtype /Type1 +/Name /F6 +/BaseFont /Times-Italic +/Encoding /WinAnsiEncoding >> +endobj +750 0 obj +<< /Type /Font +/Subtype /Type1 +/Name /F7 +/BaseFont /Times-Bold +/Encoding /WinAnsiEncoding >> +endobj +1 0 obj +<< /Type /Pages +/Count 98 +/Kids [7 0 R 31 0 R 118 0 R 205 0 R 292 0 R 379 0 R 466 0 R 525 0 R 527 0 R 529 0 R 531 0 R 535 0 R 543 0 R 545 0 R 554 0 R 556 0 R 558 0 R 560 0 R 562 0 R 564 0 R 566 0 R 568 0 R 570 0 R 572 0 R 574 0 R 581 0 R 583 0 R 585 0 R 587 0 R 589 0 R 591 0 R 593 0 R 595 0 R 597 0 R 599 0 R 603 0 R 605 0 R 607 0 R 612 0 R 614 0 R 616 0 R 618 0 R 621 0 R 623 0 R 625 0 R 627 0 R 629 0 R 631 0 R 633 0 R 635 0 R 637 0 R 639 0 R 641 0 R 643 0 R 645 0 R 647 0 R 649 0 R 651 0 R 653 0 R 655 0 R 657 0 R 659 0 R 661 0 R 663 0 R 668 0 R 670 0 R 675 0 R 677 0 R 679 0 R 681 0 R 683 0 R 685 0 R 687 0 R 689 0 R 691 0 R 693 0 R 695 0 R 700 0 R 702 0 R 704 0 R 706 0 R 708 0 R 710 0 R 712 0 R 714 0 R 716 0 R 718 0 R 720 0 R 722 0 R 724 0 R 726 0 R 730 0 R 732 0 R 734 0 R 736 0 R 738 0 R 740 0 R 742 0 R ] >> +endobj +2 0 obj +<< /Type /Catalog +/Pages 1 0 R + >> +endobj +3 0 obj +<< +/Font << /F1 744 0 R /F11 743 0 R /F10 745 0 R /F5 746 0 R /F3 747 0 R /F9 748 0 R /F6 749 0 R /F7 750 0 R >> +/ProcSet [ /PDF /ImageC /Text ] /XObject <> +>> +endobj +11 0 obj +<< +/S /GoTo +/D [525 0 R /XYZ 67.0 725.0 null] +>> +endobj +13 0 obj +<< +/S /GoTo +/D [525 0 R /XYZ 67.0 596.2 null] +>> +endobj +15 0 obj +<< +/S /GoTo +/D [525 0 R /XYZ 67.0 418.75 null] +>> +endobj +17 0 obj +<< +/S /GoTo +/D [525 0 R /XYZ 67.0 333.7 null] +>> +endobj +19 0 obj +<< +/S /GoTo +/D [527 0 R /XYZ 67.0 659.0 null] +>> +endobj +21 0 obj +<< +/S /GoTo +/D [527 0 R /XYZ 67.0 512.35 null] +>> +endobj +23 0 obj +<< +/S /GoTo +/D [527 0 R /XYZ 67.0 196.3 null] +>> +endobj +25 0 obj +<< +/S /GoTo +/D [529 0 R /XYZ 67.0 725.0 null] +>> +endobj +27 0 obj +<< +/S /GoTo +/D [529 0 R /XYZ 67.0 650.95 null] +>> +endobj +29 0 obj +<< +/S /GoTo +/D [531 0 R /XYZ 67.0 725.0 null] +>> +endobj +34 0 obj +<< +/S /GoTo +/D [531 0 R /XYZ 67.0 690.8 null] +>> +endobj +36 0 obj +<< +/S /GoTo +/D [531 0 R /XYZ 67.0 513.35 null] +>> +endobj +38 0 obj +<< +/S /GoTo +/D [535 0 R /XYZ 67.0 725.0 null] +>> +endobj +40 0 obj +<< +/S /GoTo +/D [554 0 R /XYZ 67.0 725.0 null] +>> +endobj +42 0 obj +<< +/S /GoTo +/D [554 0 R /XYZ 67.0 367.666 null] +>> +endobj +44 0 obj +<< +/S /GoTo +/D [556 0 R /XYZ 67.0 725.0 null] +>> +endobj +46 0 obj +<< +/S /GoTo +/D [556 0 R /XYZ 67.0 481.55 null] +>> +endobj +48 0 obj +<< +/S /GoTo +/D [558 0 R /XYZ 67.0 725.0 null] +>> +endobj +50 0 obj +<< +/S /GoTo +/D [558 0 R /XYZ 67.0 412.019 null] +>> +endobj +52 0 obj +<< +/S /GoTo +/D [558 0 R /XYZ 67.0 205.969 null] +>> +endobj +54 0 obj +<< +/S /GoTo +/D [560 0 R /XYZ 67.0 505.266 null] +>> +endobj +56 0 obj +<< +/S /GoTo +/D [560 0 R /XYZ 67.0 165.282 null] +>> +endobj +58 0 obj +<< +/S /GoTo +/D [564 0 R /XYZ 67.0 725.0 null] +>> +endobj +60 0 obj +<< +/S /GoTo +/D [564 0 R /XYZ 67.0 481.55 null] +>> +endobj +62 0 obj +<< +/S /GoTo +/D [564 0 R /XYZ 67.0 242.5 null] +>> +endobj +64 0 obj +<< +/S /GoTo +/D [566 0 R /XYZ 67.0 588.6 null] +>> +endobj +66 0 obj +<< +/S /GoTo +/D [566 0 R /XYZ 67.0 130.3 null] +>> +endobj +68 0 obj +<< +/S /GoTo +/D [568 0 R /XYZ 67.0 375.2 null] +>> +endobj +70 0 obj +<< +/S /GoTo +/D [568 0 R /XYZ 67.0 184.55 null] +>> +endobj +72 0 obj +<< +/S /GoTo +/D [570 0 R /XYZ 67.0 672.2 null] +>> +endobj +74 0 obj +<< +/S /GoTo +/D [570 0 R /XYZ 67.0 455.15 null] +>> +endobj +76 0 obj +<< +/S /GoTo +/D [570 0 R /XYZ 67.0 297.5 null] +>> +endobj +78 0 obj +<< +/S /GoTo +/D [570 0 R /XYZ 67.0 137.65 null] +>> +endobj +80 0 obj +<< +/S /GoTo +/D [572 0 R /XYZ 67.0 428.0 null] +>> +endobj +82 0 obj +<< +/S /GoTo +/D [574 0 R /XYZ 67.0 610.666 null] +>> +endobj +84 0 obj +<< +/S /GoTo +/D [574 0 R /XYZ 67.0 450.816 null] +>> +endobj +86 0 obj +<< +/S /GoTo +/D [581 0 R /XYZ 67.0 640.069 null] +>> +endobj +88 0 obj +<< +/S /GoTo +/D [581 0 R /XYZ 67.0 283.378 null] +>> +endobj +90 0 obj +<< +/S /GoTo +/D [583 0 R /XYZ 67.0 689.8 null] +>> +endobj +92 0 obj +<< +/S /GoTo +/D [583 0 R /XYZ 67.0 419.95 null] +>> +endobj +94 0 obj +<< +/S /GoTo +/D [583 0 R /XYZ 67.0 198.5 null] +>> +endobj +96 0 obj +<< +/S /GoTo +/D [585 0 R /XYZ 67.0 637.0 null] +>> +endobj +98 0 obj +<< +/S /GoTo +/D [585 0 R /XYZ 67.0 413.35 null] +>> +endobj +100 0 obj +<< +/S /GoTo +/D [585 0 R /XYZ 67.0 134.7 null] +>> +endobj +102 0 obj +<< +/S /GoTo +/D [587 0 R /XYZ 67.0 588.6 null] +>> +endobj +104 0 obj +<< +/S /GoTo +/D [587 0 R /XYZ 67.0 292.35 null] +>> +endobj +106 0 obj +<< +/S /GoTo +/D [589 0 R /XYZ 67.0 725.0 null] +>> +endobj +108 0 obj +<< +/S /GoTo +/D [589 0 R /XYZ 67.0 478.488 null] +>> +endobj +110 0 obj +<< +/S /GoTo +/D [589 0 R /XYZ 67.0 149.238 null] +>> +endobj +112 0 obj +<< +/S /GoTo +/D [591 0 R /XYZ 67.0 567.469 null] +>> +endobj +114 0 obj +<< +/S /GoTo +/D [591 0 R /XYZ 67.0 392.219 null] +>> +endobj +116 0 obj +<< +/S /GoTo +/D [591 0 R /XYZ 67.0 128.969 null] +>> +endobj +121 0 obj +<< +/S /GoTo +/D [597 0 R /XYZ 67.0 236.111 null] +>> +endobj +123 0 obj +<< +/S /GoTo +/D [599 0 R /XYZ 67.0 166.508 null] +>> +endobj +125 0 obj +<< +/S /GoTo +/D [603 0 R /XYZ 67.0 549.0 null] +>> +endobj +127 0 obj +<< +/S /GoTo +/D [603 0 R /XYZ 67.0 321.819 null] +>> +endobj +129 0 obj +<< +/S /GoTo +/D [603 0 R /XYZ 67.0 146.569 null] +>> +endobj +131 0 obj +<< +/S /GoTo +/D [607 0 R /XYZ 67.0 258.705 null] +>> +endobj +133 0 obj +<< +/S /GoTo +/D [612 0 R /XYZ 67.0 578.545 null] +>> +endobj +135 0 obj +<< +/S /GoTo +/D [612 0 R /XYZ 67.0 357.095 null] +>> +endobj +137 0 obj +<< +/S /GoTo +/D [612 0 R /XYZ 67.0 166.445 null] +>> +endobj +139 0 obj +<< +/S /GoTo +/D [614 0 R /XYZ 67.0 639.2 null] +>> +endobj +141 0 obj +<< +/S /GoTo +/D [614 0 R /XYZ 67.0 314.616 null] +>> +endobj +143 0 obj +<< +/S /GoTo +/D [616 0 R /XYZ 67.0 672.2 null] +>> +endobj +145 0 obj +<< +/S /GoTo +/D [621 0 R /XYZ 67.0 725.0 null] +>> +endobj +147 0 obj +<< +/S /GoTo +/D [623 0 R /XYZ 67.0 579.866 null] +>> +endobj +149 0 obj +<< +/S /GoTo +/D [623 0 R /XYZ 67.0 336.416 null] +>> +endobj +151 0 obj +<< +/S /GoTo +/D [623 0 R /XYZ 67.0 161.166 null] +>> +endobj +153 0 obj +<< +/S /GoTo +/D [625 0 R /XYZ 67.0 661.2 null] +>> +endobj +155 0 obj +<< +/S /GoTo +/D [625 0 R /XYZ 67.0 560.75 null] +>> +endobj +157 0 obj +<< +/S /GoTo +/D [627 0 R /XYZ 67.0 725.0 null] +>> +endobj +159 0 obj +<< +/S /GoTo +/D [627 0 R /XYZ 67.0 673.2 null] +>> +endobj +161 0 obj +<< +/S /GoTo +/D [629 0 R /XYZ 67.0 683.0 null] +>> +endobj +163 0 obj +<< +/S /GoTo +/D [629 0 R /XYZ 67.0 505.157 null] +>> +endobj +165 0 obj +<< +/S /GoTo +/D [629 0 R /XYZ 67.0 342.714 null] +>> +endobj +167 0 obj +<< +/S /GoTo +/D [629 0 R /XYZ 67.0 288.464 null] +>> +endobj +169 0 obj +<< +/S /GoTo +/D [629 0 R /XYZ 67.0 218.814 null] +>> +endobj +171 0 obj +<< +/S /GoTo +/D [629 0 R /XYZ 67.0 164.564 null] +>> +endobj +173 0 obj +<< +/S /GoTo +/D [631 0 R /XYZ 67.0 725.0 null] +>> +endobj +175 0 obj +<< +/S /GoTo +/D [631 0 R /XYZ 67.0 579.219 null] +>> +endobj +177 0 obj +<< +/S /GoTo +/D [631 0 R /XYZ 67.0 460.307 null] +>> +endobj +179 0 obj +<< +/S /GoTo +/D [631 0 R /XYZ 67.0 354.126 null] +>> +endobj +181 0 obj +<< +/S /GoTo +/D [631 0 R /XYZ 67.0 247.945 null] +>> +endobj +183 0 obj +<< +/S /GoTo +/D [631 0 R /XYZ 67.0 141.764 null] +>> +endobj +185 0 obj +<< +/S /GoTo +/D [633 0 R /XYZ 67.0 670.869 null] +>> +endobj +187 0 obj +<< +/S /GoTo +/D [633 0 R /XYZ 67.0 549.288 null] +>> +endobj +189 0 obj +<< +/S /GoTo +/D [633 0 R /XYZ 67.0 154.114 null] +>> +endobj +191 0 obj +<< +/S /GoTo +/D [635 0 R /XYZ 67.0 613.935 null] +>> +endobj +193 0 obj +<< +/S /GoTo +/D [635 0 R /XYZ 67.0 466.892 null] +>> +endobj +195 0 obj +<< +/S /GoTo +/D [635 0 R /XYZ 67.0 350.649 null] +>> +endobj +197 0 obj +<< +/S /GoTo +/D [635 0 R /XYZ 67.0 216.337 null] +>> +endobj +199 0 obj +<< +/S /GoTo +/D [637 0 R /XYZ 67.0 692.0 null] +>> +endobj +201 0 obj +<< +/S /GoTo +/D [637 0 R /XYZ 67.0 194.978 null] +>> +endobj +203 0 obj +<< +/S /GoTo +/D [639 0 R /XYZ 67.0 658.138 null] +>> +endobj +208 0 obj +<< +/S /GoTo +/D [639 0 R /XYZ 67.0 551.957 null] +>> +endobj +210 0 obj +<< +/S /GoTo +/D [639 0 R /XYZ 67.0 445.776 null] +>> +endobj +212 0 obj +<< +/S /GoTo +/D [639 0 R /XYZ 67.0 354.995 null] +>> +endobj +214 0 obj +<< +/S /GoTo +/D [639 0 R /XYZ 67.0 218.014 null] +>> +endobj +216 0 obj +<< +/S /GoTo +/D [641 0 R /XYZ 67.0 725.0 null] +>> +endobj +218 0 obj +<< +/S /GoTo +/D [641 0 R /XYZ 67.0 594.619 null] +>> +endobj +220 0 obj +<< +/S /GoTo +/D [641 0 R /XYZ 67.0 491.107 null] +>> +endobj +222 0 obj +<< +/S /GoTo +/D [641 0 R /XYZ 67.0 217.992 null] +>> +endobj +224 0 obj +<< +/S /GoTo +/D [641 0 R /XYZ 67.0 127.211 null] +>> +endobj +226 0 obj +<< +/S /GoTo +/D [643 0 R /XYZ 67.0 580.935 null] +>> +endobj +228 0 obj +<< +/S /GoTo +/D [643 0 R /XYZ 67.0 325.42 null] +>> +endobj +230 0 obj +<< +/S /GoTo +/D [643 0 R /XYZ 67.0 203.839 null] +>> +endobj +232 0 obj +<< +/S /GoTo +/D [645 0 R /XYZ 67.0 725.0 null] +>> +endobj +234 0 obj +<< +/S /GoTo +/D [645 0 R /XYZ 67.0 572.885 null] +>> +endobj +236 0 obj +<< +/S /GoTo +/D [645 0 R /XYZ 67.0 369.042 null] +>> +endobj +238 0 obj +<< +/S /GoTo +/D [645 0 R /XYZ 67.0 265.53 null] +>> +endobj +240 0 obj +<< +/S /GoTo +/D [645 0 R /XYZ 67.0 128.549 null] +>> +endobj +242 0 obj +<< +/S /GoTo +/D [647 0 R /XYZ 67.0 653.269 null] +>> +endobj +244 0 obj +<< +/S /GoTo +/D [647 0 R /XYZ 67.0 562.488 null] +>> +endobj +246 0 obj +<< +/S /GoTo +/D [647 0 R /XYZ 67.0 366.373 null] +>> +endobj +248 0 obj +<< +/S /GoTo +/D [647 0 R /XYZ 67.0 185.658 null] +>> +endobj +250 0 obj +<< +/S /GoTo +/D [649 0 R /XYZ 67.0 725.0 null] +>> +endobj +252 0 obj +<< +/S /GoTo +/D [649 0 R /XYZ 67.0 602.55 null] +>> +endobj +254 0 obj +<< +/S /GoTo +/D [649 0 R /XYZ 67.0 548.3 null] +>> +endobj +256 0 obj +<< +/S /GoTo +/D [649 0 R /XYZ 67.0 360.719 null] +>> +endobj +258 0 obj +<< +/S /GoTo +/D [649 0 R /XYZ 67.0 219.338 null] +>> +endobj +260 0 obj +<< +/S /GoTo +/D [649 0 R /XYZ 67.0 128.557 null] +>> +endobj +262 0 obj +<< +/S /GoTo +/D [651 0 R /XYZ 67.0 604.869 null] +>> +endobj +264 0 obj +<< +/S /GoTo +/D [651 0 R /XYZ 67.0 483.288 null] +>> +endobj +266 0 obj +<< +/S /GoTo +/D [651 0 R /XYZ 67.0 357.307 null] +>> +endobj +268 0 obj +<< +/S /GoTo +/D [651 0 R /XYZ 67.0 215.926 null] +>> +endobj +270 0 obj +<< +/S /GoTo +/D [653 0 R /XYZ 67.0 725.0 null] +>> +endobj +272 0 obj +<< +/S /GoTo +/D [653 0 R /XYZ 67.0 610.019 null] +>> +endobj +274 0 obj +<< +/S /GoTo +/D [653 0 R /XYZ 67.0 468.638 null] +>> +endobj +276 0 obj +<< +/S /GoTo +/D [653 0 R /XYZ 67.0 327.257 null] +>> +endobj +278 0 obj +<< +/S /GoTo +/D [653 0 R /XYZ 67.0 201.276 null] +>> +endobj +280 0 obj +<< +/S /GoTo +/D [655 0 R /XYZ 67.0 725.0 null] +>> +endobj +282 0 obj +<< +/S /GoTo +/D [655 0 R /XYZ 67.0 610.019 null] +>> +endobj +284 0 obj +<< +/S /GoTo +/D [655 0 R /XYZ 67.0 519.238 null] +>> +endobj +286 0 obj +<< +/S /GoTo +/D [655 0 R /XYZ 67.0 318.602 null] +>> +endobj +288 0 obj +<< +/S /GoTo +/D [655 0 R /XYZ 67.0 202.359 null] +>> +endobj +290 0 obj +<< +/S /GoTo +/D [657 0 R /XYZ 67.0 725.0 null] +>> +endobj +295 0 obj +<< +/S /GoTo +/D [657 0 R /XYZ 67.0 629.819 null] +>> +endobj +297 0 obj +<< +/S /GoTo +/D [657 0 R /XYZ 67.0 539.038 null] +>> +endobj +299 0 obj +<< +/S /GoTo +/D [657 0 R /XYZ 67.0 432.857 null] +>> +endobj +301 0 obj +<< +/S /GoTo +/D [657 0 R /XYZ 67.0 326.676 null] +>> +endobj +303 0 obj +<< +/S /GoTo +/D [657 0 R /XYZ 67.0 220.495 null] +>> +endobj +305 0 obj +<< +/S /GoTo +/D [657 0 R /XYZ 67.0 129.714 null] +>> +endobj +307 0 obj +<< +/S /GoTo +/D [659 0 R /XYZ 67.0 655.469 null] +>> +endobj +309 0 obj +<< +/S /GoTo +/D [659 0 R /XYZ 67.0 564.688 null] +>> +endobj +311 0 obj +<< +/S /GoTo +/D [659 0 R /XYZ 67.0 311.576 null] +>> +endobj +313 0 obj +<< +/S /GoTo +/D [659 0 R /XYZ 67.0 208.064 null] +>> +endobj +315 0 obj +<< +/S /GoTo +/D [661 0 R /XYZ 67.0 725.0 null] +>> +endobj +317 0 obj +<< +/S /GoTo +/D [661 0 R /XYZ 67.0 629.819 null] +>> +endobj +319 0 obj +<< +/S /GoTo +/D [668 0 R /XYZ 67.0 725.0 null] +>> +endobj +321 0 obj +<< +/S /GoTo +/D [668 0 R /XYZ 67.0 299.607 null] +>> +endobj +323 0 obj +<< +/S /GoTo +/D [668 0 R /XYZ 67.0 245.357 null] +>> +endobj +325 0 obj +<< +/S /GoTo +/D [668 0 R /XYZ 67.0 191.107 null] +>> +endobj +327 0 obj +<< +/S /GoTo +/D [668 0 R /XYZ 67.0 121.457 null] +>> +endobj +329 0 obj +<< +/S /GoTo +/D [670 0 R /XYZ 67.0 630.4 null] +>> +endobj +331 0 obj +<< +/S /GoTo +/D [670 0 R /XYZ 67.0 560.75 null] +>> +endobj +333 0 obj +<< +/S /GoTo +/D [670 0 R /XYZ 67.0 506.5 null] +>> +endobj +335 0 obj +<< +/S /GoTo +/D [670 0 R /XYZ 67.0 452.25 null] +>> +endobj +337 0 obj +<< +/S /GoTo +/D [670 0 R /XYZ 67.0 239.6 null] +>> +endobj +339 0 obj +<< +/S /GoTo +/D [670 0 R /XYZ 67.0 154.55 null] +>> +endobj +341 0 obj +<< +/S /GoTo +/D [675 0 R /XYZ 67.0 725.0 null] +>> +endobj +343 0 obj +<< +/S /GoTo +/D [675 0 R /XYZ 67.0 681.75 null] +>> +endobj +345 0 obj +<< +/S /GoTo +/D [675 0 R /XYZ 67.0 612.1 null] +>> +endobj +347 0 obj +<< +/S /GoTo +/D [675 0 R /XYZ 67.0 542.45 null] +>> +endobj +349 0 obj +<< +/S /GoTo +/D [675 0 R /XYZ 67.0 472.8 null] +>> +endobj +351 0 obj +<< +/S /GoTo +/D [675 0 R /XYZ 67.0 418.55 null] +>> +endobj +353 0 obj +<< +/S /GoTo +/D [675 0 R /XYZ 67.0 348.9 null] +>> +endobj +355 0 obj +<< +/S /GoTo +/D [675 0 R /XYZ 67.0 279.25 null] +>> +endobj +357 0 obj +<< +/S /GoTo +/D [675 0 R /XYZ 67.0 209.6 null] +>> +endobj +359 0 obj +<< +/S /GoTo +/D [675 0 R /XYZ 67.0 155.35 null] +>> +endobj +361 0 obj +<< +/S /GoTo +/D [677 0 R /XYZ 67.0 725.0 null] +>> +endobj +363 0 obj +<< +/S /GoTo +/D [677 0 R /XYZ 67.0 635.55 null] +>> +endobj +365 0 obj +<< +/S /GoTo +/D [677 0 R /XYZ 67.0 581.3 null] +>> +endobj +367 0 obj +<< +/S /GoTo +/D [677 0 R /XYZ 67.0 450.05 null] +>> +endobj +369 0 obj +<< +/S /GoTo +/D [677 0 R /XYZ 67.0 349.6 null] +>> +endobj +371 0 obj +<< +/S /GoTo +/D [677 0 R /XYZ 67.0 295.35 null] +>> +endobj +373 0 obj +<< +/S /GoTo +/D [677 0 R /XYZ 67.0 225.7 null] +>> +endobj +375 0 obj +<< +/S /GoTo +/D [677 0 R /XYZ 67.0 171.45 null] +>> +endobj +377 0 obj +<< +/S /GoTo +/D [677 0 R /XYZ 67.0 117.2 null] +>> +endobj +382 0 obj +<< +/S /GoTo +/D [681 0 R /XYZ 67.0 725.0 null] +>> +endobj +384 0 obj +<< +/S /GoTo +/D [681 0 R /XYZ 67.0 380.6 null] +>> +endobj +386 0 obj +<< +/S /GoTo +/D [683 0 R /XYZ 67.0 502.483 null] +>> +endobj +388 0 obj +<< +/S /GoTo +/D [683 0 R /XYZ 67.0 240.368 null] +>> +endobj +390 0 obj +<< +/S /GoTo +/D [685 0 R /XYZ 67.0 725.0 null] +>> +endobj +392 0 obj +<< +/S /GoTo +/D [685 0 R /XYZ 67.0 170.854 null] +>> +endobj +394 0 obj +<< +/S /GoTo +/D [687 0 R /XYZ 67.0 587.738 null] +>> +endobj +396 0 obj +<< +/S /GoTo +/D [687 0 R /XYZ 67.0 233.368 null] +>> +endobj +398 0 obj +<< +/S /GoTo +/D [689 0 R /XYZ 67.0 254.2 null] +>> +endobj +400 0 obj +<< +/S /GoTo +/D [689 0 R /XYZ 67.0 128.219 null] +>> +endobj +402 0 obj +<< +/S /GoTo +/D [691 0 R /XYZ 67.0 600.469 null] +>> +endobj +404 0 obj +<< +/S /GoTo +/D [691 0 R /XYZ 67.0 280.564 null] +>> +endobj +406 0 obj +<< +/S /GoTo +/D [693 0 R /XYZ 67.0 503.611 null] +>> +endobj +408 0 obj +<< +/S /GoTo +/D [693 0 R /XYZ 67.0 229.906 null] +>> +endobj +410 0 obj +<< +/S /GoTo +/D [695 0 R /XYZ 67.0 480.8 null] +>> +endobj +412 0 obj +<< +/S /GoTo +/D [695 0 R /XYZ 67.0 222.819 null] +>> +endobj +414 0 obj +<< +/S /GoTo +/D [700 0 R /XYZ 67.0 707.4 null] +>> +endobj +416 0 obj +<< +/S /GoTo +/D [700 0 R /XYZ 67.0 515.419 null] +>> +endobj +418 0 obj +<< +/S /GoTo +/D [700 0 R /XYZ 67.0 326.107 null] +>> +endobj +420 0 obj +<< +/S /GoTo +/D [702 0 R /XYZ 67.0 725.0 null] +>> +endobj +422 0 obj +<< +/S /GoTo +/D [702 0 R /XYZ 67.0 497.819 null] +>> +endobj +424 0 obj +<< +/S /GoTo +/D [702 0 R /XYZ 67.0 336.638 null] +>> +endobj +426 0 obj +<< +/S /GoTo +/D [704 0 R /XYZ 67.0 692.0 null] +>> +endobj +428 0 obj +<< +/S /GoTo +/D [704 0 R /XYZ 67.0 500.019 null] +>> +endobj +430 0 obj +<< +/S /GoTo +/D [704 0 R /XYZ 67.0 295.307 null] +>> +endobj +432 0 obj +<< +/S /GoTo +/D [706 0 R /XYZ 67.0 652.666 null] +>> +endobj +434 0 obj +<< +/S /GoTo +/D [706 0 R /XYZ 67.0 460.685 null] +>> +endobj +436 0 obj +<< +/S /GoTo +/D [706 0 R /XYZ 67.0 271.373 null] +>> +endobj +438 0 obj +<< +/S /GoTo +/D [708 0 R /XYZ 67.0 725.0 null] +>> +endobj +440 0 obj +<< +/S /GoTo +/D [708 0 R /XYZ 67.0 528.619 null] +>> +endobj +442 0 obj +<< +/S /GoTo +/D [708 0 R /XYZ 67.0 321.238 null] +>> +endobj +444 0 obj +<< +/S /GoTo +/D [708 0 R /XYZ 67.0 160.057 null] +>> +endobj +446 0 obj +<< +/S /GoTo +/D [710 0 R /XYZ 67.0 635.669 null] +>> +endobj +448 0 obj +<< +/S /GoTo +/D [710 0 R /XYZ 67.0 280.888 null] +>> +endobj +450 0 obj +<< +/S /GoTo +/D [712 0 R /XYZ 67.0 725.0 null] +>> +endobj +452 0 obj +<< +/S /GoTo +/D [712 0 R /XYZ 67.0 472.357 null] +>> +endobj +454 0 obj +<< +/S /GoTo +/D [712 0 R /XYZ 67.0 239.445 null] +>> +endobj +456 0 obj +<< +/S /GoTo +/D [714 0 R /XYZ 67.0 634.338 null] +>> +endobj +458 0 obj +<< +/S /GoTo +/D [714 0 R /XYZ 67.0 335.64 null] +>> +endobj +460 0 obj +<< +/S /GoTo +/D [716 0 R /XYZ 67.0 676.6 null] +>> +endobj +462 0 obj +<< +/S /GoTo +/D [716 0 R /XYZ 67.0 469.219 null] +>> +endobj +464 0 obj +<< +/S /GoTo +/D [716 0 R /XYZ 67.0 220.976 null] +>> +endobj +469 0 obj +<< +/S /GoTo +/D [718 0 R /XYZ 67.0 659.0 null] +>> +endobj +471 0 obj +<< +/S /GoTo +/D [720 0 R /XYZ 67.0 725.0 null] +>> +endobj +473 0 obj +<< +/S /GoTo +/D [720 0 R /XYZ 67.0 657.8 null] +>> +endobj +475 0 obj +<< +/S /GoTo +/D [720 0 R /XYZ 67.0 493.157 null] +>> +endobj +477 0 obj +<< +/S /GoTo +/D [720 0 R /XYZ 67.0 328.514 null] +>> +endobj +479 0 obj +<< +/S /GoTo +/D [720 0 R /XYZ 67.0 176.602 null] +>> +endobj +481 0 obj +<< +/S /GoTo +/D [722 0 R /XYZ 67.0 725.0 null] +>> +endobj +483 0 obj +<< +/S /GoTo +/D [722 0 R /XYZ 67.0 627.619 null] +>> +endobj +485 0 obj +<< +/S /GoTo +/D [722 0 R /XYZ 67.0 344.911 null] +>> +endobj +487 0 obj +<< +/S /GoTo +/D [722 0 R /XYZ 67.0 236.53 null] +>> +endobj +489 0 obj +<< +/S /GoTo +/D [724 0 R /XYZ 67.0 440.166 null] +>> +endobj +491 0 obj +<< +/S /GoTo +/D [724 0 R /XYZ 67.0 331.785 null] +>> +endobj +493 0 obj +<< +/S /GoTo +/D [724 0 R /XYZ 67.0 223.404 null] +>> +endobj +495 0 obj +<< +/S /GoTo +/D [726 0 R /XYZ 67.0 692.0 null] +>> +endobj +497 0 obj +<< +/S /GoTo +/D [726 0 R /XYZ 67.0 385.619 null] +>> +endobj +499 0 obj +<< +/S /GoTo +/D [726 0 R /XYZ 67.0 261.838 null] +>> +endobj +501 0 obj +<< +/S /GoTo +/D [730 0 R /XYZ 67.0 608.4 null] +>> +endobj +503 0 obj +<< +/S /GoTo +/D [730 0 R /XYZ 67.0 443.757 null] +>> +endobj +505 0 obj +<< +/S /GoTo +/D [730 0 R /XYZ 67.0 132.976 null] +>> +endobj +507 0 obj +<< +/S /GoTo +/D [732 0 R /XYZ 67.0 545.411 null] +>> +endobj +509 0 obj +<< +/S /GoTo +/D [732 0 R /XYZ 67.0 313.772 null] +>> +endobj +511 0 obj +<< +/S /GoTo +/D [732 0 R /XYZ 67.0 123.991 null] +>> +endobj +513 0 obj +<< +/S /GoTo +/D [734 0 R /XYZ 67.0 450.869 null] +>> +endobj +515 0 obj +<< +/S /GoTo +/D [734 0 R /XYZ 67.0 298.957 null] +>> +endobj +517 0 obj +<< +/S /GoTo +/D [736 0 R /XYZ 67.0 725.0 null] +>> +endobj +519 0 obj +<< +/S /GoTo +/D [738 0 R /XYZ 67.0 725.0 null] +>> +endobj +521 0 obj +<< +/S /GoTo +/D [740 0 R /XYZ 67.0 725.0 null] +>> +endobj +523 0 obj +<< +/S /GoTo +/D [740 0 R /XYZ 67.0 688.6 null] +>> +endobj +xref +0 751 +0000000000 65535 f +0000452429 00000 n +0000453263 00000 n +0000453313 00000 n +0000000015 00000 n +0000000071 00000 n +0000001248 00000 n +0000103319 00000 n +0000103439 00000 n +0000103534 00000 n +0000103708 00000 n +0000453520 00000 n +0000103845 00000 n +0000453585 00000 n +0000103981 00000 n +0000453650 00000 n +0000104117 00000 n +0000453716 00000 n +0000104253 00000 n +0000453781 00000 n +0000104387 00000 n +0000453846 00000 n +0000104523 00000 n +0000453912 00000 n +0000104659 00000 n +0000453977 00000 n +0000104795 00000 n +0000454042 00000 n +0000104930 00000 n +0000454108 00000 n +0000105065 00000 n +0000107073 00000 n +0000107196 00000 n +0000107518 00000 n +0000454173 00000 n +0000107652 00000 n +0000454238 00000 n +0000107786 00000 n +0000454304 00000 n +0000107919 00000 n +0000454369 00000 n +0000108054 00000 n +0000454434 00000 n +0000108186 00000 n +0000454501 00000 n +0000108318 00000 n +0000454566 00000 n +0000108450 00000 n +0000454632 00000 n +0000108582 00000 n +0000454697 00000 n +0000108714 00000 n +0000454764 00000 n +0000108846 00000 n +0000454831 00000 n +0000108978 00000 n +0000454898 00000 n +0000109110 00000 n +0000454965 00000 n +0000109242 00000 n +0000455030 00000 n +0000109374 00000 n +0000455096 00000 n +0000109506 00000 n +0000455161 00000 n +0000109640 00000 n +0000455226 00000 n +0000109772 00000 n +0000455291 00000 n +0000109904 00000 n +0000455356 00000 n +0000110036 00000 n +0000455422 00000 n +0000110168 00000 n +0000455487 00000 n +0000110300 00000 n +0000455553 00000 n +0000110432 00000 n +0000455618 00000 n +0000110564 00000 n +0000455684 00000 n +0000110696 00000 n +0000455749 00000 n +0000110828 00000 n +0000455816 00000 n +0000110960 00000 n +0000455883 00000 n +0000111092 00000 n +0000455950 00000 n +0000111224 00000 n +0000456017 00000 n +0000111356 00000 n +0000456082 00000 n +0000111488 00000 n +0000456148 00000 n +0000111620 00000 n +0000456213 00000 n +0000111752 00000 n +0000456278 00000 n +0000111884 00000 n +0000456344 00000 n +0000112017 00000 n +0000456410 00000 n +0000112151 00000 n +0000456476 00000 n +0000112285 00000 n +0000456543 00000 n +0000112419 00000 n +0000456609 00000 n +0000112553 00000 n +0000456677 00000 n +0000112687 00000 n +0000456745 00000 n +0000112821 00000 n +0000456813 00000 n +0000112954 00000 n +0000456881 00000 n +0000113086 00000 n +0000115077 00000 n +0000115203 00000 n +0000115560 00000 n +0000456949 00000 n +0000115694 00000 n +0000457017 00000 n +0000115828 00000 n +0000457085 00000 n +0000115962 00000 n +0000457151 00000 n +0000116096 00000 n +0000457219 00000 n +0000116232 00000 n +0000457287 00000 n +0000116366 00000 n +0000457355 00000 n +0000116500 00000 n +0000457423 00000 n +0000116634 00000 n +0000457491 00000 n +0000116768 00000 n +0000457559 00000 n +0000116902 00000 n +0000457625 00000 n +0000117036 00000 n +0000457693 00000 n +0000117170 00000 n +0000457759 00000 n +0000117307 00000 n +0000457825 00000 n +0000117443 00000 n +0000457893 00000 n +0000117579 00000 n +0000457961 00000 n +0000117715 00000 n +0000458029 00000 n +0000117851 00000 n +0000458095 00000 n +0000117987 00000 n +0000458162 00000 n +0000118124 00000 n +0000458228 00000 n +0000118258 00000 n +0000458294 00000 n +0000118392 00000 n +0000458360 00000 n +0000118526 00000 n +0000458428 00000 n +0000118660 00000 n +0000458496 00000 n +0000118794 00000 n +0000458564 00000 n +0000118928 00000 n +0000458632 00000 n +0000119062 00000 n +0000458700 00000 n +0000119196 00000 n +0000458766 00000 n +0000119330 00000 n +0000458834 00000 n +0000119464 00000 n +0000458902 00000 n +0000119598 00000 n +0000458970 00000 n +0000119732 00000 n +0000459038 00000 n +0000119866 00000 n +0000459106 00000 n +0000120000 00000 n +0000459174 00000 n +0000120134 00000 n +0000459242 00000 n +0000120268 00000 n +0000459310 00000 n +0000120402 00000 n +0000459378 00000 n +0000120536 00000 n +0000459446 00000 n +0000120670 00000 n +0000459514 00000 n +0000120804 00000 n +0000459582 00000 n +0000120938 00000 n +0000459648 00000 n +0000121071 00000 n +0000459716 00000 n +0000121203 00000 n +0000122952 00000 n +0000123078 00000 n +0000123435 00000 n +0000459784 00000 n +0000123569 00000 n +0000459852 00000 n +0000123703 00000 n +0000459920 00000 n +0000123837 00000 n +0000459988 00000 n +0000123971 00000 n +0000460056 00000 n +0000124105 00000 n +0000460122 00000 n +0000124239 00000 n +0000460190 00000 n +0000124373 00000 n +0000460258 00000 n +0000124507 00000 n +0000460326 00000 n +0000124641 00000 n +0000460394 00000 n +0000124775 00000 n +0000460462 00000 n +0000124909 00000 n +0000460529 00000 n +0000125043 00000 n +0000460597 00000 n +0000125177 00000 n +0000460663 00000 n +0000125311 00000 n +0000460731 00000 n +0000125445 00000 n +0000460799 00000 n +0000125579 00000 n +0000460866 00000 n +0000125713 00000 n +0000460934 00000 n +0000125847 00000 n +0000461002 00000 n +0000125981 00000 n +0000461070 00000 n +0000126115 00000 n +0000461138 00000 n +0000126249 00000 n +0000461206 00000 n +0000126383 00000 n +0000461272 00000 n +0000126517 00000 n +0000461339 00000 n +0000126651 00000 n +0000461405 00000 n +0000126785 00000 n +0000461473 00000 n +0000126919 00000 n +0000461541 00000 n +0000127053 00000 n +0000461609 00000 n +0000127187 00000 n +0000461677 00000 n +0000127321 00000 n +0000461745 00000 n +0000127455 00000 n +0000461813 00000 n +0000127589 00000 n +0000461881 00000 n +0000127723 00000 n +0000461947 00000 n +0000127857 00000 n +0000462015 00000 n +0000127991 00000 n +0000462083 00000 n +0000128125 00000 n +0000462151 00000 n +0000128259 00000 n +0000462219 00000 n +0000128393 00000 n +0000462285 00000 n +0000128527 00000 n +0000462353 00000 n +0000128661 00000 n +0000462421 00000 n +0000128795 00000 n +0000462489 00000 n +0000128928 00000 n +0000462557 00000 n +0000129060 00000 n +0000130872 00000 n +0000130998 00000 n +0000131355 00000 n +0000462623 00000 n +0000131489 00000 n +0000462691 00000 n +0000131623 00000 n +0000462759 00000 n +0000131757 00000 n +0000462827 00000 n +0000131891 00000 n +0000462895 00000 n +0000132025 00000 n +0000462963 00000 n +0000132159 00000 n +0000463031 00000 n +0000132293 00000 n +0000463099 00000 n +0000132427 00000 n +0000463167 00000 n +0000132561 00000 n +0000463235 00000 n +0000132695 00000 n +0000463303 00000 n +0000132829 00000 n +0000463369 00000 n +0000132963 00000 n +0000463437 00000 n +0000133100 00000 n +0000463503 00000 n +0000133234 00000 n +0000463571 00000 n +0000133368 00000 n +0000463639 00000 n +0000133502 00000 n +0000463707 00000 n +0000133638 00000 n +0000463775 00000 n +0000133772 00000 n +0000463841 00000 n +0000133906 00000 n +0000463908 00000 n +0000134040 00000 n +0000463974 00000 n +0000134174 00000 n +0000464041 00000 n +0000134308 00000 n +0000464107 00000 n +0000134442 00000 n +0000464174 00000 n +0000134576 00000 n +0000464240 00000 n +0000134710 00000 n +0000464307 00000 n +0000134844 00000 n +0000464373 00000 n +0000134978 00000 n +0000464440 00000 n +0000135112 00000 n +0000464506 00000 n +0000135246 00000 n +0000464573 00000 n +0000135380 00000 n +0000464639 00000 n +0000135514 00000 n +0000464706 00000 n +0000135648 00000 n +0000464772 00000 n +0000135782 00000 n +0000464839 00000 n +0000135916 00000 n +0000464905 00000 n +0000136050 00000 n +0000464972 00000 n +0000136184 00000 n +0000465038 00000 n +0000136318 00000 n +0000465105 00000 n +0000136452 00000 n +0000465171 00000 n +0000136586 00000 n +0000465238 00000 n +0000136720 00000 n +0000465304 00000 n +0000136853 00000 n +0000465371 00000 n +0000136985 00000 n +0000138779 00000 n +0000138905 00000 n +0000139262 00000 n +0000465437 00000 n +0000139399 00000 n +0000465503 00000 n +0000139533 00000 n +0000465569 00000 n +0000139669 00000 n +0000465637 00000 n +0000139803 00000 n +0000465705 00000 n +0000139937 00000 n +0000465771 00000 n +0000140071 00000 n +0000465839 00000 n +0000140205 00000 n +0000465907 00000 n +0000140339 00000 n +0000465975 00000 n +0000140473 00000 n +0000466041 00000 n +0000140607 00000 n +0000466109 00000 n +0000140741 00000 n +0000466177 00000 n +0000140875 00000 n +0000466245 00000 n +0000141009 00000 n +0000466313 00000 n +0000141143 00000 n +0000466381 00000 n +0000141277 00000 n +0000466447 00000 n +0000141411 00000 n +0000466515 00000 n +0000141545 00000 n +0000466581 00000 n +0000141679 00000 n +0000466649 00000 n +0000141813 00000 n +0000466717 00000 n +0000141947 00000 n +0000466783 00000 n +0000142081 00000 n +0000466851 00000 n +0000142215 00000 n +0000466919 00000 n +0000142349 00000 n +0000466985 00000 n +0000142483 00000 n +0000467053 00000 n +0000142619 00000 n +0000467121 00000 n +0000142753 00000 n +0000467189 00000 n +0000142887 00000 n +0000467257 00000 n +0000143021 00000 n +0000467325 00000 n +0000143155 00000 n +0000467391 00000 n +0000143289 00000 n +0000467459 00000 n +0000143423 00000 n +0000467527 00000 n +0000143557 00000 n +0000467595 00000 n +0000143691 00000 n +0000467663 00000 n +0000143825 00000 n +0000467731 00000 n +0000143959 00000 n +0000467797 00000 n +0000144093 00000 n +0000467865 00000 n +0000144227 00000 n +0000467933 00000 n +0000144361 00000 n +0000468001 00000 n +0000144495 00000 n +0000468068 00000 n +0000144629 00000 n +0000468134 00000 n +0000144762 00000 n +0000468202 00000 n +0000144894 00000 n +0000146305 00000 n +0000146431 00000 n +0000146676 00000 n +0000468270 00000 n +0000146810 00000 n +0000468336 00000 n +0000146947 00000 n +0000468402 00000 n +0000147081 00000 n +0000468468 00000 n +0000147215 00000 n +0000468536 00000 n +0000147349 00000 n +0000468604 00000 n +0000147483 00000 n +0000468672 00000 n +0000147617 00000 n +0000468738 00000 n +0000147751 00000 n +0000468806 00000 n +0000147885 00000 n +0000468874 00000 n +0000148019 00000 n +0000468941 00000 n +0000148153 00000 n +0000469009 00000 n +0000148287 00000 n +0000469077 00000 n +0000148421 00000 n +0000469145 00000 n +0000148555 00000 n +0000469211 00000 n +0000148689 00000 n +0000469279 00000 n +0000148823 00000 n +0000469347 00000 n +0000148957 00000 n +0000469413 00000 n +0000149091 00000 n +0000469481 00000 n +0000149225 00000 n +0000469549 00000 n +0000149359 00000 n +0000469617 00000 n +0000149493 00000 n +0000469685 00000 n +0000149627 00000 n +0000469753 00000 n +0000149761 00000 n +0000469821 00000 n +0000149895 00000 n +0000469889 00000 n +0000150032 00000 n +0000469955 00000 n +0000150169 00000 n +0000470021 00000 n +0000150306 00000 n +0000470087 00000 n +0000150442 00000 n +0000153591 00000 n +0000153701 00000 n +0000156757 00000 n +0000156867 00000 n +0000158081 00000 n +0000158191 00000 n +0000159906 00000 n +0000160032 00000 n +0000160061 00000 n +0000160254 00000 n +0000162326 00000 n +0000162452 00000 n +0000162513 00000 n +0000162686 00000 n +0000162857 00000 n +0000163041 00000 n +0000163224 00000 n +0000163403 00000 n +0000165664 00000 n +0000165774 00000 n +0000168039 00000 n +0000168165 00000 n +0000168202 00000 n +0000168341 00000 n +0000168459 00000 n +0000168533 00000 n +0000168669 00000 n +0000168787 00000 n +0000168861 00000 n +0000171836 00000 n +0000171946 00000 n +0000174058 00000 n +0000174168 00000 n +0000176588 00000 n +0000176698 00000 n +0000178749 00000 n +0000178859 00000 n +0000181693 00000 n +0000181803 00000 n +0000183958 00000 n +0000184068 00000 n +0000186554 00000 n +0000186664 00000 n +0000189416 00000 n +0000189526 00000 n +0000191022 00000 n +0000191132 00000 n +0000193399 00000 n +0000193509 00000 n +0000196053 00000 n +0000196179 00000 n +0000196232 00000 n +0000196443 00000 n +0000196651 00000 n +0000196842 00000 n +0000197031 00000 n +0000199387 00000 n +0000199497 00000 n +0000201711 00000 n +0000201821 00000 n +0000203761 00000 n +0000203871 00000 n +0000206176 00000 n +0000206286 00000 n +0000208948 00000 n +0000209058 00000 n +0000210862 00000 n +0000210972 00000 n +0000213238 00000 n +0000213348 00000 n +0000216202 00000 n +0000216312 00000 n +0000218611 00000 n +0000218721 00000 n +0000220917 00000 n +0000221043 00000 n +0000221072 00000 n +0000221273 00000 n +0000223244 00000 n +0000223354 00000 n +0000225516 00000 n +0000225626 00000 n +0000227950 00000 n +0000228076 00000 n +0000228113 00000 n +0000228286 00000 n +0000228470 00000 n +0000230564 00000 n +0000230674 00000 n +0000232750 00000 n +0000232860 00000 n +0000235131 00000 n +0000235241 00000 n +0000235751 00000 n +0000235861 00000 n +0000237247 00000 n +0000329702 00000 n +0000329812 00000 n +0000332744 00000 n +0000332854 00000 n +0000334570 00000 n +0000334680 00000 n +0000337147 00000 n +0000337257 00000 n +0000339498 00000 n +0000339608 00000 n +0000341544 00000 n +0000341654 00000 n +0000343935 00000 n +0000344045 00000 n +0000346382 00000 n +0000346492 00000 n +0000349413 00000 n +0000349523 00000 n +0000351627 00000 n +0000351737 00000 n +0000353957 00000 n +0000354067 00000 n +0000356513 00000 n +0000356623 00000 n +0000358765 00000 n +0000358875 00000 n +0000360666 00000 n +0000360776 00000 n +0000362770 00000 n +0000362880 00000 n +0000364709 00000 n +0000364819 00000 n +0000366130 00000 n +0000366240 00000 n +0000368081 00000 n +0000368191 00000 n +0000369597 00000 n +0000369707 00000 n +0000371926 00000 n +0000372036 00000 n +0000374142 00000 n +0000374252 00000 n +0000375310 00000 n +0000375436 00000 n +0000375473 00000 n +0000375652 00000 n +0000375864 00000 n +0000377925 00000 n +0000378035 00000 n +0000380454 00000 n +0000380580 00000 n +0000380617 00000 n +0000380811 00000 n +0000381004 00000 n +0000382606 00000 n +0000382716 00000 n +0000384923 00000 n +0000385033 00000 n +0000385427 00000 n +0000385537 00000 n +0000388394 00000 n +0000388504 00000 n +0000390623 00000 n +0000390733 00000 n +0000393319 00000 n +0000393429 00000 n +0000395815 00000 n +0000395925 00000 n +0000398394 00000 n +0000398504 00000 n +0000401106 00000 n +0000401216 00000 n +0000403745 00000 n +0000403855 00000 n +0000405924 00000 n +0000406050 00000 n +0000406087 00000 n +0000406283 00000 n +0000406477 00000 n +0000408433 00000 n +0000408543 00000 n +0000410519 00000 n +0000410629 00000 n +0000412918 00000 n +0000413028 00000 n +0000414925 00000 n +0000415035 00000 n +0000416746 00000 n +0000416856 00000 n +0000418611 00000 n +0000418721 00000 n +0000420630 00000 n +0000420740 00000 n +0000422739 00000 n +0000422849 00000 n +0000425210 00000 n +0000425320 00000 n +0000426426 00000 n +0000426536 00000 n +0000428328 00000 n +0000428438 00000 n +0000430859 00000 n +0000430969 00000 n +0000432796 00000 n +0000432906 00000 n +0000435307 00000 n +0000435433 00000 n +0000435462 00000 n +0000435634 00000 n +0000438409 00000 n +0000438519 00000 n +0000440325 00000 n +0000440435 00000 n +0000442970 00000 n +0000443080 00000 n +0000444457 00000 n +0000444567 00000 n +0000447284 00000 n +0000447394 00000 n +0000450583 00000 n +0000450693 00000 n +0000451427 00000 n +0000451537 00000 n +0000451650 00000 n +0000451759 00000 n +0000451875 00000 n +0000451986 00000 n +0000452100 00000 n +0000452207 00000 n +0000452319 00000 n +trailer +<< +/Size 751 +/Root 2 0 R +/Info 4 0 R +>> +startxref +470153 +%%EOF diff --git a/doc/modsecurity2-apache-reference.xml b/doc/modsecurity2-apache-reference.xml new file mode 100644 index 0000000..6ff8d33 --- /dev/null +++ b/doc/modsecurity2-apache-reference.xml @@ -0,0 +1,6195 @@ + + +
+ <trademark class="registered">ModSecurity</trademark> Reference + Manual + + + Version 2.5.11 (Nov 4, 2009) + + + 2004-2009 + + Breach Security, Inc. (http://www.breach.com) + + + +
+ Introduction + + ModSecurity is a web application firewall (WAF). With over 70% of + attacks now carried out over the web application level, organisations need + all the help they can get in making their systems secure. WAFs are + deployed to establish an increased external security layer to detect + and/or prevent attacks before they reach web applications. ModSecurity + provides protection from a range of attacks against web applications and + allows for HTTP traffic monitoring and real-time analysis with little or + no changes to existing infrastructure. + +
+ HTTP Traffic Logging + + Web servers are typically well-equipped to log traffic in a form + useful for marketing analyses, but fall short logging traffic to web + applications. In particular, most are not capable of logging the request + bodies. Your adversaries know this, and that is why most attacks are now + carried out via POST requests, rendering your systems blind. ModSecurity + makes full HTTP transaction logging possible, allowing complete requests + and responses to be logged. Its logging facilities also allow + fine-grained decisions to be made about exactly what is logged and when, + ensuring only the relevant data is recorded. As some of the request + and/or response may contain sensitive data in certain fields, + ModSecurity can be configured to mask these fields before they are + written to the audit log. +
+ +
+ Real-Time Monitoring and Attack Detection + + In addition to providing logging facilities, ModSecurity can + monitor the HTTP traffic in real time in order to detect attacks. In + this case, ModSecurity operates as a web intrusion detection tool, + allowing you to react to suspicious events that take place at your web + systems. +
+ +
+ Attack Prevention and Just-in-time Patching + + ModSecurity can also act immediately to prevent attacks from + reaching your web applications. There are three commonly used + approaches: + + + + Negative security model. A negative security model monitors + requests for anomalies, unusual behaviour, and common web + application attacks. It keeps anomaly scores for each request, IP + addresses, application sessions, and user accounts. Requests with + high anomaly scores are either logged or rejected altogether. + + + + Positive security model. When a positive security model is + deployed, only requests that are known to be valid are accepted, + with everything else rejected. This model requires knownledge of the + web applications you are protecting. Therefore a positive security + model works best with applications that are heavily used but rarely + updated so that maintenance of the model is minimized. + + + + Known weaknesses and vulnerabilities. Its rule language makes + ModSecurity an ideal external patching tool. External patching + (sometimes referred to as Virtual Patching) is about reducing the + window of opportunity. Time needed to patch application + vulnerabilities often runs to weeks in many organisations. With + ModSecurity, applications can be patched from the outside, without + touching the application source code (and even without any access to + it), making your systems secure until a proper patch is applied to + the application. + + +
+ +
+ Flexible Rule Engine + + A flexible rule engine sits in the heart of ModSecurity. It + implements the ModSecurity Rule Language, which is a specialised + programming language designed to work with HTTP transaction data. The + ModSecurity Rule Language is designed to be easy to use, yet flexible: + common operations are simple while complex operations are possible. + Certified ModSecurity Rules, included with ModSecurity, contain a + comprehensive set of rules that implement general-purpose hardening, + protocol validation and detection of common web application security + issues. Heavily commented, these rules can be used as a learning + tool. +
+ +
+ Embedded-mode Deployment + + ModSecurity is an embeddable web application firewall, which means + it can be deployed as part of your existing web server infrastructure + provided your web servers are Apache-based. This deployment method has + certain advantages: + + + + No changes to existing network. It only takes a few minutes to + add ModSecurity to your existing web servers. And because it was + designed to be completely passive by default, you are free to deploy + it incrementally and only use the features you need. It is equally + easy to remove or deactivate it if required. + + + + No single point of failure. Unlike with network-based + deployments, you will not be introducing a new point of failure to + your system. + + + + Implicit load balancing and scaling. Because it works embedded + in web servers, ModSecurity will automatically take advantage of the + additional load balancing and scalability features. You will not + need to think of load balancing and scaling unless your existing + system needs them. + + + + Minimal overhead. Because it works from inside the web server + process there is no overhead for network communication and minimal + overhead in parsing and data exchange. + + + + No problem with encrypted or compressed content. Many IDS + systems have difficulties analysing SSL traffic. This is not a + problem for ModSecurity because it is positioned to work when the + traffic is decrypted and decompressed. + + +
+ +
+ Network-based Deployment + + ModSecurity works equally well when deployed as part of an + Apache-based reverse proxy server, and many of our customers choose to + do so. In this scenario, one installation of ModSecurity can protect any + number of web servers (even the non-Apache ones). +
+ +
+ Portability + + ModSecurity is known to work well on a wide range of operating + systems. Our customers are successfully running it on Linux, Windows, + Solaris, FreeBSD, OpenBSD, NetBSD, AIX, Mac OS X, and HP-UX. +
+ +
+ Licensing + + ModSecurity is available under two licenses. Users can choose to + use the software under the terms of the GNU General Public License + version 2 (licence text is included with the distribution), as an Open + Source / Free Software product. A range of commercial licenses is also + available, together with a range of commercial support contracts. For + more information on commercial licensing please contact Breach + Security. + + + ModSecurity, mod_security, ModSecurity Pro, and ModSecurity Core + Rules are trademarks or registered trademarks of Breach Security, + Inc. + +
+
+ +
+ <trademark>ModSecurity Core Rules</trademark> + +
+ Overview + + ModSecurity is a web application firewall engine that provides + very little protection on its own. In order to become useful, + ModSecurity must be configured with rules. In order to enable users to + take full advantage of ModSecurity out of the box, Breach Security, Inc. + is providing a free certified rule set for ModSecurity 2.x. Unlike + intrusion detection and prevention systems, which rely on signatures + specific to known vulnerabilities, the Core Rules provide generic + protection from unknown vulnerabilities often found in web applications, + which are in most cases custom coded. The Core Rules are heavily + commented to allow it to be used as a step-by-step deployment guide for + ModSecurity. The latest Core Rules can be found at the ModSecurity + website - http://www.modsecurity.org/projects/rules/. +
+ +
+ Core Rules Content + + In order to provide generic web applications protection, the Core + Rules use the following techniques: + + + + HTTP protection - detecting violations of the HTTP protocol + and a locally defined usage policy. + + + + Common Web Attacks Protection - detecting common web + application security attack. + + + + Automation detection - Detecting bots, crawlers, scanners and + other surface malicious activity. + + + + Trojan Protection - Detecting access to Trojans horses. + + + + Error Hiding - Disguising error messages sent by the + server. + + +
+
+ +
+ Installation + + ModSecurity installation requirements: + + + + ModSecurity 2.x works only with Apache 2.0.x or higher. Version + 2.2.x is highly recommended. + + + + Make sure you have mod_unique_id installed. + + mod_unique_id is packaged with Apache httpd. + + + + libapr and libapr-util + + http://apr.apache.org/ + + + + libpcre + + http://www.pcre.org/ + + + + libxml2 + + http://xmlsoft.org/downloads.html + + + + liblua v5.1.x + + This library is optional and only needed if you will be using + the new Lua engine. + + http://www.lua.org/download.html + + Note that ModSecurity requires the dynamic libraries. These are + not built by default in the source distribution, so the binary + distribution is recommended. + + + + libcurl v7.15.1 or higher + + If you will be using the ModSecurity Log Collector (mlogc) to + send audit logs to a central repository, then you will also need the + curl library. + + http://curl.haxx.se/libcurl/ + + Many have had issues with libcurl linked with the GnuTLS + library for SSL/TLS support. It is recommended that the + openssl library be used for SSL/TLS support in libcurl. + + + + + + ModSecurity installation consists of the following steps: + + + + Stop Apache httpd + + + + Unpack the ModSecurity archive + + + + Building differs for UNIX (or UNIX-like) operating systems and + Windows. + + + + UNIX + + + + Run the configure script to generate a Makefile. + Typically no options are needed. + + ./configure + + Options are available for more customization (use + ./configure --help for a full list), but + typically you will only need to specify the location of the + apxs command installed by Apache httpd with + the --with-apxs option. + + ./configure + --with-apxs=/path/to/httpd-2.x.y/bin/apxs + + + There are certain configure options that are meant for + debugging an other development use. If enabled, these + options can substantially impact performance. These options + include all --debug-* options as well as + the --enable-performance-measurements + options. + + + + + Compile with: make + + + + Optionally test with: make + test + + + This is step is still a bit experimental. If you have + problems, please send the full output and error from the + build to the support list. Most common issues are related to + not finding the required headers and/or libraries. + + + + + Optionally build the ModSecurity Log Collector with: + make mlogc + + + + Optionally install mlogc: Review the + INSTALL file included in the + apache2/mlogc-src directory in the distribution. + + + + Install the ModSecurity module with: make + install + + + + + + Windows (MS VC++ 8) + + + + Edit Makefile.win to configure the + Apache base and library paths. + + + + Compile with: nmake -f + Makefile.win + + + + Install the ModSecurity module with: nmake -f + Makefile.win install + + + + Copy the libxml2.dll and + lua5.1.dll to the Apache + bin directory. Alternatively you can follow + the step below for using LoadFile to load these + libraries. + + + + + + + + Edit the main Apache httpd config file (usually + httpd.conf) + + On UNIX (and Windows if you did not copy the DLLs as stated + above) you must load libxml2 and lua5.1 before ModSecurity with + something like this: + + LoadFile /usr/lib/libxml2.so +LoadFile /usr/lib/liblua5.1.so + + Load the ModSecurity module with:LoadModule security2_module modules/mod_security2.so + + + + Configure ModSecurity + + + + Start Apache httpd + + + + You should now have ModSecurity 2.x up and running. + + + + + If you have compiled Apache yourself you might experience problems + compiling ModSecurity against PCRE. This is because Apache bundles PCRE + but this library is also typically provided by the operating system. I + would expect most (all) vendor-packaged Apache distributions to be + configured to use an external PCRE library (so this should not be a + problem). + + You want to avoid Apache using the bundled PCRE library and + ModSecurity linking against the one provided by the operating system. + The easiest way to do this is to compile Apache against the PCRE library + provided by the operating system (or you can compile it against the + latest PCRE version you downloaded from the main PCRE distribution + site). You can do this at configure time using the --with-pcre switch. If you are not in a + position to recompile Apache, then, to compile ModSecurity successfully, + you'd still need to have access to the bundled PCRE headers (they are + available only in the Apache source code) and change the include path + for ModSecurity (as you did in step 7 above) to point to them (via the + --with-pcre ModSecurity configure option). + + Do note that if your Apache is using an external PCRE library you + can compile ModSecurity with WITH_PCRE_STUDY defined,which would possibly + give you a slight performance edge in regular expression + processing. + + Non-gcc compilers may have problems running out-of-the-box as the + current build system was designed around the gcc compiler and some + compiler/linker flags may differ. To use a non-gcc compiler you may need + some manual Makefile tweaks if issues cannot be solved by exporting + custom CFLAGS and CPPFLAGS environment variables. + + If you are upgrading from ModSecurity 1.x, please refer to the + migration matrix at http://www.modsecurity.org/documentation/ModSecurity-Migration-Matrix.pdf + +
+ +
+ Configuration Directives + + The following section outlines all of the ModSecurity directives. + Most of the ModSecurity directives can be used inside the various Apache + Scope Directives such as VirtualHost, + Location, LocationMatch, + Directory, etc... There are others, however, that can + only be used once in the main configuration file. This information is + specified in the Scope sections below. The first version to use a given + directive is given in the Version sections below. + + These rules, along with the Core rules files, should be contained is + files outside of the httpd.conf file and called up with Apache "Include" + directives. This allows for easier updating/migration of the rules. If you + create your own custom rules that you would like to use with the Core + rules, you should create a file called - + modsecurity_crs_15_customrules.conf and place it in + the same directory as the Core rules files. By using this file name, your + custom rules will be called up after the standard ModSecurity Core rules + configuration file but before the other Core rules. This allows your rules + to be evaluated first which can be useful if you need to implement + specific "allow" rules or to correct any false positives in the Core rules + as they are applied to your site. + + + It is highly encouraged that you do not edit the Core rules files + themselves but rather place all changes (such as + SecRuleRemoveByID, etc...) in your custom rules file. + This will allow for easier upgrading as newer Core rules are released by + Breach Security on the ModSecurity website. + + +
+ <literal>SecAction</literal> + + Description: Unconditionally processes the + action list it receives as the first and only parameter. It accepts one + parameter, the syntax of which is identical to the third parameter + of SecRule. + + Syntax: SecAction + action1,action2,action3 + + Example Usage: SecAction + nolog,phase:1,initcol:RESOURCE=%{REQUEST_FILENAME} + + Processing Phase: Any + + Scope: Any + + Version: 2.0.0 + + Dependencies/Notes: None + + SecAction is best used when you unconditionally execute an action. + This is explicit triggering whereas the normal Actions are conditional + based on data inspection of the request/response. This is a useful + directive when you want to run certain actions such as + initcol to initialize collections. +
+ +
+ <literal>SecArgumentSeparator</literal> + + Description: Specifies which character to use + as separator for + application/x-www-form-urlencoded content. Defaults to + &. Applications are sometimes + (very rarely) written to use a semicolon (;). + + Syntax: SecArgumentSeparator character + + Example Usage: SecArgumentSeparator ; + + Processing Phase: Any + + Scope: Main + + Version: 2.0.0 + + Dependencies/Notes: None + + This directive is needed if a backend web application is using a + non-standard argument separator. If this directive is not set properly + for each web application, then ModSecurity will not be able to parse the + arguments appropriately and the effectiveness of the rule matching will + be significantly decreased. +
+ +
+ <literal>SecAuditEngine</literal> + + Description: Configures the audit logging + engine. + + Syntax: SecAuditEngine On|Off|RelevantOnly + + Example Usage: SecAuditEngine On + + Processing Phase: N/A + + Scope: Any + + Version: 2.0.0 + + Dependencies/Notes: Can be set/changed with + the "ctl" action for the current transaction. + + Example: The following example shows the various audit directives + used together. + + SecAuditEngine RelevantOnly +SecAuditLog logs/audit/audit.log +SecAuditLogParts ABCFHZ +SecAuditLogType concurrent +SecAuditLogStorageDir logs/audit +SecAuditLogRelevantStatus ^(?:5|4\d[^4]) + + Possible values are: + + + + On - log all transactions + by default. + + + + Off - do not log + transactions by default. + + + + RelevantOnly - by default + only log transactions that have triggered a warning or an error, or + have a status code that is considered to be relevant (see SecAuditLogRelevantStatus). + + +
+ +
+ <literal>SecAuditLog</literal> + + Description: Defines the path to the main + audit log file. + + Syntax: SecAuditLog + /path/to/auditlog + + Example Usage: SecAuditLog + /usr/local/apache/logs/audit.log + + Processing Phase: N/A + + Scope: Any + + Version: 2.0.0 + + Dependencies/Notes: This file is open on + startup when the server typically still runs as + root. You should not allow non-root users to have write + privileges for this file or for the directory it is stored in.. + + This file will be used to store the audit log entries if serial + audit logging format is used. If concurrent audit logging format is used + this file will be used as an index, and contain a record of all audit + log files created. If you are planning to use Concurrent audit logging + and sending your audit log data off to a remote Console host or + commercial ModSecurity Management Appliance, then you will need to + configure and use the ModSecurity Log Collector (mlogc) and use the + following format for the audit log: + + SecAuditLog "|/path/to/mlogc /path/to/mlogc.conf" +
+ +
+ <literal>SecAuditLog2</literal> + + Description: Defines the path to the + secondary audit log index file when concurrent logging is enabled. See + SecAuditLog2 for more details. + + Syntax: SecAuditLog2 + /path/to/auditlog2 + + Example Usage: SecAuditLog2 + /usr/local/apache/logs/audit2.log + + Processing Phase: N/A + + Scope: Any + + Version: 2.1.2 + + Dependencies/Notes: A main audit log must be + defined via SecAuditLog before this + directive may be used. Additionally, this log is only used for + replicating the main audit log index file when concurrent audit logging + is used. It will not be used for non-concurrent + audit logging. +
+ +
+ <literal>SecAuditLogDirMode</literal> + + Description: Configures the mode + (permissions) of any directories created for concurrent audit logs using + an octal mode (as used in chmod). See SecAuditLogFileMode for controlling the mode + of audit log files. + + Syntax: SecAuditLogDirMode octal_mode|"default" + + Example Usage: SecAuditLogDirMode 02750 + + Processing Phase: N/A + + Scope: Any + + Version: 2.5.10 + + Dependencies/Notes: This feature is not + available on operating systems not supporting octal file modes. The + default mode (0600) only grants read/write access to the account writing + the file. If access from another account is needed (using mpm-itk is a + good example), then this directive may be required. However, use this + directive with caution to avoid exposing potentially sensitive data to + unauthorized users. Using the value "default" will revert back to the + default setting. + + + The process umask may still limit the mode if it is being more + restrictive than the mode set using this directive. + +
+ +
+ <literal>SecAuditLogFileMode</literal> + + Description: Configures the mode + (permissions) of any files created for concurrent audit logs using an + octal mode (as used in chmod). See SecAuditLogDirMode for controlling the mode of + created audit log directories. + + Syntax: SecAuditLogFileMode + octal_mode|"default" + + Example Usage: SecAuditLogFileMode 00640 + + Processing Phase: N/A + + Scope: Any + + Version: 2.5.10 + + Dependencies/Notes: This feature is not + available on operating systems not supporting octal file modes. The + default mode (0600) only grants read/write access to the account writing + the file. If access from another account is needed (using mpm-itk is a + good example), then this directive may be required. However, use this + directive with caution to avoid exposing potentially sensitive data to + unauthorized users. Using the value "default" will revert back to the + default setting. + + + The process umask may still limit the mode if it is being more + restrictive than the mode set using this directive. + +
+ +
+ <literal>SecAuditLogParts</literal> + + Description: Defines which part of each + transaction are going to be recorded in audit log. Each part is assigned + a single letter. If a letter appears in the list then the equivalent + part of each transactions will be recorded. See below for the list of + all parts. + + Syntax: SecAuditLogParts PARTS + + Example Usage: SecAuditLogParts ABCFHZ + + Processing Phase: N/A + + Scope: Any + + Version: 2.0.0 + + Dependencies/Notes: At this time ModSecurity + does not log response bodies of stock Apache responses (e.g. 404), or the Server and Date response headers. + + Default: ABCFHZ. + + + Please refer to the ModSecurity Data Formats document for a + detailed description of every available part. + + + Available audit log parts: + + + + A - audit log header + (mandatory) + + + + B - request headers + + + + C - request body (present + only if the request body exists and ModSecurity is configured to + intercept it) + + + + D - RESERVED for + intermediary response headers, not implemented yet. + + + + E - intermediary response + body (present only if ModSecurity is configured to intercept + response bodies, and if the audit log engine is configured to record + it). Intermediary response body is the same as the actual response + body unless ModSecurity intercepts the intermediary response body, + in which case the actual response body will contain the error + message (either the Apache default error message, or the + ErrorDocument page). + + + + F - final response headers + (excluding the Date and Server headers, which are always added by + Apache in the late stage of content delivery). + + + + G - RESERVED for the actual + response body, not implemented yet. + + + + H - audit log + trailer + + + + I - This part is a + replacement for part C. It will log the same data as C in all cases + except when multipart/form-data + encoding in used. In this case it will log a fake application/x-www-form-urlencoded body + that contains the information about parameters but not about the + files. This is handy if you don't want to have (often large) files + stored in your audit logs. + + + + J - RESERVED. This part, + when implemented, will contain information about the files uploaded + using multipart/form-data encoding. + + + + K - This part contains a + full list of every rule that matched (one per line) in the order + they were matched. The rules are fully qualified and will thus show + inherited actions and default operators. Supported as of + v2.5.0 + + + + Z - final boundary, + signifies the end of the entry (mandatory) + + +
+ +
+ <literal>SecAuditLogRelevantStatus</literal> + + Description: Configures which response status + code is to be considered relevant for the purpose of audit + logging. + + Syntax: SecAuditLogRelevantStatus REGEX + + Example Usage: SecAuditLogRelevantStatus + ^(?:5|4\d[^4]) + + Processing Phase: N/A + + Scope: Any + + Version: 2.0.0 + + Dependencies/Notes: Must have the + SecAuditEngine set to + RelevantOnly. The parameter is a regular + expression. + + The main purpose of this directive is to allow you to configure + audit logging for only transactions that generate the specified HTTP + Response Status Code. This directive is often used to the decrease the + total size of the audit log file. Keep in mind that if this parameter is + used, then successful attacks that result in a 200 OK status code will + not be logged. +
+ +
+ <literal>SecAuditLogStorageDir</literal> + + Description: Configures the storage directory + where concurrent audit log entries are to be stored. + + Syntax: SecAuditLogStorageDir + /path/to/storage/dir + + Example Usage: SecAuditLogStorageDir + /usr/local/apache/logs/audit + + Processing Phase: N/A + + Scope: Any + + Version: 2.0.0 + + Dependencies/Notes: SecAuditLogType must be + set to Concurrent. The directory must already be created before starting + Apache and it must be writable by the web server user as new files are + generated at runtime. + + As with all logging mechanisms, ensure that you specify a file + system location that has adequate disk space and is not on the root + partition. +
+ +
+ <literal>SecAuditLogType</literal> + + Description: Configures the type of audit + logging mechanism to be used. + + Syntax: SecAuditLogType Serial|Concurrent + + Example Usage: SecAuditLogType Serial + + Processing Phase: N/A + + Scope: Any + + Version: 2.0.0 + + Dependencies/Notes: Must specify + SecAuditLogStorageDir if you use concurrent + logging. + + Possible values are: + + + + Serial - all audit log + entries will be stored in the main audit logging file. This is more + convenient for casual use but it is slower as only one audit log + entry can be written to the file at any one file. + + + + Concurrent - audit log + entries will be stored in separate files, one for each transaction. + Concurrent logging is the mode to use if you are going to send the + audit log data off to a remote ModSecurity Console host. + + +
+ +
+ <literal>SecCacheTransformations</literal> + (Deprecated/Experimental) + + Description: Controls caching of + transformations. Caching is off by default starting with 2.5.6, when it + was deprecated and downgraded back to experimental. + + Syntax: SecCacheTransformations On|Off + [options] + + Example Usage: SecCacheTransformations On + "minlen:64,maxlen:0" + + Processing Phase: N/A + + Scope: Any + + Version: 2.5.0 + + Dependencies/Notes: N/A + + First parameter: + + + + On - cache transformations + (per transaction, per phase) allowing identical transformations to + be performed only once. (default) + + + + Off - do not cache any + transformations, forcing all transformations to be performed for + each rule executed. + + + + The following options are allowed (comma separated): + + + + incremental:on|off - + enabling this option will cache every transformation instead of just + the final transformation. (default: off) + + + + maxitems:N - do not allow + more than N transformations to be cached. The cache will then be + disabled. A zero value is interpreted as "unlimited". This option + may be useful to limit caching for a form with a large number of + ARGS. (default: 512) + + + + minlen:N - do not cache the + transformation if the value's length is less than N bytes. (default: + 32) + + + + maxlen:N - do not cache the + transformation if the value's length is more than N bytes. A zero + value is interpreted as "unlimited". (default: 1024) + + +
+ +
+ <literal>SecChrootDir</literal> + + Description: Configures the directory path + that will be used to jail the web server process. + + Syntax: SecChrootDir + /path/to/chroot/dir + + Example Usage: SecChrootDir /chroot + + Processing Phase: N/A + + Scope: Main + + Version: 2.0.0 + + Dependencies/Notes: This feature is not + available on Windows builds. The internal chroot functionality provided + by ModSecurity works great for simple setups. One example of a simple + setup is Apache serving static files only, or running scripts using + modules.builds. Some problems you might encounter with more complex + setups: + + + + DNS lookups do not work (this is because this feature requires + a shared library that is loaded on demand, after chroot takes + place). + + + + You cannot send email from PHP because it uses sendmail and + sendmail is outside the jail. + + + + In some cases Apache graceful (reload) no longer works. + + + + You should be aware that the internal chroot feature might not be + 100% reliable. Due to the large number of default and third-party + modules available for the Apache web server, it is not possible to + verify the internal chroot works reliably with all of them. A module, + working from within Apache, can do things that make it easy to break out + of the jail. In particular, if you are using any of the modules that + fork in the module initialisation phase (e.g. + mod_fastcgi, mod_fcgid, + mod_cgid), you are advised to examine each Apache + process and observe its current working directory, process root, and the + list of open files. Consider what your options are and make your own + decision. +
+ +
+ <literal>SecComponentSignature</literal> + + Description: Appends component signature to + the ModSecurity signature. + + Syntax: SecComponentSignature + "COMPONENT_NAME/X.Y.Z (COMMENT)" + + Example usage: SecComponentSignature + "Core Rules/1.2.3" + + Processing Phase: N/A + + Scope: Main + + Version: 2.5.0 + + Dependencies/Notes: This directive should be + used to make the presence of significant ModSecurity components known. + The entire signature will be recorded in transaction audit log. It + should be used by ModSecurity module and rule set writers to make + debugging easier. +
+ +
+ <literal>SecContentInjection</literal> + + Description: Enables content injection using + actions append and prepend. + + Syntax: SecContentInjection + (On|Off) + + Example Usage: SecContentInjection + On + + Processing Phase: N/A + + Scope: Any + + Version: 2.5.0 + + Dependencies/Notes: N/A +
+ +
+ <literal>SecCookieFormat</literal> + + Description: Selects the cookie format that + will be used in the current configuration context. + + Syntax: SecCookieFormat 0|1 + + Example Usage: SecCookieFormat 0 + + Processing Phase: N/A + + Scope: Any + + Version: 2.0.0 + + Dependencies/Notes: None + + Possible values are: + + + + 0 - use version 0 + (Netscape) cookies. This is what most applications use. It is the + default value. + + + + 1 - use version 1 + cookies. + + +
+ +
+ <literal>SecDataDir</literal> + + Description: Path where persistent data (e.g. + IP address data, session data, etc) is to be stored. + + Syntax: SecDataDir + /path/to/dir + + Example Usage: SecDataDir /usr/local/apache/logs/data + + Processing Phase: N/A + + Scope: Main + + Dependencies/Notes: This directive is needed + when initcol, setsid an setuid are used. Must be writable by the web + server user. +
+ +
+ <literal>SecDebugLog</literal> + + Description: Path to the ModSecurity debug + log file. + + Syntax: SecDebugLog + /path/to/modsec-debug.log + + Example Usage: SecDebugLog + /usr/local/apache/logs/modsec-debug.log + + Processing Phase: N/A + + Scope: Any + + Version: 2.0.0 + + Dependencies/Notes: None +
+ +
+ <literal>SecDebugLogLevel</literal> + + Description: Configures the verboseness of + the debug log data. + + Syntax: SecDebugLogLevel 0|1|2|3|4|5|6|7|8|9 + + Example Usage: SecDebugLogLevel 4 + + Processing Phase: N/A + + Scope: Any + + Version: 2.0.0 + + Dependencies/Notes: Levels 1 - 3 are always sent to the Apache error log. + Therefore you can always use level 0 + as the default logging level in production. Level 5 is useful when debugging. It is not + advisable to use higher logging levels in production as excessive + logging can slow down server significantly. + + Possible values are: + + + + 0 - no logging. + + + + 1 - errors (intercepted + requests) only. + + + + 2 - warnings. + + + + 3 - notices. + + + + 4 - details of how + transactions are handled. + + + + 5 - as above, but including + information about each piece of information handled. + + + + 9 - log everything, + including very detailed debugging information. + + +
+ +
+ <literal>SecDefaultAction</literal> + + Description: Defines the default action to + take on a rule match. + + Syntax: SecDefaultAction + action1,action2,action3 + + Example Usage: SecDefaultAction + log,auditlog,deny,status:403,phase:2 + + Processing Phase: Any + + Scope: Any + + Version: 2.0.0 + + Dependencies/Notes: Rules following a + SecDefaultAction directive will inherit this setting + unless a specific action is specified for an individual rule or until + another SecDefaultAction is specified. Take special + note that in the logging disruptive actions are not allowed, but this + can inadvertently be inherited using a disruptive action in + SecDefaultAction. + + The default value is minimal (differing from previous + versions): + + SecDefaultAction phase:2,log,auditlog,pass + + + SecDefaultAction must specify a disruptive + action and a processing phase and cannot contain metadata + actions. + + + + SecDefaultAction is not + inherited across configuration contexts. (For an example of why this + may be a problem for you, read the following ModSecurity Blog entry + http://blog.modsecurity.org/2008/07/modsecurity-tri.html). + +
+ +
+ <literal>SecGeoLookupDb</literal> + + Description: Defines the path to the + geographical database file. + + Syntax: SecGeoLookupDb /path/to/db + + Example Usage: SecGeoLookupDb + /usr/local/geo/data/GeoLiteCity.dat + + Processing Phase: N/A + + Scope: Any + + Version: 2.5.0 + + Dependencies/Notes: Check out + maxmind.com for free database files. +
+ +
+ <literal>SecGuardianLog</literal> + + Description: Configuration directive to use + the httpd-guardian script to monitor for Denial of Service (DoS) + attacks. + + Syntax: SecGuardianLog |/path/to/httpd-guardian + + Example Usage: SecGuardianLog + |/usr/local/apache/bin/httpd-guardian + + Processing Phase: N/A + + Scope: Main + + Version: 2.0.0 + + Dependencies/Notes: By default httpd-guardian + will defend against clients that send more than 120 requests in a + minute, or more than 360 requests in five minutes. + + Since 1.9, ModSecurity supports a new directive, SecGuardianLog, + that is designed to send all access data to another program using the + piped logging feature. Since Apache is typically deployed in a + multi-process fashion, making information sharing difficult, the idea is + to deploy a single external process to observe all requests in a + stateful manner, providing additional protection. + + Development of a state of the art external protection tool will be + a focus of subsequent ModSecurity releases. However, a fully functional + tool is already available as part of the Apache httpd tools + project. The tool is called httpd-guardian and can be used to + defend against Denial of Service attacks. It uses the blacklist tool + (from the same project) to interact with an iptables-based (Linux) or + pf-based (*BSD) firewall, dynamically blacklisting the offending IP + addresses. It can also interact with SnortSam (http://www.snortsam.net). + Assuming httpd-guardian is already configured (look into the source code + for the detailed instructions) you only need to add one line to your + Apache configuration to deploy it: + + SecGuardianLog |/path/to/httpd-guardian +
+ +
+ <literal>SecMarker</literal> + + Description: Adds a fixed rule marker in the + ruleset to be used as a target in a skipAfter action. + A SecMarker directive essentially creates a rule that + does nothing and whose only purpose it to carry the given ID. + + Syntax: SecMarker + ID + + Example Usage: SecMarker 9999 + + Processing Phase: Any + + Scope: Any + + Version: 2.5.0 + + Dependencies/Notes: None + + SecRule REQUEST_URI "^/$" \ + "chain,t:none,t:urlDecode,t:lowercase,t:normalisePath,skipAfter:99" +SecRule REMOTE_ADDR "^127\.0\.0\.1$" "chain" +SecRule REQUEST_HEADERS:User-Agent \ + "^Apache \(internal dummy connection\)$" "t:none" +SecRule &REQUEST_HEADERS:Host "@eq 0" \ + "deny,log,status:400,id:08,severity:4,msg:'Missing a Host Header'" +SecRule &REQUEST_HEADERS:Accept "@eq 0" \ + "log,deny,log,status:400,id:15,msg:'Request Missing an Accept Header'" + +SecMarker 99 +
+ +
+ <literal>SecPdfProtect</literal> + + Description: Enables the PDF XSS protection + functionality. Once enabled access to PDF files is tracked. Direct + access attempts are redirected to links that contain one-time tokens. + Requests with valid tokens are allowed through unmodified. Requests with + invalid tokens are also allowed through but with forced download of the + PDF files. This implementation uses response headers to detect PDF files + and thus can be used with dynamically generated PDF files that do not + have the .pdf extension in the request URI. + + Syntax: SecPdfProtect On|Off + + Example Usage: SecPdfProtect On + + Processing Phase: N/A + + Scope: Any + + Version: 2.5.0 + + Dependencies/Notes: None +
+ +
+ <literal>SecPdfProtectMethod</literal> + + Description: Configure desired protection + method to be used when requests for PDF files are detected. Possible + values are TokenRedirection and + ForcedDownload. The token redirection approach will + attempt to redirect with tokens where possible. This allows PDF files to + continue to be opened inline but only works for GET requests. Forced + download always causes PDF files to be delivered as opaque binaries and + attachments. The latter will always be used for non-GET requests. Forced + download is considered to be more secure but may cause usability + problems for users ("This PDF won't open anymore!"). + + Syntax: SecPdfProtectMethod method + + Example Usage: SecPdfProtectMethod TokenRedirection + + Processing Phase: N/A + + Scope: Any + + Version: 2.5.0 + + Dependencies/Notes: None + + Default: + TokenRedirection +
+ +
+ <literal>SecPdfProtectSecret</literal> + + Description: Defines the secret that will be + used to construct one-time tokens. You should use a reasonably long + value for the secret (e.g. 16 characters is good). Once selected the + secret should not be changed as it will break the tokens that were sent + prior to change. But it's not a big deal even if you change it. It will + just force download of PDF files with tokens that were issued in the + last few seconds. + + Syntax: SecPdfProtectSecret secret + + Example Usage: SecPdfProtectSecret + MyRandomSecretString + + Processing Phase: N/A + + Scope: Any + + Version: 2.5.0 + + Dependencies/Notes: None +
+ +
+ <literal>SecPdfProtectTimeout</literal> + + Description: Defines the token timeout. After + token expires it can no longer be used to allow access to PDF file. + Request will be allowed through but the PDF will be delivered as + attachment. + + Syntax: SecPdfProtectTimeout timeout + + Example Usage: SecPdfProtectTimeout 10 + + Processing Phase: N/A + + Scope: Any + + Version: 2.5.0 + + Dependencies/Notes: None + + Default: 10 +
+ +
+ <literal>SecPdfProtectTokenName</literal> + + Description: Defines the name of the token. + The only reason you would want to change the name of the token is if you + wanted to hide the fact you are running ModSecurity. It's a good reason + but it won't really help as the adversary can look into the algorithm + used for PDF protection and figure it out anyway. It does raise the bar + slightly so go ahead if you want to. + + Syntax: SecPdfProtectTokenName name + + Example Usage: SecPdfProtectTokenName PDFTOKEN + + Processing Phase: N/A + + Scope: Any + + Version: 2.5.0 + + Dependencies/Notes: None + + Default: PDFTOKEN +
+ +
+ <literal>SecRequestBodyAccess</literal> + + Description: Configures whether request + bodies will be buffered and processed by ModSecurity by default. + + Syntax: SecRequestBodyAccess On|Off + + Example Usage: SecRequestBodyAccess On + + Processing Phase: N/A + + Scope: Any + + Version: 2.0.0 + + Dependencies/Notes: This directive is + required if you plan to inspect POST_PAYLOAD. This + directive must be used along with the "phase:2" processing phase action + and REQUEST_BODY variable/location. If any of these 3 + parts are not configured, you will not be able to inspect the request + bodies. + + Possible values are: + + + + On - access request + bodies. + + + + Off - do not attempt to + access request bodies. + + +
+ +
+ <literal>SecRequestBodyLimit</literal> + + Description: Configures the maximum request + body size ModSecurity will accept for buffering. + + Syntax: SecRequestBodyLimit NUMBER_IN_BYTES + + Example Usage: SecRequestBodyLimit 134217728 + + Scope: Any + + Version: 2.0.0 + + Dependencies/Notes: 131072 KB (134217728 + bytes) is the default setting. Anything over this limit will be rejected + with status code 413 Request Entity Too Large. There is a hard limit of + 1 GB. +
+ +
+ <literal>SecRequestBodyNoFilesLimit</literal> + + Description: Configures the maximum request + body size ModSecurity will accept for buffering, excluding the size of + files being transported in the request. This directive comes handy to + further reduce susceptibility to DoS attacks when someone is sending + request bodies of very large sizes. Web applications that require file + uploads must configure SecRequestBodyLimit to a high + value. Since large files are streamed to disk file uploads will not + increase memory consumption. However, it's still possible for someone to + take advantage of a large request body limit and send non-upload + requests with large body sizes. This directive eliminates that + loophole. + + Syntax: SecRequestBodyNoFilesLimit + NUMBER_IN_BYTES + + Example Usage: SecRequestBodyLimit 131072 + + Scope: Any + + Version: 2.5.0 + + Dependencies/Notes: 1 MB (1048576 bytes) is + the default setting. This value is very conservative. For most + applications you should be able to reduce it down to 128 KB or lower. + Anything over the limit will be rejected with status code 413 + Request Entity Too Large. There is a hard limit of 1 + GB. +
+ +
+ <literal>SecRequestBodyInMemoryLimit</literal> + + Description: Configures the maximum request + body size ModSecurity will store in memory. + + Syntax: SecRequestBodyInMemoryLimit + NUMBER_IN_BYTES + + Example Usage: SecRequestBodyInMemoryLimit 131072 + + Processing Phase: N/A + + Scope: Any + + Version: 2.0.0 + + Dependencies/Notes: None + + By default the limit is 128 KB: + + # Store up to 128 KB in memory +SecRequestBodyInMemoryLimit 131072 +
+ +
+ <literal>SecResponseBodyLimit</literal> + + Description: Configures the maximum response + body size that will be accepted for buffering. + + Syntax: SecResponseBodyLimit NUMBER_IN_BYTES + + Example Usage: SecResponseBodyLimit 524228 + + Processing Phase: N/A + + Scope: Any + + Version: 2.0.0 + + Dependencies/Notes: Anything over this limit + will be rejected with status code 500 Internal Server Error. This + setting will not affect the responses with MIME types that are not + marked for buffering. There is a hard limit of 1 GB. + + By default this limit is configured to 512 KB: + + # Buffer response bodies of up to 512 KB in length +SecResponseBodyLimit 524288 +
+ +
+ <literal>SecResponseBodyLimitAction</literal> + + Description: Controls what happens once a + response body limit, configured with + SecResponseBodyLimit, is encountered. By default + ModSecurity will reject a response body that is longer than specified. + Some web sites, however, will produce very long responses making it + difficult to come up with a reasonable limit. Such sites would have to + raise the limit significantly to function properly defying the purpose + of having the limit in the first place (to control memory consumption). + With the ability to choose what happens once a limit is reached site + administrators can choose to inspect only the first part of the + response, the part that can fit into the desired limit, and let the rest + through. Some could argue that allowing parts of responses to go + uninspected is a weakness. This is true in theory but only applies to + cases where the attacker controls the output (e.g. can make it arbitrary + long). In such cases, however, it is not possible to prevent leakage + anyway. The attacker could compress, obfuscate, or even encrypt data + before it is sent back, and therefore bypass any monitoring + device. + + Syntax: SecResponseBodyLimitAction + Reject|ProcessPartial + + Example Usage: + SecResponseBodyLimitAction ProcessPartial + + Processing Phase: N/A + + Scope: Any + + Version: 2.5.0 + + Dependencies/Notes: None +
+ +
+ <literal>SecResponseBodyMimeType</literal> + + Description: Configures which MIME types are to be considered for response + body buffering. + + Syntax: SecResponseBodyMimeType mime/type + + Example Usage: SecResponseBodyMimeType text/plain + text/html + + Processing Phase: N/A + + Scope: Any + + Version: 2.0.0 + + Dependencies/Notes: Multiple SecResponseBodyMimeType directives can be + used to add MIME types. + + The default value is text/plaintext/html: + + SecResponseBodyMimeType text/plain text/html +
+ +
+ <literal>SecResponseBodyMimeTypesClear</literal> + + Description: Clears the list of MIME types considered for response body + buffering, allowing you to start populating the list from + scratch. + + Syntax: SecResponseBodyMimeTypesClear + + Example Usage: SecResponseBodyMimeTypesClear + + Processing Phase: N/A + + Scope: Any + + Version: 2.0.0 + + Dependencies/Notes: None +
+ +
+ <literal>SecResponseBodyAccess</literal> + + Description: Configures whether response + bodies are to be buffer and analysed or not. + + Syntax: SecResponseBodyAccess On|Off + + Example Usage: SecResponseBodyAccess On + + Processing Phase: N/A + + Scope: Any + + Version: 2.0.0 + + Dependencies/Notes: This directive is + required if you plan to inspect HTML responses. This directive must be + used along with the "phase:4" processing phase action and RESPONSE_BODY + variable/location. If any of these 3 parts are not configured, you will + not be able to inspect the response bodies. + + Possible values are: + + + + On - access response bodies + (but only if the MIME type matches, see above). + + + + Off - do not attempt to + access response bodies. + + +
+ +
+ <literal>SecRule</literal> + + Description: SecRule is the main ModSecurity directive. It + is used to analyse data and perform actions based on the results. + + Syntax: SecRule + VARIABLES OPERATOR [ACTIONS] + + Example Usage: SecRule REQUEST_URI "attack" \ + + + "phase:1,t:none,t:urlDecode,t:lowercase,t:normalisePath" + + Processing Phase: Any + + Scope: Any + + Version: 2.0.0 + + Dependencies/Notes: None + + In general, the format of this rule is as follows: + + SecRule VARIABLES OPERATOR [ACTIONS] + + The second part, OPERATOR, + specifies how they are going to be checked. The third (optional) part, + ACTIONS, specifies what to do + whenever the operator used performs a successful match against a + variable. + +
+ Variables in rules + + The first part, VARIABLES, + specifies which variables are to be checked. For example, the + following rule will reject a transaction that has the word + dirty in the URI: + + SecRule ARGS dirty + + Each rule can specify one or more variables: + + SecRule ARGS|REQUEST_HEADERS:User-Agent dirty + + There is a third format supported by the selection operator - + XPath expression. XPath expressions can only used against the special + variable XML, which is available only of the request body was + processed as XML. + + SecRule XML:/xPath/Expression dirty + + + Not all collections support all selection operator format + types. You should refer to the documentation of each collection to + determine what is and isn't supported. + +
+ +
+ Collections + + A variable can contain one or many pieces of data, depending on + the nature of the variable and the way it is used. We've seen examples + of both approaches in the previous section. When a variable can + contain more than one value we refer to it as a + collection. + + Collections are always expanded before a rule is run. For + example, the following rule: + + SecRule ARGS dirty + + will be expanded to: + + SecRule ARGS:p dirty +SecRule ARGS:q dirty + + in a requests that has only two parameters, named + p and q. + + Collections come in several flavours: + + + + Read-only + + + Created at runtime using transaction data. For example: + ARGS (contains a list of all request + parameter values) and REQUEST_HEADERS + (contains a list of all request header values). + + + + + Transient Read/Write + + + The TX collection is created (empty) + for every transaction. Rules can read from it and write to it + (using the setvar action, for example), but + the information stored in this collection will not survive the + end of transaction. + + + + + Persistent Read/Write + + + There are several collections that can be written to, but + which are persisted to the storage backend. These collections + are used to track clients across transactions. Examples of + collections that fall into this type are IP, + SESSION and USER. + + + +
+ +
+ Operators in rules + + In the simplest possible case you will use a regular expression + pattern as the second rule parameter. This is what we've done in the + examples above. If you do this ModSecurity assumes you want to use the + rx (regular expression) operator. + You can also explicitly specify the operator you want to use by using + @, followed by the name of an + operator, at the beginning of the second SecRule + parameter: + + SecRule ARGS "@rx dirty" + + Note how we had to use double quotes to delimit the second rule + parameter. This is because the second parameter now has whitespace in + it. Any number of whitespace characters can follow the name of the + operator. If there are any non-whitespace characters there, they will + all be treated as a special parameter to the operator. In the case of + the regular expression operator the special parameter is the pattern + that will be used for comparison. + + The @ can be the second character if you are using negation to + negate the result returned by the operator: + + SecRule &ARGS "!@rx ^0$" +
+ +
+ Operator negation + + Operator results can be negated by using an exclamation mark at + the beginning of the second parameter. The following rule matches if + the word dirty does not appear + in the User-Agent request header: + + SecRule REQUEST_HEADERS:User-Agent !dirty + + You can use the exclamation mark in combination with any + parameter. If you do, the exclamation mark needs to go first, followed + by the explicit operator reference. The following rule has the same + effect as the previous example: + + SecRule REQUEST_HEADERS:User-Agent "!@rx dirty" + + If you need to use negation in a rule that is going to be + applied to several variables then it may not be immediately clear what + will happen. Consider the following example: + + SecRule ARGS:p|ARGS:q !dirty + + The above rule is identical to: + + SecRule ARGS:p !dirty +SecRule ARGS:q !dirty + + + Negation is applied to operations against individual + operations, not agains the entire variable list. + +
+ +
+ Actions in rules + + The third parameter, ACTIONS, + can be omitted only because there is a helper feature that specifies + the default action list. If the parameter isn't omitted the actions + specified in the parameter will be merged with the default action list + to create the actual list of actions that will be processed on a rule + match. +
+
+ +
+ <literal>SecRuleInheritance</literal> + + Description: Configures whether the current + context will inherit rules from the parent context (configuration + options are inherited in most cases - you should look up the + documentation for every directive to determine if it is inherited or + not). + + Syntax: SecRuleInheritance On|Off + + Example Usage: SecRuleInheritance Off + + Processing Phase: Any + + Scope: Any + + Version: 2.0.0 + + Dependencies/Notes: Resource-specific + contexts (e.g. Location, Directory, etc) cannot override + phase1 rules configured in the main server or in + the virtual server. This is because phase 1 is run early in the request + processing process, before Apache maps request to resource. Virtual host + context can override phase 1 rules configured in the main server. + + Example: The following example shows where ModSecurity may be + enabled in the main Apache configuration scope, however you might want + to configure your VirtualHosts differently. In the first example, the + first VirtualHost is not inheriting the ModSecurity main config + directives and in the second one it is. + + SecRuleEngine On +SecDefaultAction log,pass,phase:2 +... + +<VirtualHost *:80> +ServerName app1.com +ServerAlias www.app1.com +SecRuleInheritance Off +SecDefaultAction log,deny,phase:1,redirect:http://www.site2.com +... +</VirtualHost> + +<VirtualHost *:80> +ServerName app2.com +ServerAlias www.app2.com +SecRuleInheritance On SecRule ARGS "attack" +... +</VirtualHost> + + Possible values are: + + + + On - inherit rules from the + parent context. + + + + Off - do not inherit rules + from the parent context. + + + Configuration contexts are an Apache concept. Directives + <Directory>, + <Files>, + <Location> and + <VirtualHost> are all used to create + configuration contexts. For more information please go to the + Apache documentation section Configuration + Sections. + + + +
+ +
+ <literal>SecRuleEngine</literal> + + Description: Configures the rules + engine. + + Syntax: SecRuleEngine On|Off|DetectionOnly + + Example Usage: SecRuleEngine On + + Processing Phase: Any + + Scope: Any + + Version: 2.0.0 + + Dependencies/Notes: This directive can also + be controlled by the ctl action (ctl:ruleEngine=off) for per rule + processing. + + Possible values are: + + + + On - process rules. + + + + Off - do not process + rules. + + + + DetectionOnly - process + rules but never intercept transactions, even when rules are + configured to do so. + + +
+ +
+ <literal>SecRuleRemoveById</literal> + + Description: Removes matching rules from the + parent contexts. + + Syntax: SecRuleUpdateActionById RULEID + ACTIONLIST + + Example Usage: SecRuleRemoveByID 1 2 "9000-9010" + + Processing Phase: Any + + Scope: Any + + Version: 2.0.0 + + Dependencies/Notes: This directive supports + multiple parameters, where each parameter can either be a rule ID, or a + range. Parameters that contain spaces must be delimited using double + quotes. + + SecRuleRemoveById 1 2 5 10-20 "400-556" 673 +
+ +
+ <literal>SecRuleRemoveByMsg</literal> + + Description: Removes matching rules from the + parent contexts. + + Syntax: SecRuleRemoveByMsg REGEX + + Example Usage: SecRuleRemoveByMsg "FAIL" + + Processing Phase: Any + + Scope: Any + + Version: 2.0.0 + + Dependencies/Notes: This directive supports + multiple parameters. Each parameter is a regular expression that will be + applied to the message (specified using the msg action). +
+ +
+ <literal>SecRuleScript</literal> (Experimental) + + Description: This directive creates a special + rule that executes a Lua script to decide whether to match or not. The + main difference from SecRule is that there are no + targets nor operators. The script can fetch any variable from the + ModSecurity context and use any (Lua) operator to test them. The second + optional parameter is the list of actions whose meaning is identical to + that of SecRule. + + Syntax: SecRuleScript + /path/to/script.lua [ACTIONS] + + Example Usage: SecRuleScript "/path/to/file.lua" + "block" + + Processing Phase: Any + + Scope: Any + + Version: 2.5.0 + + Dependencies/Notes: None + + + All Lua scripts are compiled at configuration time and cached in + memory. To reload scripts you must reload the entire ModSecurity + configuration by restarting Apache. + + + Example script: + + -- Your script must define the main entry +-- point, as below. +function main() + -- Log something at level 1. Normally you shouldn't be + -- logging anything, especially not at level 1, but this is + -- just to show you can. Useful for debugging. + m.log(1, "Hello world!"); + + -- Retrieve one variable. + local var1 = m.getvar("REMOTE_ADDR"); + + -- Retrieve one variable, applying one transformation function. + -- The second parameter is a string. + local var2 = m.getvar("ARGS", "lowercase"); + + -- Retrieve one variable, applying several transformation functions. + -- The second parameter is now a list. You should note that m.getvar() + -- requires the use of comma to separate collection names from + -- variable names. This is because only one variable is returned. + local var3 = m.getvar("ARGS.p", { "lowercase", "compressWhitespace" } ); + + -- If you want this rule to match return a string + -- containing the error message. The message must contain the name + -- of the variable where the problem is located. + -- return "Variable ARGS:p looks suspicious!" + + -- Otherwise, simply return nil. + return nil; +end + + In this first example we were only retrieving one variable at the + time. In this case the name of the variable is known to you. In many + cases, however, you will want to examine variables whose names you won't + know in advance, for example script parameters. + + Example showing use of m.getvars() to retrieve + many variables at once: + + function main() + -- Retrieve script parameters. + local d = m.getvars("ARGS", { "lowercase", "htmlEntityDecode" } ); + + -- Loop through the paramters. + for i = 1, #d do + -- Examine parameter value. + if (string.find(d[i].value, "<script")) then + -- Always specify the name of the variable where the + -- problem is located in the error message. + return ("Suspected XSS in variable " .. d[i].name .. "."); + end + end + + -- Nothing wrong found. + return nil; +end + + + Go to http://www.lua.org/ to find more + about the Lua programming language. The reference manual too is + available online, at http://www.lua.org/manual/5.1/. + + + + Lua support is marked as experimental as + the way the progamming interface may continue to evolve while we are + working for the best implementation style. Any user input into the + programming interface is appreciated. + +
+ +
+ <literal>SecRuleUpdateActionById</literal> + + Description: Updates the action list of the + specified rule. + + Syntax: SecRuleRemoveById RULEID ACTIONLIST + + Example Usage: SecRuleUpdateActionById 12345 + deny,status:403 + + Processing Phase: Any + + Scope: Any + + Version: 2.5.0 + + Dependencies/Notes: This directive merges the + specified action list with the rule's action list. There are two + limitations. The rule ID cannot be changed, nor can the phase. Further + note that actions that may be specified multiple times are appended to + the original. + + SecAction \ + "t:lowercase,phase:2,id:12345,pass,msg:'The Message',log,auditlog" +SecRuleUpdateActionById 12345 "t:compressWhitespace,deny,status:403,msg:'A new message' + + The example above will cause the rule to be executed as if it was + specified as follows: + + SecAction \ + "t:lowercase,phase:2,id:12345,log,auditlog,t:compressWhitespace,deny,status:403,msg:'A new message'" +
+ +
+ <literal>SecServerSignature</literal> + + Description: Instructs ModSecurity to change + the data presented in the "Server:" response header token. + + Syntax: SecServerSignature "WEB SERVER + SOFTWARE" + + Example Usage: SecServerSignature + "Netscape-Enterprise/6.0" + + Processing Phase: N/A + + Scope: Main + + Version: 2.0.0 + + Dependencies/Notes: In order for this + directive to work, you must set the Apache ServerTokens directive to + Full. ModSecurity will overwrite the server signature data held in this + memory space with the data set in this directive. If ServerTokens is not + set to Full, then the memory space is most likely not large enough to + hold the new data we are looking to insert. +
+ +
+ <literal>SecTmpDir</literal> + + Description: Configures the directory where + temporary files will be created. + + Syntax: SecTmpDir + /path/to/dir + + Example Usage: SecTmpDir /tmp + + Processing Phase: N/A + + Scope: Any + + Version: 2.0.0 + + Dependencies/Notes: Needs to be writable by + the Apache user process. This is the directory location where Apache + will swap data to disk if it runs out of memory (more data than what was + specified in the SecRequestBodyInMemoryLimit directive) during + inspection. +
+ +
+ <literal>SecUploadDir</literal> + + Description: Configures the directory where + intercepted files will be stored. + + Syntax: SecUploadDir + /path/to/dir + + Example Usage: SecUploadDir /tmp + + Processing Phase: N/A + + Scope: Any + + Version: 2.0.0 + + Dependencies/Notes: This directory must be on + the same filesystem as the temporary directory defined with SecTmpDir. This directive is used with + SecUploadKeepFiles. +
+ +
+ <literal>SecUploadFileMode</literal> + + Description: Configures the mode + (permissions) of any uploaded files using an octal mode (as used in + chmod). + + Syntax: SecUploadFileMode octal_mode|"default" + + Example Usage: SecUploadFileMode 0640 + + Processing Phase: N/A + + Scope: Any + + Version: 2.1.6 + + Dependencies/Notes: This feature is not + available on operating systems not supporting octal file modes. The + default mode (0600) only grants read/write access to the account writing + the file. If access from another account is needed (using clamd is a + good example), then this directive may be required. However, use this + directive with caution to avoid exposing potentially sensitive data to + unauthorized users. Using the value "default" will revert back to the + default setting. + + + The process umask may still limit the mode if it is being more + restrictive than the mode set using this directive. + +
+ +
+ <literal>SecUploadKeepFiles</literal> + + Description: Configures whether or not the + intercepted files will be kept after transaction is processed. + + Syntax: SecUploadKeepFiles On|Off|RelevantOnly + + Example Usage: SecUploadKeepFiles On + + Processing Phase: N/A + + Scope: Any + + Version: 2.0.0 + + Dependencies/Notes: This directive requires + the storage directory to be defined (using SecUploadDir). + + Possible values are: + + + + On - Keep uploaded + files. + + + + Off - Do not keep uploaded + files. + + + + RelevantOnly - This will + keep only those files that belong to requests that are deemed + relevant. + + +
+ +
+ <literal>SecWebAppId</literal> + + Description: Creates a partition on the + server that belongs to one web application. + + Syntax: SecWebAppId + "NAME" + + Example Usage: SecWebAppId "WebApp1" + + Processing Phase: N/A + + Scope: Any + + Version: 2.0.0 + + Dependencies/Notes: Partitions are used to + avoid collisions between session IDs and user IDs. This directive must + be used if there are multiple applications deployed on the same server. + If it isn't used, a collision between session IDs might occur. The + default value is default. + Example: + + <VirtualHost *:80> +ServerName app1.com +ServerAlias www.app1.com +SecWebAppId "App1" +SecRule REQUEST_COOKIES:PHPSESSID !^$ chain,nolog,pass +SecAction setsid:%{REQUEST_COOKIES.PHPSESSID} +... +</VirtualHost> + +<VirtualHost *:80> +ServerName app2.com +ServerAlias www.app2.com +SecWebAppId "App2" +SecRule REQUEST_COOKIES:PHPSESSID !^$ chain,nolog,pass +SecAction setsid:%{REQUEST_COOKIES.PHPSESSID} +... +</VirtualHost> + + In the two examples configurations shown, SecWebAppId is being + used in conjunction with the Apache VirtualHost directives. What this + achieves is to create more unique collection names when being hosted on + one server. Normally, when setsid is used, ModSecurity will create a + collection with the name "SESSION" and it will hold the value specified. + With using SecWebAppId as shown in the examples, however, the name of + the collection would become "App1_SESSION" and "App2_SESSION". + + SecWebAppId is relevant in two cases: + + + + You are logging transactions/alerts to the ModSecurity Console + and you want to use the web application ID to search only the + transactions belonging to that application. + + + + You are using the data persistence facility (collections + SESSION and USER) and you need to avoid collisions between sessions + and users belonging to different applications. + + +
+
+ +
+ Processing Phases + + ModSecurity 2.x allows rules to be placed in one of the following + five phases: + + + + Request headers (REQUEST_HEADERS) + + + + Request body (REQUEST_BODY) + + + + Response headers (RESPONSE_HEADERS) + + + + Response body (RESPONSE_BODY) + + + + Logging (LOGGING) + + + + Below is a diagram of the standard Apache Request Cycle. In the + diagram, the 5 ModSecurity processing phases are shown. + + + + In order to select the phase a rule executes during, use the phase + action either directly in the rule or in using the + SecDefaultAction directive: + + SecDefaultAction "log,pass,phase:2" +SecRule REQUEST_HEADERS:Host "!^$" "deny,phase:1" + + + Keep in mind that rules are executed according to phases, so even + if two rules are adjacent in a configuration file, but are set to + execute in different phases, they would not happen one after the other. + The order of rules in the configuration file is important only within + the rules of each phase. This is especially important when using the + skip and skipAfter actions. + + + + The LOGGING phase is special. It is executed at + the end of each transaction no matter what happened in the previous + phases. This means it will be processed even if the request was + intercepted or the allow action was used to pass the + transaction through. + + +
+ Phase Request Headers + + Rules in this phase are processed immediately after Apache + completes reading the request headers (post-read-request phase). At this + point the request body has not been read yet, meaning not all request + arguments are available. Rules should be placed in this phase if you + need to have them run early (before Apache does something with the + request), to do something before the request body has been read, + determine whether or not the request body should be buffered, or decide + how you want the request body to be processed (e.g. whether to parse it + as XML or not). + + Note + + Rules in this phase can not leverage Apache scope directives + (Directory, Location, LocationMatch, etc...) as the post-read-request + hook does not have this information yet. The exception here is the + VirtualHost directive. If you want to use ModSecurity rules inside + Apache locations, then they should run in Phase 2. Refer to the Apache + Request Cycle/ModSecurity Processing Phases diagram. +
+ +
+ Phase Request Body + + This is the general-purpose input analysis phase. Most of the + application-oriented rules should go here. In this phase you are + guaranteed to have received the request arguments (provided the request + body has been read). ModSecurity supports three encoding types for the + request body phase: + + + + application/x-www-form-urlencoded - used to + transfer form data + + + + multipart/form-data - used for file + transfers + + + + text/xml - used for passing XML data + + + + Other encodings are not used by most web applications. +
+ +
+ Phase Response Headers + + This phase takes place just before response headers are sent back + to the client. Run here if you want to observe the response before that + happens, and if you want to use the response headers to determine if you + want to buffer the response body. Note that some response status codes + (such as 404) are handled earlier in the request cycle by Apache and my + not be able to be triggered as expected. Additionally, there are some + response headers that are added by Apache at a later hook (such as Date, + Server and Connection) that we would not be able to trigger on or + sanitize. This should work appropriately in a proxy setup or within + phase:5 (logging). +
+ +
+ Phase Response Body + + This is the general-purpose output analysis phase. At this point + you can run rules against the response body (provided it was buffered, + of course). This is the phase where you would want to inspect the + outbound HTML for information disclosure, error messages or failed + authentication text. +
+ +
+ Phase Logging + + This phase is run just before logging takes place. The rules + placed into this phase can only affect how the logging is performed. + This phase can be used to inspect the error messages logged by Apache. + You cannot deny/block connections in this phase as it is too late. This + phase also allows for inspection of other response headers that weren't + available during phase:3 or phase:4. Note that you must be careful not + to inherit a disruptive action into a rule in this phase as this is a + configuration error in ModSecurity 2.5.0 and later versions. +
+
+ +
+ Variables + + The following variables are supported in ModSecurity 2.x: + +
+ <literal moreinfo="none">ARGS</literal> + + ARGS is a collection and can be used on its own + (means all arguments including the POST Payload), with a static + parameter (matches arguments with that name), or with a regular + expression (matches all arguments with name that matches the regular + expression). To look at only the query string or body arguments, see the + ARGS_GET and ARGS_POST + collections. + + Some variables are actually collections, which are expanded into + more variables at runtime. The following example will examine all + request arguments:SecRule ARGS dirty + Sometimes, however, you will want to look only at parts of a collection. + This can be achieved with the help of the selection + operator(colon). The following example will only look at the + arguments named p (do note that, in + general, requests can contain multiple arguments with the same name): + SecRule ARGS:p dirty + It is also possible to specify exclusions. The following will examine + all request arguments for the word dirty, except + the ones named z (again, there can be + zero or more arguments named z): + SecRule ARGS|!ARGS:z dirty + There is a special operator that allows you to count how many variables + there are in a collection. The following rule will trigger if there is + more than zero arguments in the request (ignore the second parameter for + the time being): SecRule &ARGS !^0$ + And sometimes you need to look at an array of parameters, each with a + slightly different name. In this case you can specify a regular + expression in the selection operator itself. The following rule will + look into all arguments whose names begin with id_: SecRule ARGS:/^id_/ dirty + + + Using ARGS:p will not result in any + invocations against the operator if argument p does not exist. + + In ModSecurity 1.X, the ARGS variable stood + for QUERY_STRING + POST_PAYLOAD, + whereas now it expands to individual variables. + +
+ +
+ <literal moreinfo="none">ARGS_COMBINED_SIZE</literal> + + This variable allows you to set more targeted evaluations on the + total size of the Arguments as compared with normal Apache LimitRequest + directives. For example, you could create a rule to ensure that the + total size of the argument data is below a certain threshold (to help + prevent buffer overflow issues). Example: Block request if the size of + the arguments is above 25 characters. + + SecRule REQUEST_FILENAME "^/cgi-bin/login\.php" \ + "chain,log,deny,phase:2,t:none,t:lowercase,t:normalisePath" +SecRule ARGS_COMBINED_SIZE "@gt 25" +
+ +
+ <literal moreinfo="none">ARGS_NAMES</literal> + + Is a collection of the argument names. You can search for specific + argument names that you want to block. In a positive policy scenario, + you can also whitelist (using an inverted rule with the ! character) + only authorized argument names. Example: This example rule will only + allow 2 argument names - p and a. If any other argument names are + injected, it will be blocked. + + SecRule REQUEST_FILENAME "/index.php" \ + "chain,log,deny,status:403,phase:2,t:none,t:lowercase,t:normalisePath" +SecRule ARGS_NAMES "!^(p|a)$" "t:none,t:lowercase" +
+ +
+ <literal moreinfo="none">ARGS_GET</literal> + + ARGS_GET is similar to ARGS, + but only contains arguments from the query string. +
+ +
+ <literal moreinfo="none">ARGS_GET_NAMES</literal> + + ARGS_GET_NAMES is similar to + ARGS_NAMES, but only contains argument names from the + query string. +
+ +
+ <literal moreinfo="none">ARGS_POST</literal> + + ARGS_POST is similar to + ARGS, but only contains arguments from the POST + body. +
+ +
+ <literal moreinfo="none">ARGS_POST_NAMES</literal> + + ARGS_POST_NAMES is similar to + ARGS_NAMES, but only contains argument names from the + POST body. +
+ +
+ <literal moreinfo="none">AUTH_TYPE</literal> + + This variable holds the authentication method used to validate a + user. Example: + + SecRule AUTH_TYPE "basic" log,deny,status:403,phase:1,t:lowercase + + Note + + This data will not be available in a proxy-mode deployment as the + authentication is not local. In a proxy-mode deployment, you would need + to inspect the REQUEST_HEADERS:Authorization + header. +
+ +
+ <literal moreinfo="none">ENV</literal> + + Collection, requires a single parameter (after colon). The + ENV variable is set with setenv and does not give + access to the CGI environment variables. Example: + + SecRule REQUEST_FILENAME "printenv" pass,setenv:tag=suspicious +SecRule ENV:tag "suspicious" +
+ +
+ <literal moreinfo="none">FILES</literal> + + Collection. Contains a collection of original file names (as they + were called on the remote user's file system). Note: only available if + files were extracted from the request body. Example: + + SecRule FILES "\.conf$" log,deny,status:403,phase:2 +
+ +
+ <literal moreinfo="none">FILES_COMBINED_SIZE</literal> + + Single value. Total size of the uploaded files. Note: only + available if files were extracted from the request body. Example: + + SecRule FILES_COMBINED_SIZE "@gt 1000" log,deny,status:403,phase:2 +
+ +
+ <literal moreinfo="none">FILES_NAMES</literal> + + Collection w/o parameter. Contains a list of form fields that were + used for file upload. Note: only available if files were extracted from + the request body. Example: + + SecRule FILES_NAMES "^upfile$" log,deny,status:403,phase:2 +
+ +
+ <literal moreinfo="none">FILES_SIZES</literal> + + Collection. Contains a list of file sizes. Useful for implementing + a size limitation on individual uploaded files. Note: only available if + files were extracted from the request body. Example: + + SecRule FILES_SIZES "@gt 100" log,deny,status:403,phase:2 +
+ +
+ <literal moreinfo="none">FILES_TMPNAMES</literal> + + Collection. Contains a collection of temporary files' names on the + disk. Useful when used together with @inspectFile. Note: only available if files + were extracted from the request body. Example: + + SecRule FILES_TMPNAMES "@inspectFile /path/to/inspect_script.pl" +
+ +
+ <literal moreinfo="none">GEO</literal> + + GEO is a collection populated by the results of + the last @geoLookup operator. The + collection can be used to match geographical fields looked from an IP + address or hostname. + + Available since ModSecurity 2.5.0. + + Fields: + + + + COUNTRY_CODE: Two character country code. + EX: US, GB, etc. + + + + COUNTRY_CODE3: Up to three character + country code. + + + + COUNTRY_NAME: The full country + name. + + + + COUNTRY_CONTINENT: The two character + continent that the country is located. EX: EU + + + + REGION: The two character region. For US, + this is state. For Canada, providence, etc. + + + + CITY: The city name if supported by the + database. + + + + POSTAL_CODE: The postal code if supported + by the database. + + + + LATITUDE: The latitude if supported by + the database. + + + + LONGITUDE: The longitude if supported by + the database. + + + + DMA_CODE: The metropolitan area code if + supported by the database. (US only) + + + + AREA_CODE: The phone system area code. + (US only) + + + + Example: + + SecGeoLookupDb /usr/local/geo/data/GeoLiteCity.dat +... +SecRule REMOTE_ADDR "@geoLookup" "chain,drop,msg:'Non-GB IP address'" +SecRule GEO:COUNTRY_CODE "!@streq GB" +
+ +
+ <literal moreinfo="none">HIGHEST_SEVERITY</literal> + + This variable holds the highest severity of any rules that have + matched so far. Severities are numeric values and thus can be used with + comparison operators such as @lt, + etc. + + + Higher severities have a lower numeric value. + + A value of 255 indicates no severity has been set. + + + SecRule HIGHEST_SEVERITY "@le 2" "phase:2,deny,status:500,msg:'severity %{HIGHEST_SEVERITY}'" +
+ +
+ <literal moreinfo="none">MATCHED_VAR</literal> + + This variable holds the value of the variable that was matched + against. It is similar to the TX:0, except it can be used for all + operators and does not require that the capture action be specified. + + SecRule ARGS pattern chain,deny +... +SecRule MATCHED_VAR "further scrutiny" +
+ +
+ <literal moreinfo="none">MATCHED_VAR_NAME</literal> + + This variable holds the full name of the variable that was matched + against. + + SecRule ARGS pattern setvar:tx.mymatch=%{MATCHED_VAR_NAME} +... +SecRule TX:MYMATCH "@eq ARGS:param" deny +
+ +
+ <literal moreinfo="none">MODSEC_BUILD</literal> + + This variable holds the ModSecurity build number. This variable is + intended to be used to check the build number prior to using a feature + that is available only in a certain build. Example: + + SecRule MODSEC_BUILD "!@ge 02050102" skipAfter:12345 +SecRule ARGS "@pm some key words" id:12345,deny,status:500 +
+ +
+ <literal>MULTIPART_CRLF_LF_LINES</literal> + + This flag variable will be set to 1 whenever a + multi-part request uses mixed line terminators. The + multipart/form-data RFC requires + CRLF sequence to be used to terminate lines. Since + some client implementations use only LF to terminate + lines you might want to allow them to proceed under certain + circumstances (if you want to do this you will need to stop using + MULTIPART_STRICT_ERROR and check each multi-part flag + variable individually, avoiding MULTIPART_LF_LINE). + However, mixing CRLF and LF line + terminators is dangerous as it can allow for evasion. Therefore, in such + cases, you will have to add a check for + MULTIPART_CRLF_LF_LINES. +
+ +
+ <literal>MULTIPART_STRICT_ERROR</literal> + + MULTIPART_STRICT_ERROR will be set to + 1 when any of the following variables is also set to + 1: REQBODY_PROCESSOR_ERROR, + MULTIPART_BOUNDARY_QUOTED, + MULTIPART_BOUNDARY_WHITESPACE, + MULTIPART_DATA_BEFORE, + MULTIPART_DATA_AFTER, + MULTIPART_HEADER_FOLDING, + MULTIPART_LF_LINE, + MULTIPART_SEMICOLON_MISSING + MULTIPART_INVALID_QUOTING. Each of these variables + covers one unusual (although sometimes legal) aspect of the request body + in multipart/form-data format. Your policies should + always contain a rule to check either this variable + (easier) or one or more individual variables (if you know exactly what + you want to accomplish). Depending on the rate of false positives and + your default policy you should decide whether to block or just warn when + the rule is triggered. + + The best way to use this variable is as in the example + below: + + SecRule MULTIPART_STRICT_ERROR "!@eq 0" \ +"phase:2,t:none,log,deny,msg:'Multipart request body \ +failed strict validation: \ +PE %{REQBODY_PROCESSOR_ERROR}, \ +BQ %{MULTIPART_BOUNDARY_QUOTED}, \ +BW %{MULTIPART_BOUNDARY_WHITESPACE}, \ +DB %{MULTIPART_DATA_BEFORE}, \ +DA %{MULTIPART_DATA_AFTER}, \ +HF %{MULTIPART_HEADER_FOLDING}, \ +LF %{MULTIPART_LF_LINE}, \ +SM %{MULTIPART_SEMICOLON_MISSING}, \ +IQ %{MULTIPART_INVALID_QUOTING}'" + + The multipart/form-data parser was upgraded in + ModSecurity v2.1.3 to actively look for signs of evasion. Many variables + (as listed above) were added to expose various facts discovered during + the parsing process. The MULTIPART_STRICT_ERROR + variable is handy to check on all abnormalities at once. The individual + variables allow detection to be fine-tuned according to your + circumstances in order to reduce the number of false positives. Detailed + analysis of various evasion techniques covered will be released as a + separated document at a later date. +
+ +
+ <literal>MULTIPART_UNMATCHED_BOUNDARY</literal> + + Set to 1 when, during the parsing phase of a + multipart/request-body, ModSecurity encounters what + feels like a boundary but it is not. Such an event may occur when + evasion of ModSecurity is attempted. + + The best way to use this variable is as in the example + below: + + SecRule MULTIPART_UNMATCHED_BOUNDARY "!@eq 0" \ +"phase:2,t:none,log,deny,msg:'Multipart parser detected a possible unmatched boundary.'" + + Change the rule from blocking to logging-only if many false + positives are encountered. +
+ +
+ <literal moreinfo="none">PATH_INFO</literal> + + Besides passing query information to a script/handler, you can + also pass additional data, known as extra path information, as part of + the URL. Example: + + SecRule PATH_INFO "^/(bin|etc|sbin|opt|usr)" +
+ +
+ <literal moreinfo="none">QUERY_STRING</literal> + + This variable holds form data passed to the script/handler by + appending data after a question mark. Warning: Not URL-decoded. + Example: + + SecRule QUERY_STRING "attack" +
+ +
+ <literal moreinfo="none">REMOTE_ADDR</literal> + + This variable holds the IP address of the remote client. + Example: + + SecRule REMOTE_ADDR "^192\.168\.1\.101$" +
+ +
+ <literal moreinfo="none">REMOTE_HOST</literal> + + If HostnameLookUps are set to On, then this variable will hold the + DNS resolved remote host name. If it is set to Off, then it will hold + the remote IP address. Possible uses for this variable would be to deny + known bad client hosts or network blocks, or conversely, to allow in + authorized hosts. Example: + + SecRule REMOTE_HOST "\.evil\.network\org$" +
+ +
+ <literal moreinfo="none">REMOTE_PORT</literal> + + This variable holds information on the source port that the client + used when initiating the connection to our web server. Example: in this + example, we are evaluating to see if the REMOTE_PORT + is less than 1024, which would indicate that the user is a privileged + user (root). + + SecRule REMOTE_PORT "@lt 1024" phase:1,log,pass,setenv:remote_port=privileged +
+ +
+ <literal moreinfo="none">REMOTE_USER</literal> + + This variable holds the username of the authenticated user. If + there are no password (basic|digest) access controls in place, then this + variable will be empty. Example: + + SecRule REMOTE_USER "admin" + + Note + + This data will not be available in a proxy-mode deployment as the + authentication is not local. +
+ +
+ <literal moreinfo="none">REQBODY_PROCESSOR</literal> + + Built-in processors are URLENCODED, + MULTIPART, and XML. + Example: + + SecRule REQBODY_PROCESSOR "^XML$ chain +SecRule XML "@validateDTD /opt/apache-frontend/conf/xml.dtd" +
+ +
+ <literal + moreinfo="none">REQBODY_PROCESSOR_ERROR</literal> + + Possible values are 0 (no error) or 1 (error). This variable will + be set by request body processors (typically the + multipart/request-data parser or the XML parser) + when they fail to properly parse a request payload. + + Example: + + SecRule REQBODY_PROCESSOR_ERROR "@eq 1" deny,phase:2 + + + Your policies must have a rule to check + REQBODY_PROCESSOR_ERROR at the beginning of phase 2. Failure to do so + will leave the door open for impedance mismatch attacks. It is + possible, for example, that a payload that cannot be parsed by + ModSecurity can be successfully parsed by more tolerant parser + operating in the application. If your policy dictates blocking then + you should reject the request if error is detected. When operating in + detection-only mode your rule should alert with high severity when + request body processing fails. + +
+ +
+ <literal + moreinfo="none">REQBODY_PROCESSOR_ERROR_MSG</literal> + + Empty, or contains the error message from the processor. + Example: + + SecRule REQBODY_PROCESSOR_ERROR_MSG "failed to parse" t:lowercase +
+ +
+ <literal moreinfo="none">REQUEST_BASENAME</literal> + + This variable holds just the filename part of + REQUEST_FILENAME (e.g. index.php). + + Example: + + SecRule REQUEST_BASENAME "^login\.php$" phase:2,t:none,t:lowercase + + + Please note that anti-evasion transformations are not applied to + this variable by default. REQUEST_BASENAME will + recognise both / and \ as path + separators. + +
+ +
+ <literal moreinfo="none">REQUEST_BODY</literal> + + This variable holds the data in the request body (including + POST_PAYLOAD data). REQUEST_BODY + should be used if the original order of the arguments is important + (ARGS should be used in all other cases). + Example: + + SecRule REQUEST_BODY "^username=\w{25,}\&password=\w{25,}\&Submit\=login$" + + + This variable is only available if the + URLENCODED request body processor parsed a request + body. This will occur by default when an + application/x-www-form-urlencoded is detected, or + the URLENCODED request body parser is forced. As of + 2.5.7 it is possible to force the presence of the + REQUEST_BODY variable, but only when there is no + request body processor defined, using the + ctl:forceRequestBodyVariable option in the + REQUEST_HEADERS phase. + +
+ +
+ <literal moreinfo="none">REQUEST_COOKIES</literal> + + This variable is a collection of all of the cookie data. Example: + the following example is using the Ampersand special operator to count + how many variables are in the collection. In this rule, it would trigger + if the request does not include any Cookie headers. + + SecRule &REQUEST_COOKIES "@eq 0" +
+ +
+ <literal moreinfo="none">REQUEST_COOKIES_NAMES</literal> + + This variable is a collection of the cookie names in the request + headers. Example: the following rule will trigger if the JSESSIONID + cookie is not present. + + SecRule &REQUEST_COOKIES_NAMES:JSESSIONID "@eq 0" +
+ +
+ <literal moreinfo="none">REQUEST_FILENAME</literal> + + This variable holds the relative REQUEST_URI + minus the QUERY_STRING part (e.g. /index.php). + Example: + + SecRule REQUEST_FILENAME "^/cgi-bin/login\.php$" phase:2,t:none,t:normalisePath + + + Please note that anti-evasion transformations are not used on + REQUEST_FILENAME by default. + +
+ +
+ <literal moreinfo="none">REQUEST_HEADERS</literal> + + This variable can be used as either a collection of all of the + request headers or can be used to specify individual headers (by using + REQUEST_HEADERS:Header-Name). Example: the first + example uses REQUEST_HEADERS as a collection and is + applying the validateUrlEncoding operator against all + headers. + + SecRule REQUEST_HEADERS "@validateUrlEncoding" + + Example: the second example is targeting only the + Host header. + + SecRule REQUEST_HEADERS:Host "^[\d\.]+$" \ + "deny,log,status:400,msg:'Host header is a numeric IP address'" +
+ +
+ <literal moreinfo="none">REQUEST_HEADERS_NAMES</literal> + + This variable is a collection of the names of all of the request + headers. Example: + + SecRule REQUEST_HEADERS_NAMES "^x-forwarded-for" \ + "log,deny,status:403,t:lowercase,msg:'Proxy Server Used'" +
+ +
+ <literal moreinfo="none">REQUEST_LINE</literal> + + This variable holds the complete request line sent to the server + (including the REQUEST_METHOD and HTTP version data). Example: this + example rule will trigger if the request method is something other than + GET, HEAD, POST or if the HTTP is something other than HTTP/0.9, 1.0 or + 1.1. + + SecRule REQUEST_LINE "!(^((?:(?:pos|ge)t|head))|http/(0\.9|1\.0|1\.1)$)" t:none,t:lowercase +
+ +
+ <literal moreinfo="none">REQUEST_METHOD</literal> + + This variable holds the request method used by the client. + + The following example will trigger if the request method is either + CONNECT or TRACE. + + SecRule REQUEST_METHOD "^((?:connect|trace))$" t:none,t:lowercase +
+ +
+ <literal moreinfo="none">REQUEST_PROTOCOL</literal> + + This variable holds the request protocol version information. + Example: + + SecRule REQUEST_PROTOCOL "!^http/(0\.9|1\.0|1\.1)$" t:none,t:lowercase +
+ +
+ <literal moreinfo="none">REQUEST_URI</literal> + + This variable holds the full URL including the + QUERY_STRING data (e.g. /index.php?p=X), however it + will never contain a domain name, even if it was provided on the request + line. It also does not include either the + REQUEST_METHOD or the HTTP version info. + + Example: + + SecRule REQUEST_URI "attack" phase:1,t:none,t:urlDecode,t:lowercase,t:normalisePath + + + Please note that anti-evasion transformations are not used on + REQUEST_URI by default. + +
+ +
+ <literal moreinfo="none">REQUEST_URI_RAW</literal> + + Same as REQUEST_URI but will contain the domain + name if it was provided on the request line (e.g. + http://www.example.com/index.php?p=X). + + Example: + + SecRule REQUEST_URI_RAW "http:/" phase:1,t:none,t:urlDecode,t:lowercase,t:normalisePath + + + Please note that anti-evasion transformations are not used on + REQUEST_URI_RAW by default. + +
+ +
+ <literal moreinfo="none">RESPONSE_BODY</literal> + + This variable holds the data for the response payload. + + Example: + + SecRule RESPONSE_BODY "ODBC Error Code" +
+ +
+ <literal>RESPONSE_CONTENT_LENGTH</literal> + + Response body length in bytes. Can be available starting with + phase 3 but it does not have to be (as the length of response body is + not always known in advance.) If the size is not known this variable + will contain a zero. If RESPONSE_CONTENT_LENGTH + contains a zero in phase 5 that means the actual size of the response + body was 0. + + The value of this variable can change between phases if the body + is modified. For example, in embedded mode + mod_deflate can compress the response body between + phases 4 and 5. +
+ +
+ <literal>RESPONSE_CONTENT_TYPE</literal> + + Response content type. Only available starting with phase + 3. +
+ +
+ <literal moreinfo="none">RESPONSE_HEADERS</literal> + + This variable is similar to the REQUEST_HEADERS variable and can + be used in the same manner. Example: + + SecRule RESPONSE_HEADERS:X-Cache "MISS" + + Note + + This variable may not have access to some headers when running in + embedded-mode. Headers such as Server, Date, Connection and Content-Type + are added during a later Apache hook just prior to sending the data to + the client. This data should be available, however, either during + ModSecurity phase:5 (logging) or when running in proxy-mode. +
+ +
+ <literal moreinfo="none">RESPONSE_HEADERS_NAMES</literal> + + This variable is a collection of the response header names. + Example: + + SecRule RESPONSE_HEADERS_NAMES "Set-Cookie" + + Note + + Same limitations as RESPONSE_HEADERS with regards to access to + some headers in embedded-mode. +
+ +
+ <literal moreinfo="none">RESPONSE_PROTOCOL</literal> + + This variable holds the HTTP response protocol information. + Example: + + SecRule RESPONSE_PROTOCOL "^HTTP\/0\.9" +
+ +
+ <literal moreinfo="none">RESPONSE_STATUS</literal> + + This variable holds the HTTP response status code as generated by + Apache. Example: + + SecRule RESPONSE_STATUS "^[45]" + + Note + + This directive may not work as expected in embedded-mode as Apache + handles many of the stock response codes (404, 401, etc...) earlier in + Phase 2. This variable should work as expected in a proxy-mode + deployment. +
+ +
+ <literal moreinfo="none">RULE</literal> + + This variable provides access to the id, rev, + severity, logdata, and msg fields of the rule that triggered the + action. Only available for expansion in action strings (e.g.setvar:tx.varname=%{rule.id}). Example: + + SecRule &REQUEST_HEADERS:Host "@eq 0" "log,deny,setvar:tx.varname=%{rule.id}" +
+ +
+ <literal moreinfo="none">SCRIPT_BASENAME</literal> + + This variable holds just the local filename part of + SCRIPT_FILENAME. Example: + + SecRule SCRIPT_BASENAME "^login\.php$" + + Note + + This variable is not available in proxy mode. +
+ +
+ <literal moreinfo="none">SCRIPT_FILENAME</literal> + + This variable holds the full path on the server to the requested + script. (e.g. SCRIPT_NAME plus the server path). Example: + + SecRule SCRIPT_FILENAME "^/usr/local/apache/cgi-bin/login\.php$" + + Note + + This variable is not available in proxy mode. +
+ +
+ <literal moreinfo="none">SCRIPT_GID</literal> + + This variable holds the group id (numerical value) of the group + owner of the script. Example: + + SecRule SCRIPT_GID "!^46$" + + Note + + This variable is not available in proxy mode. +
+ +
+ <literal moreinfo="none">SCRIPT_GROUPNAME</literal> + + This variable holds the group name of the group owner of the + script. Example: + + SecRule SCRIPT_GROUPNAME "!^apache$" + + Note + + This variable is not available in proxy mode. +
+ +
+ <literal moreinfo="none">SCRIPT_MODE</literal> + + This variable holds the script's permissions mode data (numerical + - 1=execute, 2=write, 4=read and 7=read/write/execute). Example: will + trigger if the script has the WRITE permissions set. + + SecRule SCRIPT_MODE "^(2|3|6|7)$" + + Note + + This variable is not available in proxy mode. +
+ +
+ <literal moreinfo="none">SCRIPT_UID</literal> + + This variable holds the user id (numerical value) of the owner of + the script. Example: the example rule below will trigger if the UID is + not 46 (the Apache user). + + SecRule SCRIPT_UID "!^46$" + + Note + + This variable is not available in proxy mode. +
+ +
+ <literal moreinfo="none">SCRIPT_USERNAME</literal> + + This variable holds the username of the owner of the script. + Example: + + SecRule SCRIPT_USERNAME "!^apache$" + + Note + + This variable is not available in proxy mode. +
+ +
+ <literal moreinfo="none">SERVER_ADDR</literal> + + This variable contains the IP address of the server. + Example: + + SecRule SERVER_ADDR "^192\.168\.1\.100$" +
+ +
+ <literal moreinfo="none">SERVER_NAME</literal> + + This variable contains the server's hostname or IP address. + Example: + + SecRule SERVER_NAME "hostname\.com$" + + Note + + This data is taken from the Host header submitted in the client + request. +
+ +
+ <literal moreinfo="none">SERVER_PORT</literal> + + This variable contains the local port that the web server is + listening on. Example: + + SecRule SERVER_PORT "^80$" +
+ +
+ <literal moreinfo="none">SESSION</literal> + + This variable is a collection, available only after setsid is executed. Example: the following + example shows how to initialize a SESSION collection with setsid, how to + use setvar to increase the session.score values, how to set the + session.blocked variable and finally how to deny the connection based on + the session:blocked value. + + SecRule REQUEST_COOKIES:PHPSESSID !^$ chain,nolog,pass +SecAction setsid:%{REQUEST_COOKIES.PHPSESSID} +SecRule REQUEST_URI "^/cgi-bin/finger$" \ + "phase:2,t:none,t:lowercase,t:normalisePath,pass,log,setvar:session.score=+10" +SecRule SESSION:SCORE "@gt 50" "pass,log,setvar:session.blocked=1" +SecRule SESSION:BLOCKED "@eq 1" "log,deny,status:403" +
+ +
+ <literal moreinfo="none">SESSIONID</literal> + + This variable is the value set with setsid. Example: + + SecRule SESSIONID !^$ chain,nolog,pass +SecRule REQUEST_COOKIES:PHPSESSID !^$ +SecAction setsid:%{REQUEST_COOKIES.PHPSESSID} +
+ +
+ <literal moreinfo="none">TIME</literal> + + This variable holds a formatted string representing the time + (hour:minute:second). Example: + + SecRule TIME "^(([1](8|9))|([2](0|1|2|3))):\d{2}:\d{2}$" +
+ +
+ <literal moreinfo="none">TIME_DAY</literal> + + This variable holds the current date (1-31). Example: this rule + would trigger anytime between the 10th and 20th days of the + month. + + SecRule TIME_DAY "^(([1](0|1|2|3|4|5|6|7|8|9))|20)$" +
+ +
+ <literal moreinfo="none">TIME_EPOCH</literal> + + This variable holds the time in seconds since 1970. + Example: + + SecRule TIME_EPOCH "@gt 1000" +
+ +
+ <literal moreinfo="none">TIME_HOUR</literal> + + This variable holds the current hour (0-23). Example: this rule + would trigger during "off hours". + + SecRule TIME_HOUR "^(0|1|2|3|4|5|6|[1](8|9)|[2](0|1|2|3))$" +
+ +
+ <literal moreinfo="none">TIME_MIN</literal> + + This variable holds the current minute (0-59). Example: this rule + would trigger during the last half hour of every hour. + + SecRule TIME_MIN "^(3|4|5)" +
+ +
+ <literal moreinfo="none">TIME_MON</literal> + + This variable holds the current month (0-11). Example: this rule + would match if the month was either November (10) or December + (11). + + SecRule TIME_MON "^1" +
+ +
+ <literal moreinfo="none">TIME_SEC</literal> + + This variable holds the current second count (0-59). + Example: + + SecRule TIME_SEC "@gt 30" +
+ +
+ <literal moreinfo="none">TIME_WDAY</literal> + + This variable holds the current weekday (0-6). Example: this rule + would trigger only on week-ends (Saturday and Sunday). + + SecRule TIME_WDAY "^(0|6)$" +
+ +
+ <literal moreinfo="none">TIME_YEAR</literal> + + This variable holds the current four-digit year data. + Example: + + SecRule TIME_YEAR "^2006$" +
+ +
+ <literal moreinfo="none">TX</literal> + + Transaction Collection. This is used to store pieces of data, + create a transaction anomaly score, and so on. Transaction variables are + set for 1 request/response cycle. The scoring and evaluation will not + last past the current request/response process. Example: In this + example, we are using setvar to increase the tx.score value by 5 points. + We then have a follow-up run that will evaluate the transactional score + this request and then it will decided whether or not to allow/deny the + request through. + + The following is a list of reserved names in the TX + collection: + + + + TX:0 - The matching value + when using the @rx or @pm operator with the capture action. + + + + TX:1-TX:9 - The captured + subexpression value when using the @rx operator with capturing parens and the + capture action. + + + + SecRule WEBSERVER_ERROR_LOG "does not exist" "phase:5,pass,setvar:tx.score=+5" +SecRule TX:SCORE "@gt 20" deny,log +
+ +
+ <literal moreinfo="none">USERID</literal> + + This variable is the value set with setuid. Example: + + SecAction setuid:%{REMOTE_USER},nolog +SecRule USERID "Admin" +
+ +
+ <literal moreinfo="none">WEBAPPID</literal> + + This variable is the value set with SecWebAppId. Example: + + SecWebAppId "WebApp1" +SecRule WEBAPPID "WebApp1" "chain,log,deny,status:403" +SecRule REQUEST_HEADERS:Transfer-Encoding "!^$" +
+ +
+ <literal moreinfo="none">WEBSERVER_ERROR_LOG</literal> + + Contains zero or more error messages produced by the web server. + Access to this variable is in phase:5 (logging). Example: + + SecRule WEBSERVER_ERROR_LOG "File does not exist" "phase:5,setvar:tx.score=+5" +
+ +
+ <literal moreinfo="none">XML</literal> + + Can be used standalone (as a target for + validateDTD and validateSchema) or + with an XPath expression parameter (which makes it a valid target for + any function that accepts plain text). Example using XPath: + + SecDefaultAction log,deny,status:403,phase:2 +SecRule REQUEST_HEADERS:Content-Type ^text/xml$ \ + phase:1,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML +SecRule REQBODY_PROCESSOR "!^XML$" skipAfter:12345 +SecRule XML:/employees/employee/name/text() Fred +SecRule XML:/xq:employees/employee/name/text() Fred \ + id:12345,xmlns:xq=http://www.example.com/employees + + The first XPath expression does not use namespaces. It would match + against payload such as this one: + + <employees> + <employee> + <name>Fred Jones</name> + <address location="home"> + <street>900 Aurora Ave.</street> + <city>Seattle</city> + <state>WA</state> + <zip>98115</zip> + </address> + <address location="work"> + <street>2011 152nd Avenue NE</street> + <city>Redmond</city> + <state>WA</state> + <zip>98052</zip> + </address> + <phone location="work">(425)555-5665</phone> + <phone location="home">(206)555-5555</phone> + <phone location="mobile">(206)555-4321</phone> + </employee> +</employees> + + The second XPath expression does use namespaces. It would match + the following payload: + + <xq:employees xmlns:xq="http://www.example.com/employees"> + <employee> + <name>Fred Jones</name> + <address location="home"> + <street>900 Aurora Ave.</street> + <city>Seattle</city> + <state>WA</state> + <zip>98115</zip> + </address> + <address location="work"> + <street>2011 152nd Avenue NE</street> + <city>Redmond</city> + <state>WA</state> + <zip>98052</zip> + </address> + <phone location="work">(425)555-5665</phone> + <phone location="home">(206)555-5555</phone> + <phone location="mobile">(206)555-4321</phone> + </employee> +</xq:employees> + + Note the different namespace used in the second example. + + To learn more about XPath we suggest the following + resources: + + + + XPath + Standard + + + + XPath + Tutorial + + +
+
+ +
+ Transformation functions + + When ModSecurity receives request or response information, it makes + a copy of this data and places it into memory. It is on this data in + memory that transformation functions are applied. The raw request/response + data is never altered. Transformation functions are used to transform a + variable before testing it in a rule. + + Note + + There are no default transformation functions as there were in + previous versions of ModSecurity. + + The following rule will ensure that an attacker does not use mixed + case in order to evade the ModSecurity rule: + + SecRule ARGS:p "xp_cmdshell" "t:lowercase" + multiple transformation actions can be used in the same rule, for example + the following rule also ensures that an attacker does not use URL encoding + (%xx encoding) for evasion. Note the order of the transformation + functions, which ensures that a URL encoded letter is first decoded and + than translated to lower case. + + SecRule ARGS:p "xp_cmdshell" "t:urlDecode,t:lowercase" + + One can use the SecDefaultAction command to ensure the translation + occurs for every rule until the next. Note that transformation actions are + additive, so if a rule explicitly list actions, the translation actions + set by SecDefaultAction are still performed. + + SecDefaultAction t:urlDecode,t:lowercase + + The following transformation functions are supported: + +
+ <literal>base64Decode</literal> + + This function decodes a base64-encoded string. +
+ +
+ <literal>base64Encode</literal> + + This function encodes input string using base64 encoding. +
+ +
+ <literal>compressWhitespace</literal> + + It converts whitespace characters (32, \f, \t, \n, \r, \v, 160) to + spaces (ASCII 32) and then compresses multiple consecutive space + characters into one. +
+ +
+ cssDecode + + Decodes CSS-encoded characters, as specified at http://www.w3.org/TR/REC-CSS2/syndata.html. + This function uses only up to two bytes in the decoding process, meaning + it is useful to uncover ASCII characters (that wouldn't normally be + encoded) encoded using CSS encoding, or to counter evasion which is a + combination of a backslash and non-hexadecimal characters (e.g. + ja\vascript is equivalent to + javascript). +
+ +
+ <literal>escapeSeqDecode</literal> + + This function decode ANSI C escape sequences: \a, \b, + \f, \n, \r, + \t, \v, \\, + \?, \', \", + \xHH (hexadecimal), \0OOO (octal). Invalid encodings are left in + the output. +
+ +
+ <literal>hexDecode</literal> + + This function decodes a hex-encoded string. +
+ +
+ <literal>hexEncode</literal> + + This function encodes input as hex-encoded string. +
+ +
+ <literal>htmlEntityDecode</literal> + + This function decodes HTML entities present in input. The + following variants are supported: + + + + &#xHH and &#xHH; (where H is any hexadecimal + number) + + + + &#DDD and &#DDD; (where D is any decimal + number) + + + + &quot and &quot; + + + + &nbsp and &nbsp; + + + + &lt and &lt; + + + + &gt and &gt; + + + + This function will convert any entity into a single byte only, + possibly resulting in a loss of information. It is thus useful to + uncover bytes that would otherwise not need to be encoded, but it cannot + do anything with the characters from the range above 255. +
+ +
+ <literal>jsDecode</literal> + + Decodes JavaScript escape sequences. If a + \uHHHH code is in the range of + FF01-FF5E (the full width ASCII + codes), then the higher byte is used to detect and adjust the lower + byte. Otherwise, only the lower byte will be used and the higher byte + zeroed. +
+ +
+ <literal>length</literal> + + This function converts the input to its numeric length (count of + bytes). +
+ +
+ <literal>lowercase</literal> + + This function converts all characters to lowercase using the + current C locale. +
+ +
+ <literal>md5</literal> + + This function calculates an MD5 hash from input. Note that the + computed hash is in a raw binary form and may need encoded into text to + be usable (for example: t:md5,t:hexEncode). +
+ +
+ <literal><literal>none</literal></literal> + + Not an actual transformation function, but an instruction to + ModSecurity to remove all transformation functions associated with the + current rule. +
+ +
+ <literal>normalisePath</literal> + + This function will remove multiple slashes, self-references and + directory back-references (except when they are at the beginning of the + input). +
+ +
+ <literal>normalisePathWin</literal> + + Same as normalisePath, but will first convert + backslash characters to forward slashes. +
+ +
+ <literal>parityEven7bit</literal> + + This function calculates even parity of 7-bit data replacing the + 8th bit of each target byte with the calculated parity bit. +
+ +
+ <literal>parityOdd7bit</literal> + + This function calculates odd parity of 7-bit data replacing the + 8th bit of each target byte with the calculated parity bit. +
+ +
+ <literal>parityZero7bit</literal> + + This function calculates zero parity of 7-bit data replacing the + 8th bit of each target byte with a zero parity bit which allows + inspection of even/odd parity 7bit data as ASCII7 data. +
+ +
+ <literal>removeNulls</literal> + + This function removes NULL bytes from input. +
+ +
+ <literal>removeWhitespace</literal> + + This function removes all whitespace characters from input. +
+ +
+ <literal>replaceComments</literal> + + This function replaces each occurrence of a C-style comments + (/* ... */) with a single space + (multiple consecutive occurrences of a space will not be compressed). + Unterminated comments will too be replaced with a space (ASCII 32). + However, a standalone termination of a comment (*/) will not be acted upon. +
+ +
+ <literal>replaceNulls</literal> + + This function is enabled by default. It replaces NULL bytes in + input with spaces (ASCII 32). +
+ +
+ <literal>urlDecode</literal> + + This function decodes an URL-encoded input string. Invalid + encodings (i.e. the ones that use non-hexadecimal characters, or the + ones that are at the end of string and have one or two characters + missing) will not be converted. If you want to detect invalid encodings + use the @validateUrlEncoding + operator. The transformation function should not be used against + variables that have already been URL-decoded unless it is your intention + to perform URL decoding twice! +
+ +
+ <literal>urlDecodeUni</literal> + + In addition to decoding %xx like urlDecode, urlDecodeUni also decodes %uXXXX encoding. If the code is in the range + of FF01-FF5E (the full width ASCII + codes), then the higher byte is used to detect and adjust the lower + byte. Otherwise, only the lower byte will be used and the higher byte + zeroed. +
+ +
+ <literal>urlEncode</literal> + + This function encodes input using URL encoding. +
+ +
+ <literal>sha1</literal> + + This function calculates a SHA1 hash from input. Note that the + computed hash is in a raw binary form and may need encoded to be usable + (for example: t:sha1,t:hexEncode). +
+ +
+ <literal>trimLeft</literal> + + This function removes whitespace from the left side of + input. +
+ +
+ <literal>trimRight</literal> + + This function removes whitespace from the right side of + input. +
+ +
+ <literal>trim</literal> + + This function removes whitespace from both the left and right + sides of input. +
+
+ +
+ Actions + + Each action belongs to one of five groups: + + + + Disruptive actions + + + Cause ModSecurity to do something. In many cases something + means block transaction, but not in all. For example, the allow + action is classified as a disruptive action, but it does the + opposite of blocking. There can only be one disruptive action per + rule (if there are multiple disruptive actions present, or + inherited, only the last one will take effect), or rule chain (in a + chain, a disruptive action can only appear in the first + rule). + + + + + Non-disruptive actions + + + Do something, but that something does not and cannot affect + the rule processing flow. Setting a variable, or changing its value + is an example of a non-disruptive action. Non-disruptive action can + appear in any rule, including each rule belonging to a chain. + + + + + Flow actions + + + These actions affect the rule flow (for example + skip or skipAfter). + + + + + Meta-data actions + + + Meta-data actions are used to provide more information about + rules. Examples include id, + rev, severity and + msg. + + + + + Data actions + + + Not really actions, these are mere containers that hold data + used by other actions. For example, the status + action holds the status that will be used for blocking (if it takes + place). + + + + +
+ <literal>allow</literal> + + Description: Stops rule processing on a + successful match and allows the transaction to proceed. + + Action Group: Disruptive + + Example: + + SecRule REMOTE_ADDR "^192\.168\.1\.100$" nolog,phase:1,allow + + Prior to ModSecurity 2.5 the allow action would + only affect the current phase. An allow in phase 1 + would skip processing the remaining rules in phase 1 but the rules from + phase 2 would execute. Starting with v2.5.0 allow was + enhanced to allow for fine-grained control of what is done. The + following rules now apply: + + + + If used one its own, like in the example above, + allow will affect the entire transaction, + stopping processing of the current phase but also skipping over all + other phases apart from the logging phase. (The logging phase is + special; it is designed to always execute.) + + + + If used with parameter "phase", allow will + cause the engine to stop processing the current phase. Other phases + will continue as normal. + + + + If used with parameter "request", allow + will cause the engine to stop processing the current phase. The next + phase to be processed will be phase + RESPONSE_HEADERS. + + + + Examples: + + # Do not process request but process response. +SecAction phase:1,allow:request + +# Do not process transaction (request and response). +SecAction phase:1,allow + + + If you want to allow a response through, put a rule in phase + RESPONSE_HEADERS and simply use + allow on its own: + + # Allow response through. +SecAction phase:3,allow +
+ +
+ append + + Description: Appends text given as parameter + to the end of response body. For this action to work content injection + must be enabled by setting SecContentInjection to + On. Also make sure you check the content type of the + response before you make changes to it (e.g. you don't want to inject + stuff into images). + + Action Group: Non-disruptive + + Processing Phases: 3 and 4. + + Example: + + SecRule RESPONSE_CONTENT_TYPE "^text/html" "nolog,pass,append:'<hr>Footer'" + + + While macro expansion is allowed in the additional content, you + are strongly cautioned against inserting user defined data + fields. + +
+ +
+ <literal>auditlog</literal> + + Description: Marks the transaction for + logging in the audit log. + + Action Group: Non-disruptive + + Example: + + SecRule REMOTE_ADDR "^192\.168\.1\.100$" auditlog,phase:1,allow + + Note + + The auditlog action is now explicit if log is already + specified. +
+ +
+ <literal>block</literal> + + Description: Performs the default disruptive + action. + + Action Group: Disruptive + + It is intended to be used by ruleset writers to signify that the + rule was intended to block and leaves the "how" up to the administrator. + This action is currently a placeholder which will just be replaced by + the action from the last SecDefaultAction in the same + context. Using the block action with the + SecRuleUpdateActionById directive allows a rule to be + reverted back to the previous SecDefaultAction + disruptive action. + + In future versions of ModSecurity, more control and functionality + will be added to define "how" to block. + + Examples: + + In the following example, the second rule will "deny" because of + the SecDefaultAction disruptive action. The intent being that the + administrator could easily change this to another disruptive action + without editing the actual rules. + + ### Administrator defines "how" to block (deny,status:403)... +SecDefaultAction phase:2,deny,status:403,log,auditlog + +### Included from a rulest... +# Intent is to warn for this User Agent +SecRule REQUEST_HEADERS:User-Agent "perl" "phase:2,pass,msg:'Perl based user agent identified'" +# Intent is to block for this User Agent, "how" described in SecDefaultAction +SecRule REQUEST_HEADERS:User-Agent "nikto" "phase:2,block,msg:'Nikto Scanners Identified'" + + In the following example, The rule is reverted back to the + pass action defined in the SecDefaultAction directive + by using the SecRuleUpdateActionById directive in + conjuction with the block action. This allows an + administrator to override an action in a 3rd party rule without + modifying the rule itself. + + ### Administrator defines "how" to block (deny,status:403)... +SecDefaultAction phase:2,pass,log,auditlog + +### Included from a rulest... +SecRule REQUEST_HEADERS:User-Agent "nikto" "id:1,phase:2,deny,msg:'Nikto Scanners Identified'" + +### Added by the administrator +SecRuleUpdateActionById 1 "block" +
+ +
+ <literal>capture</literal> + + Description: When used together with the + regular expression operator, capture action will create copies of + regular expression captures and place them into the transaction variable + collection. Up to ten captures will be copied on a successful pattern + match, each with a name consisting of a digit from 0 to 9. + + Action Group: Non-disruptive + + Example: + + SecRule REQUEST_BODY "^username=(\w{25,})" phase:2,capture,t:none,chain +SecRule TX:1 "(?:(?:a(dmin|nonymous)))" + + Note + + The 0 data captures the entire REGEX match and 1 captures the data + in the first parens, etc... +
+ +
+ <literal>chain</literal> + + Description: Chains the rule where the action + is placed with the rule that immediately follows it. The result is + called a rule chain. Chained rules allow for more + complex rule matches where you want to use a number of different + VARIABLES to create a better rule and to help prevent false + positives. + + Action Group: Flow + + Example: + + # Refuse to accept POST requests that do +# not specify request body length. Do note that +# this rule should be preceeded by a rule that verifies +# only valid request methods (e.g. GET, HEAD and POST) are used. +SecRule REQUEST_METHOD ^POST$ chain,t:none +SecRule REQUEST_HEADERS:Content-Length ^$ t:none + + + In programming language concepts, think of chained rules + somewhat similar to AND conditional statements. The actions specified + in the first portion of the chained rule will only be triggered if all + of the variable checks return positive hits. If one aspect of the + chained rule is negative, then the entire rule chain is negative. Also + note that disruptive actions, execution phases, metadata actions (id, + rev, msg), skip and skipAfter actions can only be specified on by the + chain starter rule. + +
+ +
+ <literal>ctl</literal> + + Description: The ctl action allows + configuration options to be updated for the transaction. + + Action Group: Non-disruptive + + Example: + + # Parse requests with Content-Type "text/xml" as XML +SecRule REQUEST_CONTENT_TYPE ^text/xml nolog,pass,ctl:requestBodyProcessor=XML + + Note + + The following configuration options are supported: + + + + auditEngine + + + + auditLogParts + + + + debugLogLevel + + + + ruleRemoveById (single rule + ID, or a single rule ID range accepted as parameter) + + + + requestBodyAccess + + + + forceRequestBodyVariable + + + + requestBodyLimit + + + + requestBodyProcessor + + + + responseBodyAccess + + + + responseBodyLimit + + + + ruleEngine + + + + With the exception of + requestBodyProcessor and + forceRequestBodyVariable, each configuration option + corresponds to one configuration directive and the usage is + identical. + + The requestBodyProcessor option allows you to + configure the request body processor. By default ModSecurity will use + the URLENCODED and MULTIPART processors to process an application/x-www-form-urlencoded and a + multipart/form-data bodies, + respectively. A third processor, XML, is also + supported, but it is never used implicitly. Instead you must tell + ModSecurity to use it by placing a few rules in the REQUEST_HEADERS processing phase. After the + request body was processed as XML you will be able to use the + XML-related features to inspect it. + + Request body processors will not interrupt a transaction if an + error occurs during parsing. Instead they will set variables REQBODY_PROCESSOR_ERROR and REQBODY_PROCESSOR_ERROR_MSG. These variables + should be inspected in the REQUEST_BODY phase and an appropriate action + taken. + + The forceRequestBodyVariable option allows you + to configure the REQUEST_BODY variable to be set when + there is no request body processor configured. This allows for + inspection of request bodies of unknown types. +
+ +
+ <literal>deny</literal> + + Description: Stops rule processing and + intercepts transaction. + + Action Group: Disruptive + + Example: + + SecRule REQUEST_HEADERS:User-Agent "nikto" "log,deny,msg:'Nikto Scanners Identified'" +
+ +
+ <literal>deprecatevar</literal> + + Description: Decrement counter based on its + age. + + Action Group: Non-Disruptive + + Example: The following example will decrement the counter by 60 + every 300 seconds. + + SecAction deprecatevar:session.score=60/300 + + Note + + Counter values are always positive, meaning the value will never + go below zero. +
+ +
+ <literal>drop</literal> + + Description: Immediately initiate a + "connection close" action to tear down the TCP connection by sending a + FIN packet. + + Action Group: Disruptive + + Example: The following example initiates an IP collection for + tracking Basic Authentication attempts. If the client goes over the + threshold of more than 25 attempts in 2 minutes, it will DROP subsequent + connections. + + SecAction phase:1,initcol:ip=%{REMOTE_ADDR},nolog +SecRule ARGS:login "!^$" \ + nolog,phase:1,setvar:ip.auth_attempt=+1,deprecatevar:ip.auth_attempt=20/120 +SecRule IP:AUTH_ATTEMPT "@gt 25" \ + "log,drop,phase:1,msg:'Possible Brute Force Attack'" + + Note + + This action is currently not available on Windows based builds. + This action is extremely useful when responding to both Brute Force and + Denial of Service attacks in that, in both cases, you want to minimize + both the network bandwidth and the data returned to the client. This + action causes error message to appear in the log "(9)Bad file + descriptor: core_output_filter: writing data to the network" +
+ +
+ <literal>exec</literal> + + Description: Executes an external + script/binary supplied as parameter. As of v2.5.0, if the parameter + supplied to exec is a Lua script (detected by the + .lua extension) the script will be processed + internally. This means you will get direct access + to the internal request context from the script. Please read the + SecRuleScript documentation for more details on how + to write Lua scripts. + + Action Group: Non-disruptive + + Example: + + # The following is going to execute /usr/local/apache/bin/test.sh +# as a shell script on rule match. +SecRule REQUEST_URI "^/cgi-bin/script\.pl" \ + "phase:2,t:none,t:lowercase,t:normalisePath,log,exec:/usr/local/apache/bin/test.sh" + +# The following is going to process /usr/local/apache/conf/exec.lua +# internally as a Lua script on rule match. +SecRule ARGS:p attack log,exec:/usr/local/apache/conf/exec.lua + + + The exec action is executed independently from any disruptive + actions. External scripts will always be called with no parameters. + Some transaction information will be placed in environment variables. + All the usual CGI environment variables will be there. You should be + aware that forking a threaded process results in all threads being + replicated in the new process. Forking can therefore incur larger + overhead in multi-threaded operation. The script you execute must + write something (anything) to stdout. If it doesn't ModSecurity will + assume execution didn't work. + +
+ +
+ <literal>expirevar</literal> + + Description: Configures a collection variable + to expire after the given time in seconds. + + Action Group: Non-disruptive + + Example: + + SecRule REQUEST_COOKIES:JSESSIONID "!^$" nolog,phase:1,pass,chain +SecAction setsid:%{REQUEST_COOKIES:JSESSIONID} +SecRule REQUEST_URI "^/cgi-bin/script\.pl" \ + "phase:2,t:none,t:lowercase,t:normalisePath,log,allow,\ +setvar:session.suspicious=1,expirevar:session.suspicious=3600,phase:1" + + Note + + You should use expirevar actions at the same time that you use + setvar actions in order to keep the indented expiration time. If they + are used on their own (perhaps in a SecAction directive) the expire time + could get re-set. When variables are removed from collections, and there + are no other changes, collections are not written to disk at the end of + request. This is because the variables can always be expired again when + the collection is read again on a subsequent request. +
+ +
+ <literal>id</literal> + + Description: Assigns a unique ID to the rule + or chain. + + Action Group: Meta-data + + Example: + + SecRule &REQUEST_HEADERS:Host "@eq 0" \ + "log,id:60008,severity:2,msg:'Request Missing a Host Header'" + + Note + + These are the reserved ranges: + + + + 1-99,999; reserved for local (internal) use. Use as you see + fit but do not use this range for rules that are distributed to + others. + + + + 100,000-199,999; reserved for internal use of the engine, to + assign to rules that do not have explicit IDs. + + + + 200,000-299,999; reserved for rules published at + modsecurity.org. + + + + 300,000-399,999; reserved for rules published at + gotroot.com. + + + + 400,000-419,999; unused (available for reservation). + + + + 420,000-429,999; reserved for ScallyWhack. + + + + 430,000-899,999; unused (available for reservation). + + + + 900,000-999,999; reserved for the Core Rules + project. + + + + 1,000,000 and above; unused (available for + reservation). + + +
+ +
+ <literal>initcol</literal> + + Description: Initialises a named persistent + collection, either by loading data from storage or by creating a new + collection in memory. + + Action Group: Non-disruptive + + Example: The following example initiates IP address + tracking. + + SecAction phase:1,initcol:ip=%{REMOTE_ADDR},nolog + + Note + + Normally you will want to use phase:1 along + with initcol so that the collection is available in + all phases. + + Collections are loaded into memory when the initcol action is + encountered. The collection in storage will be persisted (and the + appropriate counters increased) only if it was + changed during transaction processing. + + See the "Persistant Storage" section for further details. +
+ +
+ <literal>log</literal> + + Description: Indicates that a successful + match of the rule needs to be logged. + + Action Group: Non-disruptive + + Example: + + SecAction phase:1,initcol:ip=%{REMOTE_ADDR},log + + Note + + This action will log matches to the Apache error log file and the + ModSecurity audit log. +
+ +
+ <literal>logdata</literal> + + Description: Allows a data fragment to be + logged as part of the alert message. + + Action Group: Non-disruptive + + Example: + + SecRule &ARGS:p "@eq 0" "log,logdata:'%{TX.0}'" + + Note + + The logdata information appears in the error and/or audit log + files and is not sent back to the client in response headers. Macro + expansion is preformed so you may use variable names such as %{TX.0}, + etc. The information is properly escaped for use with logging binary + data. +
+ +
+ <literal>msg</literal> + + Description: Assigns a custom message to the + rule or chain. + + Action Group: Meta-data + + Example: + + SecRule &REQUEST_HEADERS:Host "@eq 0" \ + "log,id:60008,severity:2,msg:'Request Missing a Host Header'" + + Note + + The msg information appears in the error and/or audit log files + and is not sent back to the client in response headers. +
+ +
+ <literal>multiMatch</literal> + + Description: If enabled ModSecurity will + perform multiple operator invocations for every target, before and after + every anti-evasion transformation is performed. + + Action Group: Non-disruptive + + Example: + + SecDefaultAction log,deny,phase:1,t:removeNulls,t:lowercase +SecRule ARGS "attack" multiMatch + + Note + + Normally, variables are evaluated once, only after all + transformation functions have completed. With multiMatch, variables are + checked against the operator before and after every transformation + function that changes the input. +
+ +
+ <literal>noauditlog</literal> + + Description: Indicates that a successful + match of the rule should not be used as criteria whether the transaction + should be logged to the audit log. + + Action Group: Non-disruptive + + Example: + + SecRule REQUEST_HEADERS:User-Agent "Test" allow,noauditlog + + Note + + If the SecAuditEngine is set to On, all of the transactions will + be logged. If it is set to RelevantOnly, then you can control it with + the noauditlog action. Even if the noauditlog action is applied to a + specific rule and a rule either before or after triggered an audit + event, then the transaction will be logged to the audit log. The correct + way to disable audit logging for the entire transaction is to use + "ctl:auditEngine=Off" +
+ +
+ <literal>nolog</literal> + + Description: Prevents rule matches from + appearing in both the error and audit logs. + + Action Group: Non-disruptive + + Example: + + SecRule REQUEST_HEADERS:User-Agent "Test" allow,nolog + + Note + + The nolog action also implies noauditlog. +
+ +
+ <literal>pass</literal> + + Description: Continues processing with the + next rule in spite of a successful match. + + Action Group: Disruptive + + Example1: + + SecRule REQUEST_HEADERS:User-Agent "Test" log,pass + + When using pass with SecRule with multiple + targets, all targets will be processed and + all non-disruptive actions will trigger for + every match found. In the second example the + TX:test target would be incremented by 1 for each matching + argument. + + Example2: + + SecRule ARGS "test" log,pass,setvar:TX.test=+1 + + Note + + The transaction will not be interrupted but a log will be + generated for each matching target (unless logging has been + suppressed). +
+ +
+ <literal>pause</literal> + + Description: Pauses transaction processing + for the specified number of milliseconds. + + Action Group: Non-disruptive + + Example: + + SecRule REQUEST_HEADERS:User-Agent "Test" log,deny,status:403,pause:5000 + + Note + + This feature can be of limited benefit for slowing down Brute + Force Scanners, however use with care. If you are under a Denial of + Service type of attack, the pause feature may make matters worse as this + feature will cause child processes to sit idle until the pause is + completed. +
+ +
+ <literal>phase</literal> + + Description: Places the rule (or the rule + chain) into one of five available processing phases. + + Action Group: Meta-data + + Example: + + SecDefaultAction log,deny,phase:1,t:removeNulls,t:lowercase +SecRule REQUEST_HEADERS:User-Agent "Test" log,deny,status:403 + + Note + + Keep in mind that is you specify the incorrect phase, the target + variable that you specify may be empty. This could lead to a false + negative situation where your variable and operator (RegEx) may be + correct, but it misses malicious data because you specified the wrong + phase. +
+ +
+ prepend + + Description: Prepends text given as parameter + to the response body. For this action to work content injection must be + enabled by setting SecContentInjection to + On. Also make sure you check the content type of the + response before you make changes to it (e.g. you don't want to inject + stuff into images). + + Action Group: Non-disruptive + + Processing Phases: 3 and 4. + + Example: + + SecRule RESPONSE_CONTENT_TYPE ^text/html "phase:3,nolog,pass,prepend:'Header<br>'" + + + While macro expansion is allowed in the additional content, you + are strongly cautioned against inserting user defined data + fields. + +
+ +
+ <literal>proxy</literal> + + Description: Intercepts transaction by + forwarding request to another web server using the proxy backend. + + Action Group: Disruptive + + Example: + + SecRule REQUEST_HEADERS:User-Agent "Test" log,proxy:http://www.honeypothost.com/ + + Note + + For this action to work, mod_proxy must also be installed. This + action is useful if you would like to proxy matching requests onto a + honeypot webserver. +
+ +
+ <literal>redirect</literal> + + Description: Intercepts transaction by + issuing a redirect to the given location. + + Action Group: Disruptive + + Example: + + SecRule REQUEST_HEADERS:User-Agent "Test" \ + log,redirect:http://www.hostname.com/failed.html + + Note + + If the status action is present + and its value is acceptable (301, 302, 303, or 307) it will be used for + the redirection. Otherwise status code 302 will be used. +
+ +
+ <literal>rev</literal> + + Description: Specifies rule revision. + + Action Group: Meta-data + + Example: + + SecRule REQUEST_METHOD "^PUT$" "id:340002,rev:1,severity:2,msg:'Restricted HTTP function'" + + Note + + This action is used in combination with the id action to allow the same rule ID to be used + after changes take place but to still provide some indication the rule + changed. +
+ +
+ <literal>sanitiseArg</literal> + + Description: Sanitises (replaces each byte + with an asterisk) a named request argument prior to audit + logging. + + Action Group: Non-disruptive + + Example: + + SecAction nolog,phase:2,sanitiseArg:password + + Note + + The sanitize actions do not sanitize any data within the actual + raw requests but only on the copy of data within memory that is set to + log to the audit log. It will not sanitize the data in the + modsec_debug.log file (if the log level is set high enough to capture + this data). +
+ +
+ <literal>sanitiseMatched</literal> + + Description: Sanitises the variable (request + argument, request header, or response header) that caused a rule + match. + + Action Group: Non-disruptive + + Example: This action can be used to sanitise arbitrary transaction + elements when they match a condition. For example, the example below + will sanitise any argument that contains the word + password in the name. + + SecRule ARGS_NAMES password nolog,pass,sanitiseMatched + + Note + + Same note as sanitiseArg. +
+ +
+ <literal>sanitiseRequestHeader</literal> + + Description: Sanitises a named request + header. + + Action Group: Non-disruptive + + Example: This will sanitise the data in the Authorization + header. + + SecAction log,phase:1,sanitiseRequestHeader:Authorization + + Note + + Same note as sanitiseArg. +
+ +
+ <literal>sanitiseResponseHeader</literal> + + Description: Sanitises a named response + header. + + Action Group: Non-disruptive + + Example: This will sanitise the Set-Cookie data sent to the + client. + + SecAction log,phase:3,sanitiseResponseHeader:Set-Cookie + + Note + + Same note as sanitiseArg. +
+ +
+ <literal>severity</literal> + + Description: Assigns severity to the rule it + is placed with. + + Action Group: Meta-data + + Example: + + SecRule REQUEST_METHOD "^PUT$" "id:340002,rev:1,severity:CRITICAL,msg:'Restricted HTTP function'" + + Note + + Severity values in ModSecurity follow those of syslog, as + below: + + + + 0 - EMERGENCY + + + + 1 - ALERT + + + + 2 - CRITICAL + + + + 3 - ERROR + + + + 4 - WARNING + + + + 5 - NOTICE + + + + 6 - INFO + + + + 7 - DEBUG + + + + It is possible to specify severity levels using either the + numerical values or the text values. You should always specify severity + levels using the text values. The use of the numerical values is + deprecated (as of v2.5.0) and may be removed in one of the susequent + major updates. +
+ +
+ <literal>setuid</literal> + + Description: Special-purpose action that + initialises the USER + collection. + + Action Group: Non-disruptive + + Example: + + SecAction setuid:%{REMOTE_USER},nolog + + Note + + After initialisation takes place the variable USERID will be available for use in the + subsequent rules. +
+ +
+ <literal>setsid</literal> + + Description: Special-purpose action that + initialises the SESSION + collection. + + Action Group: Non-disruptive + + Example: + + # Initialise session variables using the session cookie value +SecRule REQUEST_COOKIES:PHPSESSID !^$ chain,nolog,pass +SecAction setsid:%{REQUEST_COOKIES.PHPSESSID} + + Note + + On first invocation of this action the collection will be empty + (not taking the predefined variables into account - see initcol for more information). On subsequent + invocations the contents of the collection (session, in this case) will + be retrieved from storage. After initialisation takes place the + variable SESSIONID will be available + for use in the subsequent rules.This action understands each application + maintains its own set of sessions. It will utilise the current web + application ID to create a session namespace. +
+ +
+ <literal>setenv</literal> + + Description: Creates, removes, or updates an + environment variable. + + Action Group: Non-disruptive + + Examples: + + To create a new variable (if you omit the value 1 will be used): + + setenv:name=value + + To remove a variable: + + setenv:!name + + Note + + This action can be used to establish communication with other + Apache modules. +
+ +
+ <literal>setvar</literal> + + Description: Creates, removes, or updates a + variable in the specified collection. + + Action Group: Non-disruptive + + Examples: + + To create a new variable: + + setvar:tx.score=10 + + To remove a variable prefix the name with exclamation mark: + + setvar:!tx.score + + To increase or decrease variable value use + and - + characters in front of a numerical value: + + setvar:tx.score=+5 +
+ +
+ <literal>skip</literal> + + Description: Skips one or more rules (or + chains) on successful match. + + Action Group: Flow + + Example: + + SecRule REQUEST_URI "^/$" \ +"phase:2,chain,t:none,skip:2" +SecRule REMOTE_ADDR "^127\.0\.0\.1$" "chain" +SecRule REQUEST_HEADERS:User-Agent "^Apache \(internal dummy connection\)$" "t:none" +SecRule &REQUEST_HEADERS:Host "@eq 0" \ + "deny,log,status:400,id:960008,severity:4,msg:'Request Missing a Host Header'" +SecRule &REQUEST_HEADERS:Accept "@eq 0" \ + "log,deny,log,status:400,id:960015,msg:'Request Missing an Accept Header'" + + Note + + Skip only applies to the current processing phase and not + necessarily the order in which the rules appear in the configuration + file. If you group rules by processing phases, then skip should work as + expected. This action can not be used to skip rules within one chain. + Accepts a single parameter denoting the number of rules (or chains) to + skip. +
+ +
+ <literal>skipAfter</literal> + + Description: Skips rules (or chains) on + successful match resuming rule execution after the specified rule ID or + marker (see SecMarker) is found. + + Action Group: Flow + + Example: + + SecRule REQUEST_URI "^/$" "chain,t:none,skipAfter:960015" +SecRule REMOTE_ADDR "^127\.0\.0\.1$" "chain" +SecRule REQUEST_HEADERS:User-Agent "^Apache \(internal dummy connection\)$" "t:none" +SecRule &REQUEST_HEADERS:Host "@eq 0" \ + "deny,log,status:400,id:960008,severity:4,msg:'Request Missing a Host Header'" +SecRule &REQUEST_HEADERS:Accept "@eq 0" \ + "log,deny,log,status:400,id:960015,msg:'Request Missing an Accept Header'" + + Note + + SkipAfter only applies to the current + processing phase and not necessarily the order in which the rules appear + in the configuration file. If you group rules by processing phases, then + skip should work as expected. This action can not be used to skip rules + within one chain. Accepts a single parameter denoting the last rule ID + to skip. +
+ +
+ <literal>status</literal> + + Description: Specifies the response status + code to use with actions deny + and redirect. + + Action Group: Data + + Example: + + SecDefaultAction log,deny,status:403,phase:1 + + Note + + Status actions defined in Apache scope locations (such as + Directory, Location, etc...) may be superseded by phase:1 action + settings. The Apache ErrorDocument directive will be triggered if + present in the configuration. Therefore if you have previously defined a + custom error page for a given status then it will be executed and its + output presented to the user. +
+ +
+ <literal>t</literal> + + Description: This action can be used which + transformation function should be used against the specified variables + before they (or the results, rather) are run against the operator + specified in the rule. + + Action Group: Non-disruptive + + Example: + + SecDefaultAction log,deny,phase:1,t:removeNulls,t:lowercase +SecRule REQUEST_COOKIES:SESSIONID "47414e81cbbef3cf8366e84eeacba091" \ + log,deny,status:403,t:md5,t:hexEncode + + Note + + Any transformation functions that you specify in a SecRule will be + in addition to previous ones specified in SecDefaultAction. Use of + "t:none" will remove all transformation functions for the specified + rule. +
+ +
+ <literal>tag</literal> + + Description: Assigns custom text to a rule or + chain. + + Action Group: Meta-data + + Example: + + SecRule REQUEST_FILENAME "\b(?:n(?:map|et|c)|w(?:guest|sh)|cmd(?:32)?|telnet|rcmd|ftp)\.exe\b" \ + "t:none,t:lowercase,deny,msg:'System Command Access',id:'950002',\ +tag:'WEB_ATTACK/FILE_INJECTION',tag:'OWASP/A2',severity:'2'" + + Note + + The tag information appears in the error and/or audit log files. + Its intent is to be used to automate classification of rules and the + alerts generated by rules. Multiple tags can be used per + rule/chain. +
+ +
+ <literal>xmlns</literal> + + Description: This action should be used + together with an XPath expression to register a namespace. + + Action Group: Data + + Example: + + SecRule REQUEST_HEADERS:Content-Type "text/xml" \ + "phase:1,pass,ctl:requestBodyProcessor=XML,ctl:requestBodyAccess=On, \ + xmlns:xsd="http://www.w3.org/2001/XMLSchema" +SecRule XML:/soap:Envelope/soap:Body/q1:getInput/id() "123" phase:2,deny +
+
+ +
+ Operators + + A number of operators can be used in rules, as documented below. The + operator syntax uses the @ symbol followed by the + specific operator name. + +
+ <literal>beginsWith</literal> + + Description: This operator is a string + comparison and returns true if the parameter value is found at the + beginning of the input. Macro expansion is performed so you may use + variable names such as %{TX.1}, etc. + + Example: + + SecRule REQUEST_LINE "!@beginsWith GET" t:none,deny,status:403 +SecRule REQUEST_ADDR "^(.*)\.\d+$" deny,status:403,capture,chain +SecRule ARGS:gw "!@beginsWith %{TX.1}" +
+ +
+ <literal>contains</literal> + + Description: This operator is a string + comparison and returns true if the parameter value is found anywhere in + the input. Macro expansion is performed so you may use variable names + such as %{TX.1}, etc. + + Example: + + SecRule REQUEST_LINE "!@contains .php" t:none,deny,status:403 +SecRule REQUEST_ADDR "^(.*)$" deny,status:403,capture,chain +SecRule ARGS:ip "!@contains %{TX.1}" +
+ +
+ <literal>endsWith</literal> + + Description: This operator is a string + comparison and returns true if the parameter value is found at the end + of the input. Macro expansion is performed so you may use variable names + such as %{TX.1}, etc. + + Example: + + SecRule REQUEST_LINE "!@endsWith HTTP/1.1" t:none,deny,status:403 +SecRule ARGS:route "!@endsWith %{REQUEST_ADDR}" t:none,deny,status:403 +
+ +
+ <literal>eq</literal> + + Description: This operator is a numerical + comparison and stands for "equal to." + + Example: + + SecRule &REQUEST_HEADERS_NAMES "@eq 15" +
+ +
+ <literal>ge</literal> + + Description: This operator is a numerical + comparison and stands for "greater than or equal to." + + Example: + + SecRule &REQUEST_HEADERS_NAMES "@ge 15" +
+ +
+ <literal>geoLookup</literal> + + Description: This operator looks up various + data fields from an IP address or hostname in the target data. The + results will be captured in the GEO + collection. + + You must provide a database via SecGeoLookupDb before this operator can be + used. + + + This operator matches and the action is executed on a + successful lookup. For this reason, you probably want to + use the pass,nolog actions. This allows for + setvar and other non-disruptive + actions to be executed on a match. If you wish to block on a failed + lookup, then do something like this (look for an empty GEO + collection): + + SecGeoLookupDb /usr/local/geo/data/GeoLiteCity.dat +... +SecRule REMOTE_ADDR "@geoLookup" "pass,nolog" +SecRule &GEO "@eq 0" "deny,status:403,msg:'Failed to lookup IP'" + + + See the GEO variable for an + example and more information on various fields available. +
+ +
+ <literal>gt</literal> + + Description: This operator is a numerical + comparison and stands for "greater than." + + Example: + + SecRule &REQUEST_HEADERS_NAMES "@gt 15" +
+ +
+ <literal>inspectFile</literal> + + Description: Executes the external + script/binary given as parameter to the operator against every file + extracted from the request. As of v2.5.0, if the supplied filename is + not absolute it is treated as relative to the directory in which the + configuration file resides. Also as of v2.5.0, if the filename is + determined to be a Lua script (based on its extension) the script will + be processed by the internal engine. As such it will have full access to + the ModSecurity context. + + Example of using an external binary/script: + + # Execute external script to validate uploaded files. +SecRule FILES_TMPNAMES "@inspectFile /opt/apache/bin/inspect_script.pl" + + Example of using Lua script: + + SecRule FILES_TMPNANMES "@inspectFile inspect.lua" + + Script inspect.lua: + + function main(filename) + -- Do something to the file to verify it. In this example, we + -- read up to 10 characters from the beginning of the file. + local f = io.open(filename, "rb"); + local d = f:read(10); + f:close(); + + -- Return null if there is no reason to believe there is ansything + -- wrong with the file (no match). Returning any text will be taken + -- to mean a match should be trigerred. + return null; +end +
+ +
+ <literal>le</literal> + + Description: This operator is a numerical + comparison and stands for "less than or equal to." + + Example: + + SecRule &REQUEST_HEADERS_NAMES "@le 15" +
+ +
+ <literal>lt</literal> + + Description: This operator is a numerical + comparison and stands for "less than." + + Example: + + SecRule &REQUEST_HEADERS_NAMES "@lt 15" +
+ +
+ <literal>pm</literal> + + Description: Phrase Match operator. This + operator uses a set based matching engine (Aho-Corasick) for faster + matches of keyword lists. It will match any one of its arguments + anywhere in the target value. The match is case insensitive. + + Example: + + SecRule REQUEST_HEADERS:User-Agent "@pm WebZIP WebCopier Webster WebStripper SiteSnagger ProWebWalker CheeseBot" "deny,status:403 + + The above would deny access with 403 if any of the words matched + within the User-Agent HTTP header value. +
+ +
+ <literal>pmFromFile</literal> + + Description: Phrase Match operator. This + operator uses a set based matching engine (Aho-Corasick) for faster + matches of keyword lists. This operator is the same as + @pm except that it takes a list of files as + arguments. It will match any one of the phrases listed in the file(s) + anywhere in the target value. + + Notes: + + + + The contents of the files should be one phrase per line. End + of line markers will be stripped from the phrases, however, + whitespace will not be trimmed from phrases in the file. Empty lines + and comment lines (beginning with a '#') are ignored. + + + + To allow easier inclusion of phrase files with rulesets, + relative paths may be used to the phrase files. In this case, the + path of the file containing the rule is prepended to the phrase file + path. + + + + Example: + + SecRule REQUEST_HEADERS:User-Agent "@pm /path/to/blacklist1 blacklist2" "deny,status:403 + + The above would deny access with 403 if any of the patterns in the + two files matched within the User-Agent HTTP header value. The + blacklist2 file would need to be placed in the same + path as the file containing the rule. +
+ +
+ <literal>rbl</literal> + + Description: Look up the parameter in the RBL + given as parameter. Parameter can be an IPv4 address, or a + hostname. + + Example: + + SecRule REMOTE_ADDR "@rbl sc.surbl.org" +
+ +
+ <literal>rx</literal> + + Description: Regular expression operator. + This is the default operator, so if the "@" operator is not defined, it + is assumed to be rx. + + Example: + + SecRule REQUEST_HEADERS:User-Agent "@rx nikto" + + Note + + Regular expressions are handled by the PCRE library (http://www.pcre.org). ModSecurity + compiles its regular expressions with the following settings: + + + + The entire input is treated as a single line, even when there + are newline characters present. + + + + All matches are case-sensitive. If you do not care about case + sensitivity you either need to implement the lowercase transformation function, or use + the per-pattern(?i)modifier, as + allowed by PCRE. + + + + The PCRE_DOTALL and + PCRE_DOLLAR_ENDONLY flags are set + during compilation, meaning a single dot will match any character, + including the newlines and a $ + end anchor will not match a trailing newline character. + + +
+ +
+ <literal>streq</literal> + + Description: This operator is a string + comparison and returns true if the parameter value matches the input + exactly. Macro expansion is performed so you may use variable names such + as %{TX.1}, etc. + + Example: + + SecRule ARGS:foo "!@streq bar" t:none,deny,status:403 +SecRule REQUEST_ADDR "^(.*)$" deny,status:403,capture,chain +SecRule REQUEST_HEADERS:Ip-Address "!@streq %{TX.1}" +
+ +
+ <literal>validateByteRange</literal> + + Description: Validates the byte range used in + the variable falls into the specified range. + + Example: + + SecRule ARGS:text "@validateByteRange 10, 13, 32-126" + + Note + + You can force requests to consist only of bytes from a certain + byte range. This can be useful to avoid stack overflow attacks (since + they usually contain "random" binary content). Default range values are + 0 and 255, i.e. all byte values are allowed. This directive does not + check byte range in a POST payload when + multipart/form-data encoding (file upload) is used. + Doing so would prevent binary files from being uploaded. However, after + the parameters are extracted from such request they are checked for a + valid range. + + validateByteRange is similar to the ModSecurity 1.X + SecFilterForceByteRange Directive however since it works in a rule + context, it has the following differences: + + + + You can specify a different range for different + variables. + + + + It has an "event" context (id, msg....) + + + + It is executed in the flow of rules rather than being a built + in pre-check. + + +
+ +
+ <literal>validateDTD</literal> + + Description: Validates the DOM tree generated + by the XML request body processor against the supplied DTD. + + Example: + + SecDefaultAction log,deny,status:403,phase:2 +SecRule REQUEST_HEADERS:Content-Type ^text/xml$ \ + phase:1,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML +SecRule REQBODY_PROCESSOR "!^XML$" nolog,pass,skipAfter:12345 +SecRule XML "@validateDTD /path/to/apache2/conf/xml.dtd" "deny,id:12345" + + + This operator requires request body to be processed as + XML. + +
+ +
+ <literal>validateSchema</literal> + + Description: Validates the DOM tree generated + by the XML request body processor against the supplied XML + Schema. + + Example: + + SecDefaultAction log,deny,status:403,phase:2 +SecRule REQUEST_HEADERS:Content-Type ^text/xml$ \ + phase:1,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML +SecRule REQBODY_PROCESSOR "!^XML$" nolog,pass,skipAfter:12345 +SecRule XML "@validateSchema /path/to/apache2/conf/xml.xsd" "deny,id:12345" + + + This operator requires request body to be processed as + XML. + +
+ +
+ <literal>validateUrlEncoding</literal> + + Description: Verifies the encodings used in + the variable (if any) are valid. + + Example: + + SecRule ARGS "@validateUrlEncoding" + + Note + + URL encoding is an HTTP standard for encoding byte values within a + URL. The byte is escaped with a % followed by two hexadecimal values + (0-F). This directive does not check encoding in a POST payload when the + multipart/form-data encoding (file upload) is used. + It is not necessary to do so because URL encoding is not used for this + encoding. +
+ +
+ <literal>validateUtf8Encoding</literal> + + Description: Verifies the variable is a valid + UTF-8 encoded string. + + Example: + + SecRule ARGS "@validateUtf8Encoding" + + Note + + UTF-8 encoding is valid on most web servers. Integer values + between 0-65535 are encoded in a UTF-8 byte sequence that is escaped by + percents. The short form is two bytes in length. + + check for three types of errors: + + + + Not enough bytes. UTF-8 supports two, three, four, five, and + six byte encodings. ModSecurity will locate cases when a byte or + more is missing. + + + + Invalid encoding. The two most significant bits in most + characters are supposed to be fixed to 0x80. Attackers can use this + to subvert Unicode decoders. + + + + Overlong characters. ASCII characters are mapped directly into + the Unicode space and are thus represented with a single byte. + However, most ASCII characters can also be encoded with two, three, + four, five, and six characters thus tricking the decoder into + thinking that the character is something else (and, presumably, + avoiding the security check). + + +
+ +
+ <literal>verifyCC</literal> + + Description: This operator verifies a given + regular expression as a potential credit card number. It first matches + with a single generic regular expression then runs the resulting match + through a Luhn checksum algorithm to further verify it as a potential + credit card number. + + Example: + + SecRule ARGS "@verifyCC \d{13,16}" \ + "phase:2,sanitiseMatched,log,auditlog,pass,msg:'Potential credit card number'" +
+ +
+ <literal>within</literal> + + Description: This operator is a string + comparison and returns true if the input value is found anywhere within + the parameter value. Note that this is similar to + @contains, except that the target and match values + are reversed. Macro expansion is performed so you may use variable names + such as %{TX.1}, etc. + + Example: + + SecRule REQUEST_METHOD "!@within get,post,head" t:lowercase,deny,status:403 + +SecAction "pass,setvar:'tx.allowed_methods=get,post,head'" +SecRule REQUEST_METHOD "!@within %{tx.allowed_methods}" t:lowercase,deny,status:403 +
+
+ +
+ Macro Expansion + + Macros allow for using place holders in rules that will be expanded + out to their values at runtime. Currently only variable expansion is + supported, however more options may be added in future versions of + ModSecurity. + + Format: + + %{VARIABLE} +%{COLLECTION.VARIABLE} + + Macro expansion can be used in actions such as initcol, setsid, + setuid, setvar, setenv, logdata. Operators that are evaluated at runtime + support expansion and are noted above. Such operators include @beginsWith, + @endsWith, @contains, @within and @streq. You cannot use macro expansion + for operators that are "compiled" such as @pm, @rx, etc. as these + operators have their values fixed at configure time for efficiency. + + Some values you may want to expand include: TX, REMOTE_ADDR, USERID, + HIGHEST_SEVERITY, MATCHED_VAR, MATCHED_VAR_NAME, MULTIPART_STRICT_ERROR, + RULE, SESSION, USERID, among others. +
+ +
+ Persistant Storage + + At this time it is only possible to have three collections in which + data is stored persistantly (i.e. data available to multiple requests). + These are: IP, SESSION and USER. + + Every collection contains several built-in variables that are + available and are read-only unless otherwise specified: + + + + CREATE_TIME - date/time of + the creation of the collection. + + + + IS_NEW - set to 1 if the + collection is new (not yet persisted) otherwise set to 0. + + + + KEY - the value of the + initcol variable (the client's IP address in the example). + + + + LAST_UPDATE_TIME - date/time + of the last update to the collection. + + + + TIMEOUT - date/time in + seconds when the collection will be updated on disk from memory (if no + other updates occur). This variable may be set if you wish to specifiy + an explicit expiration time (default is 3600 seconds). + + + + UPDATE_COUNTER - how many + times the collection has been updated since creation. + + + + UPDATE_RATE - is the average + rate updates per minute since creation. + + + + To create a collection to hold session variables (SESSION) use action setsid. To create a collection to hold user + variables (USER) use action setuid. To create a collection to hold client + address variables (IP) use action + initcol. + + + ModSecurity implements atomic updates of persistent variables only + for integer variables (counters) at this time. Variables are read from + storage whenever initcol is encountered in the rules + and persisted at the end of request processing. Counters are adjusted by + applying a delta generated by re-reading the persisted data just before + being persisted. This keeps counter data consistent even if the counter + was modified and persisted by another thread/process during the + transaction. + + + + ModSecurity uses a Berkley Database (SDBM) for persistant storage. + This type of database is generally limited to storing a maximum of 1008 + bytes per key. This may be a limitation if you are attempting to store a + considerable amount of data in variables for a single key. Some of this + limitation is planned to be reduced in a future version of + ModSecurity. + +
+ +
+ Miscellaneous Topics + + + +
+ Impedance Mismatch + + Web application firewalls have a difficult job trying to make + sense of data that passes by, without any knowledge of the application + and its business logic. The protection they provide comes from having an + independent layer of security on the outside. Because data validation is + done twice, security can be increased without having to touch the + application. In some cases, however, the fact that everything is done + twice brings problems. Problems can arise in the areas where the + communication protocols are not well specified, or where either the + device or the application do things that are not in the specification. + In such cases it may be possible to design payload that will be + interpreted in one way by one device and in another by the other device. + This problem is better known as Impedance Mismatch. It can be exploited + to evade the security devices. + + While we will continue to enhance ModSecurity to deal with various + evasion techniques the problem can only be minimized, but never solved. + With so many different application backend chances are some will always + do something completely unexpected. The only solution is to be aware of + the technologies in the backend when writing rules, adapting the rules + to remove the mismatch. See the next section for some examples. + +
+ PHP Peculiarities for ModSecurity Users + + When writing rules to protect PHP applications you need to pay + attention to the following facts: + + + + When "register_globals" is set to "On" request parameters + are automatically converted to script variables. In some PHP + versions it is even possible to override the $GLOBALS + array. + + + + Whitespace at the beginning of parameter names is ignored. + (This is very dangerous if you are writing rules to target + specific named variables.) + + + + The remaining whitespace (in parameter names) is converted + to underscores. The same applies to dots and to a "[" if the + variable name does not contain a matching closing bracket. + (Meaning that if you want to exploit a script through a variable + that contains an underscore in the name you can send a parameter + with a whitespace or a dot instead.) + + + + Cookies can be treated as request parameters. + + + + The discussion about variable names applies equally to the + cookie names. + + + + The order in which parameters are taken from the request and + the environment is EGPCS (environment, GET, POST, Cookies, + built-in variables). This means that a POST parameter will + overwrite the parameters transported on the request line (in + QUERY_STRING). + + + + When "magic_quotes_gpc" is set to "On" PHP will use + backslash to escape the following characters: single quote, double + quote, backslash, and the nul byte. + + + + If "magic_quotes_sybase" is set to "On" only the single + quote will be escaped using another single quote. In this case the + "magic_quotes_gpc" setting becomes irrelevant. The + "magic_quotes_sybase" setting completely overrides the + "magic_quotes_gpc" behaviour but "magic_quotes_gpc" still must be + set to "On" for the Sybase-specific quoting to be work. + + + + PHP will also automatically create nested arrays for you. + For example "p[x][y]=1" results in a total of three + variables. + + +
+
+
+
diff --git a/doc/modsecurity2-data-formats.html b/doc/modsecurity2-data-formats.html new file mode 100644 index 0000000..2af899b --- /dev/null +++ b/doc/modsecurity2-data-formats.html @@ -0,0 +1,315 @@ +ModSecurity 2 Data Formats
ModSecurity

ModSecurity 2 Data Formats

Version 2.5.10-dev1 (March 24, 2009)


The purpose of this document is to describe the formats of the ModSecurity alert messages, + transaction logs and communication protocols, which would not only allow for a better + understanding what ModSecurity does but also for an easy integration with third-party tools + and products.

Alerts

As part of its operations ModSecurity will emit alerts, which are either + warnings (non-fatal) or errors (fatal, + usually leading to the interception of the transaction in question). Below is an example + of a ModSecurity alert entry:

Access denied with code 505 (phase 1). Match of "rx
+  ^HTTP/(0\\\\.9|1\\\\.[01])$" against "REQUEST_PROTOCOL" required.
+  [id "960034"] [msg "HTTP protocol version is not allowed by policy"]
+  [severity "CRITICAL"] [uri "/"] [unique_id "PQaTTVBEUOkAAFwKXrYAAAAM"]

Note

Alerts will only ever contain one line of text but we've broken the above example + into multiple lines to make it fit into the page.

Each alert entry begins with the engine message, which describes what ModSecurity did + and why. For + example:

Access denied with code 505 (phase 1). Match of "rx
+  ^HTTP/(0\\\\.9|1\\\\.[01])$" against "REQUEST_PROTOCOL" required.

Alert Action Description

The first part of the engine message tells you whether ModSecurity acted to + interrupt transaction or rule processing:

  1. If the alert is only a warning, the first sentence will simply say + Warning.

  2. If the transaction was intercepted, the first sentence will begin with + Access denied. What follows is the list of possible + messages related to transaction interception:

    • Access denied with code %0 - a response with + status code %0 was sent.

    • Access denied with connection close - + connection was abruptly closed.

    • Access denied with redirection to %0 using status + %1 - a redirection to URI %0 was + issued using status %1.

  3. There is also a special message that ModSecurity emits where an allow action is executed. There are three variations of this + type of message:

    • Access allowed - rule engine stopped + processing rules (transaction was unaffected).

    • Access to phase allowed - rule engine stopped + processing rules in the current phase only. Subsequent phases will + be processed normally. Transaction was not affected by this rule but + it may be affected by any of the rules in the subsequent + phase.

    • Access to request allowed - rule engine + stopped processing rules in the current phase. Phases prior to + request execution in the backend (currently phases 1 and 2) will not + be processed. The response phases (currently phases 3 and 4) and + others (currently phase 5) will be processed as normal. Transaction + was not affected by this rule but it may be affected by any of the + rules in the subsequent phase.

Alert Justification Description

The second part of the engine message explains why the alert + was generated. Since it is automatically generated from the rules it will be very + technical in nature, talking about operators and their parameters and give you + insight into what the rule looked like. But this message cannot give you insight + into the reasoning behind the rule. A well-written rule will always specify a + human-readable message (using the msg action) to provide further + information.

The format of the second part of the engine message depends on whether it was + generated by the operator (which happens on a match) or by the rule processor (which + happens where there is not a match, but the negation was used):

  • @beginsWith - String match %0 at + %1.

  • @contains - String match %0 at + %1.

  • @containsWord - String match %0 at + %1.

  • @endsWith - String match %0 at + %1.

  • @eq - Operator EQ matched %0 at + %1.

  • @ge - Operator GE matched %0 at + %1.

  • @geoLookup - Geo lookup for %0 succeeded at + %1.

  • @inspectFile - File %0 rejected by the + approver script %1: %2

  • @le - Operator LE matched %0 at + %1.

  • @lt - Operator LT matched %0 at + %1.

  • @rbl - RBL lookup of %0 succeeded at + %1.

  • @rx - Pattern match %0 at + %1.

  • @streq - String match %0 at + %1.

  • @validateByteRange - Found %0 byte(s) in %1 + outside range: %2.

  • @validateDTD - XML: DTD validation + failed.

  • @validateSchema - XML: Schema validation + failed.

  • @validateUrlEncoding

    • Invalid URL Encoding: Non-hexadecimal digits used at + %0.

    • Invalid URL Encoding: Not enough characters at the end + of input at %0.

  • @validateUtf8Encoding

    • Invalid UTF-8 encoding: not enough bytes in character at + %0.

    • Invalid UTF-8 encoding: invalid byte value in character + at %0.

    • Invalid UTF-8 encoding: overlong character detected at + %0.

    • Invalid UTF-8 encoding: use of restricted character at + %0.

    • Invalid UTF-8 encoding: decoding error at + %0.

  • @verifyCC - CC# match %0 at + %1.

Messages not related to operators:

  • When SecAction directive is processed - + Unconditional match in SecAction.

  • When SecRule does not match but negation is used - + Match of %0 against %1 required.

Note

The parameters to the operators @rx and @pm (regular expression and text pattern, respectively) will be + truncated to 252 bytes if they are longer than this limit. In this case the + parameter in the alert message will be terminated with three dots.

Meta-data

The metadata fields are always placed at the end of the alert entry. Each metadata + field is a text fragment that consists of an open bracket followed by the metadata + field name, followed by the value and the closing bracket. What follows is the text + fragment that makes up the id metadata field.

[id "960034"]

The following metadata fields are currently used:

  1. offset - The byte offset where a match occured within + the target data. This is not always available.

  2. id - Unique rule ID, as specified by the id action.

  3. rev - Rule revision, as specified by the rev action.

  4. msg - Human-readable message, as specified by the + msg action.

  5. severity - Event severity as text, as specified by the + severity action. The possible values (with their + corresponding numberical values in brackets) are EMERGENCY (0), ALERT (1), CRITICAL (2), ERROR (3), WARNING (4), NOTICE (5), INFO (6) and DEBUG (7).

  6. unique_id - Unique event ID, generated + automatically.

  7. uri - Request URI.

  8. logdata - contains transaction data fragment, as + specified by the logdata action.

Escaping

ModSecurity alerts will always contain text fragments that were taken from + configuration or the transaction. Such text fragments escaped before they are user + in messages, in order to sanitise the potentially dangerous characters. They are + also sometimes surrounded using double quotes. The escaping algorithm is as + follows:

  1. Characters 0x08 (BACKSPACE), + 0x0a (NEWLINE), 0x10 (CARRIAGE RETURN), 0x09 (HORIZONTAL TAB) and 0x0b (VERTICAL TAB) will be + represented as \b, \n, \r, \t and \v, + respectively.

  2. Bytes from the ranges 0-0x1f and 0x7f-0xff (inclusive) will be represented as \xHH, where HH is the hexadecimal + value of the byte.

  3. Backslash characters (\) will be represented as + \\.

  4. Each double quote character will be represented as \", but only if the entire fragment is surrounded with + double quotes.

Alerts in the Apache Error Log

Every ModSecurity alert conforms to the following format when it appears in the + Apache error log:

[Sun Jun 24 10:19:58 2007] [error] [client 192.168.0.1]
+            ModSecurity: ALERT_MESSAGE

The above is a standard Apache error log format. The ModSecurity: + prefix is specific to ModSecurity. It is used to allow quick + identification of ModSecurity alert messages when they appear in the same file next + to other Apache messages.

The actual message (ALERT_MESSAGE in the example above) is in + the same format as described in the Alerts section.

Note

Apache further escapes ModSecurity alert messages before writing them to the + error log. This means that all backslash characters will be doubled in the error + log. In practice, since ModSecurity will already represent a single backslash + within an untrusted text fragment as two backslashes, the end result in the + Apache error log will be four backslashes. Thus, if you + need to interpret a ModSecurity message from the error log, you should decode + the message part after the ModSecurity: prefix first. This + step will peel the first encoding layer.

Alerts in Audit Logs

Alerts are transported in the H section of the ModSecurity + Audit Log. Alerts will appear each on a separate line and in the order they were + generated by ModSecurity. Each line will be in the following format:

Message: ALERT_MESSAGE

Below is an example of an H section that contains two alert + messages:

--c7036611-H--
+Message: Warning. Match of "rx ^apache.*perl" against
+  "REQUEST_HEADERS:User-Agent" required. [id "990011"] [msg "Request
+  Indicates an automated program explored the site"] [severity "NOTICE"]
+Message: Warning. Pattern match "(?:\\b(?:(?:s(?:elect\\b(?:.{1,100}?\\b
+  (?:(?:length|count|top)\\b.{1,100}?\\bfrom|from\\b.{1,100}?\\bwhere)
+  |.*?\\b(?:d(?:ump\\b.*\\bfrom|ata_type)|(?:to_(?:numbe|cha)|inst)r))|p_
+  (?:(?:addextendedpro|sqlexe)c|(?:oacreat|prepar)e|execute(?:sql)?|
+  makewebt ..." at ARGS:c. [id "950001"] [msg "SQL Injection Attack.
+  Matched signature: union select"] [severity "CRITICAL"]
+Stopwatch: 1199881676978327 2514 (396 2224 -)
+Producer: ModSecurity v2.x.x (Apache 2.x)
+Server: Apache/2.x.x
+
+--c7036611-Z--

Audit Log

ModSecurity records one transaction in a single audit log file. Below is an + example:

--c7036611-A--
+[09/Jan/2008:12:27:56 +0000] OSD4l1BEUOkAAHZ8Y3QAAAAH 209.90.77.54 64995
+  80.68.80.233 80
+--c7036611-B--
+GET //EvilBoard_0.1a/index.php?c='/**/union/**/select/**/1,concat(username,
+  char(77),password,char(77),email_address,char(77),info,char(77),user_level,
+  char(77))/**/from/**/eb_members/**/where/**/userid=1/*http://kamloopstutor.
+  com/images/banners/on.txt? HTTP/1.1
+TE: deflate,gzip;q=0.3
+Connection: TE, cslose
+Host: www.example.com
+User-Agent: libwww-perl/5.808
+
+--c7036611-F--
+HTTP/1.1 404 Not Found
+Content-Length: 223
+Connection: close
+Content-Type: text/html; charset=iso-8859-1
+
+--c7036611-H--
+Message: Warning. Match of "rx ^apache.*perl" against
+  "REQUEST_HEADERS:User-Agent" required. [id "990011"] [msg "Request
+  Indicates an automated program explored the site"] [severity "NOTICE"]
+Message: Warning. Pattern match "(?:\\b(?:(?:s(?:elect\\b(?:.{1,100}?\\b
+  (?:(?:length|count|top)\\b.{1,100}?\\bfrom|from\\b.{1,100}?\\bwhere)
+  |.*?\\b(?:d(?:ump\\b.*\\bfrom|ata_type)|(?:to_(?:numbe|cha)|inst)r))|p_
+  (?:(?:addextendedpro|sqlexe)c|(?:oacreat|prepar)e|execute(?:sql)?|
+  makewebt ..." at ARGS:c. [id "950001"] [msg "SQL Injection Attack.
+  Matched signature: union select"] [severity "CRITICAL"]
+Stopwatch: 1199881676978327 2514 (396 2224 -)
+Producer: ModSecurity v2.x.x (Apache 2.x)
+Server: Apache/2.x.x
+
+--c7036611-Z--
+

The file consist of multiple sections, each in different format. Separators are used + to define sections:

--c7036611-A--

A separator always begins on a new line and conforms to the following format:

  1. Two dashes

  2. Unique boundary, which consists from several hexadecimal characters.

  3. One dash character.

  4. Section identifier, currently a single uppercase letter.

  5. Two trailing dashes.

Refer to the documentation for SecAuditLogParts for the explanation + of each part.

Parts

This section documents the audit log parts available in ModSecurity 2.x. They are:

  • A - audit log header

  • B - request headers

  • C - request body

  • D - intended response headers (NOT + IMPLEMENTED)

  • E - intended response body

  • F - response headers

  • G - response body (NOT + IMPLEMENTED)

  • H - audit log trailer

  • I - reduced multipart request + body

  • J - multipart files information + (NOT IMPLEMENTED)

  • K - matched rules + information

  • Z - audit log footer

Audit Log Header (A)

ModSecurity 2.x audit log entries always begin with the header part. For + example:

--c7036611-A--
+[09/Jan/2008:12:27:56 +0000] OSD4l1BEUOkAAHZ8Y3QAAAAH 209.90.77.54 64995
+  80.68.80.233 80

The header contains only one line, with the following information on + it:

  1. Timestamp

  2. Unique transaction ID

  3. Source IP address (IPv4 or IPv6)

  4. Source port

  5. Destination IP address (IPv4 or IPv6)

  6. Destination port

Request Headers (B)

The request headers part contains the request line and the request headers. + The information present in this part will not be identical to that sent by the + client responsible for the transaction. ModSecurity 2.x for Apache does not have + access to the raw data; it sees what Apache itself sees. While the end result + may be identical to the raw request, differences are possible in some + areas:

  1. If any of the fields are NUL-terminated, Apache + will only see the content prior to the NUL.

  2. Headers that span multiple lines (feature known as header folding) + will be collapsed into a single line.

  3. Multiple headers with the same name will be combined into a single + header (as allowed by the HTTP RFC).

Request Body (C)

This part contains the request body of the transaction, after dechunking and + decompression (if applicable).

Intended Response Headers (D)

This part contains the status line and the request headers that would have + been delivered to the client had ModSecurity not intervened. Thus this part + makes sense only for transactions where ModSecurity altered the data flow. By + differentiating before the intended and the final response headers, we are able + to record what was internally ready for sending, but also what was actually + sent.

Note

This part is reserved for future use. It is not implemented in ModSecurity + 2.x.

Intended Response Body (E)

This part contains the transaction response body (before compression and + chunking, where used) that was either sent or would have been sent had + ModSecurity not intervened. You can find whether interception took place by + looking at the Action header of the part H. If that header is present, and the interception took place in + phase 3 or 4 then the E part contains the intended response + body. Otherwise, it contains the actual response body.

Note

Once the G (actual response body) part is implemented, + part E will be present only in audit logs that contain a + transaction that was intercepted, and there will be no need for further + analsys.

Response Headers (F)

This part contains the actual response headers sent to the client. Since + ModSecurity 2.x for Apache does not access the raw connection data, it + constructs part F out of the internal Apache data structures + that hold the response headers.

Some headers (the Date and Server + response headers) are generated just before they are sent and ModSecurity is not + able to record those. You should note than ModSecurity is working as part of a + reverse proxy, the backend web server will have generated these two servers, and + in that case they will be recorded.

Response Body (G)

When implemented, this part will contain the actual response body before + compression and chunking.

Note

This part is reserved for future use. It is not implemented in ModSecurity + 2.x.

Audit Log Trailer (H)

Part H contains additional transaction meta-data that was + obtained from the web server or from ModSecurity itself. The part contains a + number of trailer headers, which are similar to HTTP headers (without support + for header folding):

  1. Action

  2. Apache-Error

  3. Message

  4. Producer

  5. Response-Body-Transformed

  6. Sanitised-Args

  7. Sanitised-Request-Headers

  8. Sanitised-Response-Headers

  9. Server

  10. Stopwatch

  11. WebApp-Info

Action

The Action header is present only for the transactions + that were intercepted:

Action: Intercepted (phase 2)

The phase information documents the phase in which the decision to + intercept took place.

Apache-Error

The Apache-Error header contains Apache error log messages observed by + ModSecurity, excluding those sent by ModSecurity itself. For example:

Apache-Error: [file "/tmp/buildd/apache2-2.0.54/build-tree/apache2/server/
+  core.c"] [line 3505] [level 3] File does not exist: /var/www/www.
+  modsecurity.org/fst/documentation/modsecurity-apache/2.5.0-dev2
Message

Zero or more Message headers can be present in any + trailer, and each such header will represent a single ModSecurity warning or + error, displayed in the order they were raised.

The example below was broken into multiple lines to make it fit this + page:

Message: Access denied with code 400 (phase 2). Pattern match "^\w+:/" at
+  REQUEST_URI_RAW. [file "/etc/apache2/rules-1.6.1/modsecurity_crs_20_
+  protocol_violations.conf"] [line "74"] [id "960014"] [msg "Proxy access
+  attempt"] [severity "CRITICAL"] [tag "PROTOCOL_VIOLATION/PROXY_ACCESS"]
Producer

The Producer header identifies the product that + generated the audit log. For example:

Producer: ModSecurity for Apache/2.5.5 (http://www.modsecurity.org/).

ModSecurity allows rule sets to add their own signatures to the Producer information (this is done using the SecComponentSignature directive). Below is an example of the + Producer header with the signature of one component + (all one line):

Producer: ModSecurity for Apache/2.5.5 (http://www.modsecurity.org/);
+    MyComponent/1.0.0 (Beta).
Response-Body-Transformed

This header will appear in every audit log that contains a response + body:

Response-Body-Transformed: Dechunked

The contents of the header is constant at present, so the header is only + useful as a reminder that the recorded response body is not identical to the + one sent to the client. The actual content is the same, except that Apache + may further compress the body and deliver it in chunks.

Sanitised-Args

The Sanitised-Args header contains a list of arguments + that were sanitised (each byte of their content replaced with an asterisk) + before logging. For example:

Sanitised-Args: "old_password", "new_password", "new_password_repeat".
Sanitised-Request-Headers

The Sanitised-Request-Headers header contains a list of + request headers that were sanitised before logging. For example:

Sanitised-Request-Headers: "Authentication".
Sanitised-Response-Headers

The Sanitised-Response-Headers header contains a list + of response headers that were sanitised before logging. For example:

Sanitised-Response-Headers: "My-Custom-Header".
Server

The Server header identifies the web server. For + example:

Server: Apache/2.0.54 (Debian GNU/Linux) mod_ssl/2.0.54 OpenSSL/0.9.7e

This information may sometimes be present in any of the parts that contain + response headers, but there are a few cases when it isn't:

  1. None of the response headers were recoreded.

  2. The information in the response headers is not accurate + because server signature masking was used.

Stopwatch

The Stopwatch header provides certain diagnostic + information that allows you to determine the performance of the web server + and of ModSecurity itself. It will typically look like this:

Stopwatch: 1222945098201902 2118976 (770* 4400 -)

Each line can contain up to 5 different values. Some values can be absent; + each absent value will be replaced with a dash.

The meanings of the values are as follows (all values are in + microseconds):

  1. Transaction timestamp in microseconds since January 1st, + 1970.

  2. Transaction duration.

  3. The time between the moment Apache started processing the + request and until phase 2 of ModSecurity began. If an asterisk + is present that means the time includes the time it took + ModSecurity to read the request body from the client (typically + slow). This value can be used to provide a rough estimate of the + client speed, but only with larger request bodies (the smaller + request bodies may arrive in a single TCP/IP packet).

  4. The time between the start of processing and until phase 2 was + completed. If you substract the previous value from this value + you will get the exact duration of phase 2 (which is the main + rule processing phase).

  5. The time between the start of request processing and util we + began sending a fully-buffered response body to the client. If + you substract this value from the total transaction duration and + divide with the response body size you may get a rough estimate + of the client speed, but only for larger response bodies.

WebApp-Info

The WebApp-Info header contains information on the + application to which the recorded transaction belongs. This information will + appear only if it is known, which will happen if SecWebAppId was set, or setsid or setuid executed in the transaction.

The header uses the following format:

WebApp-Info: "WEBAPPID" "SESSIONID" "USERID"

Each unknown value is replaced with a dash.

Reduced Multipart Request Body (I)

Transactions that deal with file uploads tend to be large, yet the file + contents is not always relevant from the security point of view. The I part was designed to avoid recording raw multipart/form-data request bodies, replacing them with a + simulated application/x-www-form-urlencoded body that + contains the same key-value parameters.

The reduced multipart request body will not contain any file information. The + J part (currently not implemented) is intended to carry + the file metadata.

Multipart Files Information (J)

The purpose of part J is to record the information on the + files contained in a multipart/form-data request body. This + is handy in the cases when the original request body was not recorded, or when + only a reduced version was recorded (e.g. when part I was + used instead of part C).

Note

This part is reserved for future use. It is not implemented in ModSecurity + 2.x.

Matched Rules (K)

The matched rules part contains a record of all ModSecurity rules that matched + during transaction processing. You should note that if a rule that belongs to a + chain matches then the entire chain will be recorded. This is because, even + though the disruptive action may not have executed, other per-rule actions have, + and you will need to see the entire chain in order to understand the + rules.

This part is available starting with ModSecurity 2.5.x.

Audit Log Footer (Z)

Part Z is a special part that only has a boundary but no + content. Its only purpose is to signal the end of an audit log.

Storage Formats

ModSecurity supports two audit log storage formats:

  1. Serial audit log format - multiple audit log + files stored in the same file.

  2. Concurrent audit log format - one file is used + for every audit log.

Serial Audit Log Format

The serial audit log format stores multiple audit log entries within the same + file (one after another). This is often very convinent (audit log entries are + easy to find) but this format is only suitable for light logging in the current + ModSecurity implementation because writing to the file is serialised: only one + audit log entry can be written at any one time.

Concurrent Audit Log Format

The concurrent audit log format uses one file per audit log entry, and allows + many transactions to be recorded at once. A hierarchical directory structure is + used to ensure that the number of files created in any one directory remains + relatively small. For example:

$LOGGING-HOME/20081128/20081128-1414/20081128-141417-
+  egDKy38AAAEAAAyMHXsAAAAA

The current time is used to work out the directory structure. The file name is + constructed using the current time and the transaction ID.

The creation of every audit log in concurrent format is recorded with an entry + in the concurrent audit log index file. The format of each + line resembles the common web server access log format. For example:

192.168.0.111 192.168.0.1 - - [28/Nov/2008:15:06:32 +0000]
+  "GET /?p=\\ HTTP/1.1" 200 69 "-" "-" NOfRx38AAAEAAAzcCU4AAAAA
+  "-" /20081128/20081128-1506/20081128-150632-NOfRx38AAAEAAAzcCU4AAAAA
+  0 1183 md5:ffee2d414cd43c2f8ae151652910ed96

The tokens on the line are as follows:

  1. Hostname (or IP address, if the hostname is not known)

  2. Source IP address

  3. Remote user (from HTTP Authentication)

  4. Local user (from identd)

  5. Timestamp

  6. Request line

  7. Response status

  8. Bytes sent (in the response body)

  9. Referrer information

  10. User-Agent information

  11. Transaction ID

  12. Session ID

  13. Audit log file name (relative to the audit logging home, as configured + using the SecAuditLogStorageDir directive)

  14. Audit log offset

  15. Audit log size

  16. Audit log hash (the has begins with the name of the algorithm used, + followed by a colon, followed by the hexadecimal representation of the + hash itself); this hash can be used to verify that the transaction was + correctly recorded and that it hasn't been modified since.

Note

Lines in the index file will be up to 3980 bytes long, and the information + logged will be reduced to fit where necessary. Reduction will occur within + the individual fields, but the overall format will remain the same. The + character L will appear as the last character on a + reduced line. A space will be the last character on a line that was not + reduced to stay within the limit.

Transport Protocol

Audit logs generated in multi-sensor deployments are of little use if left on the + sensors. More commonly, they will be transported to a central logging server using + the transport protocol described in this section:

  1. The transport protocol is based on the HTTP protocol.

  2. The server end is an SSL-enabled web server with HTTP Basic Authentication + configured.

  3. Clients will open a connection to the centralisation web server and + authenticate (given the end-point URI, the username and the + password).

  4. Clients will submit every audit log in a single PUT + transaction, placing the file in the body of the request and additional + information in the request headers (see below for details).

  5. Server will process each submission and respond with an appropriate status + code:

    1. 200 (OK) - the submission was processed; the client can delete the + corresponding audit log entry if it so desires. The same audit log + entry must not be submitted again.

    2. 409 (Conflict) - if the submission is in invalid format and cannot + be processed. The client should attempt to fix the problem with the + submission and attempt delivery again at a later time. This error is + generally going to occur due to a programming error in the protocol + implementation, and not because of the content of the audit log + entry that is being transported.

    3. 500 (Internal Server Error) - if the server was unable to + correctly process the submission, due to its own fault. The client + should re-attempt delivery at a later time. A client that starts + receiving 500 reponses to all its submission should suspend its + operations for a period of time before continuing.

Note

Server implementations are advised to accept all submissions that correctly + implement the protocol. Clients are unlikely to be able to overcome problems + within audit log entries, so such problems are best resolved on the server + side.

Note

When en error occurs, the server may place an explanation of the problem in + the text part of the response line.

Request Headers Information

Each audit log entry submission must contain additional information in the + request headers:

  1. Header X-Content-Hash must contain the audit log + entry hash. Clients should expect the audit log entries to be validated + against the hash by the server.

  2. Header X-ForensicLog-Summary must contain the + entire concurrent format index line.

  3. The Content-Lenght header must be present and + contain the length of the audit log entry.

\ No newline at end of file diff --git a/doc/modsecurity2-data-formats.pdf b/doc/modsecurity2-data-formats.pdf new file mode 100644 index 0000000..1114154 --- /dev/null +++ b/doc/modsecurity2-data-formats.pdf @@ -0,0 +1,634 @@ +%PDF-1.3 +%ª«¬­ +4 0 obj +<< /Type /Info +/Producer (FOP 0.20.5) >> +endobj +5 0 obj +<< /Length 982 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gb"/k?#Q2d'Sc)P'ttsAin-Ho@X%('e7t7,(%#Vh"XPE[C-kDRWr;hJ5Q\<,Vb*/>:.IheO(8(^!:jopK2:Lb4:ZfC;Hq;"5$Qqc6COsFqJ@V1i)DJH&G[1P%**do^J?fk56fJjV(1%f`Rk/t9oBOq`N.iuCZ7OEL'LOuUWaqK;;3\,Wg5a6u&mmZZY(#eUcM.#8#7N16`YmX5`WV?"N?YXZUQ^KXWMfj!B47eP>S>d[(gZ$WIsO86@qtW:;,F&J5Te&cYK,8L*@-5sffO(3(QUVj>P)4&ARWLT2YJRTAeuW8Y(!S!NlI9pACi2/#fVjY%f%+sQ$9aomcUaqnUJl=!oYo/o`R<=:bUPtENS<,Np)+sOa"m.K*'@'AtLlZTu8F]KgK=gLH[QNV4Q0(ou7^JJLYIjC@R<:4>,\`msbH`NXr)>4^dh1]->B*UY";)4Xn\&>6"4mc>E8XMY$!ui2V[p,Hp\r8,d6=<^"s`aO&J5Tes'CAIn8HTp02gbsdWhIB$j@(YB*3sGLkpjW,&-c/]Sc53MW8d+9WOtP<4O*@/g2D_+sJ61'@DgMM73FhH`,OU=n6q"sP7a()I:.K[JG>W;6i\t/B\)B$(;amL*8ebFFgj, +endstream +endobj +6 0 obj +<> +stream +Gb!9sLV"j4[4VAB]Q^ROhG"[q",MK%LuBP+:,Ola%8?r\cqR"AM2ELu'd`P+]5u9^OTMiqn;HhYJ0Vq?+XjR\`OlQN]C1CWbV79)ni@cBBss/I*UH:XZ(-;B=2mVfE4/V>29soVReA>OaaWbRFXtb>1I41WGTd7Lf.69#JjLH-"jdG*af.(S$`S3>uYPqHgEF`_a`@!E*'oTE%?GV9=LlKL=&AC"0$rTAhmXnC1dWWO1#i[LD@4J,)O2mD+]/L&0MWn`K:ICfWX`KMX^ZOP%J/f_O+baXaqM7C>)e8qPXN\bj3N^>Zoi)bqpVm"NQ>#U!,8C=HSj(NDm=hW!f:.qNWpPHjY7Vj'2HML9(ChoUd#s]fX7t!g%rqN;=8T7^t_'qR;S@"CsV[@)ff\lptm,W721@?';E^MNsV8@8Pp[=`uNAB4Qe!c!BuKIOM.k,-ClBRu5$h_scOC_dL`m)LM"m9V3pjm'/HJUS8uht"mk'\-)h`4If8OR(NE?R?#M#?&maH&7>nLtF]5c2Z!D5*u%FD-ii2:6WH:5p/4YSG2O:Ko:Z%]957fjW5KdXm@58/>V*Z@F="B)!jSZ'%h_V4&KL`DZabGoBGC%Q;_N/qKTID^&Tr4YP\@PH=SW%?Ud;\sKYIZg@.iT7:GHZX>08$[IR^D4VeqLrdJ%r6#7DY-C)]M-ci.4]R`r^V17!d=,=)-['J:T3^Eg_Z6-WIgh<(gFb&H&e6eH[R-79"mB%&A%Ves"7.W2D-,0^^KK>S)-YfJ"Mt?*d-ha0)f)18dH"MK\A#R;gF`#7uq28%Dn'hM(EB8q`*_b,j4_JK$S>`_tS2_T^(7,W$52/a?a?kZP!U8k+uL43PCTNU7B]+0QAY;$Ypb$$gCJq53U&\N\,$HF.@6D_^-m+0eb/?02pJ"#)@c*,J_[S6kAn)\n/1''h1f,%R;6CNMV#j_kS"%m;+XWaf-F/4-`!]%d8>&9c4Gd6pP?o,uQL0eRH["2i&4N$BfP3FqeD0Gd8g%9VhpWk`-s:X]:?+2Y971f0;"+]J5saQNKD>>lq<@jN]/qQSV^cYht39@\d;^$E?b.5+_SVtXX;2#LC'J^,(,'N+WW39UCh";9uX_>)Ur?s.q(^MC"aeX=*[uROb>YN79rRLE^r/@cl??.?9qWre;4uFC.;/&TP6Bdg*?MY2>L`>:n`IAXRW(>oU9=_![_2ll_T/_S(Dp3nS\UmO[_ibZg"MEW78.77Shaf+.kr`'OHf!FX.%mWPp;K$#/'J=c,92!`N56[8`eo7OlJ&A<%'],@Q)lJZBI'kkW>7TOaoe)(R54@lC=B@A&6Z1N=uC"or0j4=\**UJ-roa@eKIIb*$Q_6%01Ch\Rk*Y68krVWt7ae8f1)'q3,n0lQanhKGJkmN7r!c@TB/0g=2X[$O\CN$WMb2K3=DY4/gn1m'RuUYnjTVo!n?[5`:QU!&cc$XRVGWd/_aRQdJd?sQ2\HY$mQGFQeW:okZr)C*BRVHB_^5kTPa%rDbMauoK>mufH89Z:qfVZ<4#il`Wlt<5g7,0CY?o2q@k[gNX(Z?s?#Gm=]GVV4N_WjXF)PMX?baHK9b"!Mr)EsU$E&n'ElH3K7K9\*k]E9K/QsHSPa-7)7"*T&HbbtONaDh_1ll?tuA6]9ErOIp[::*2E1)\&R"@F:RVdZm)eW`6.f!tuNRWXcJ#"YBE1;/&DBh%+;JM?AK2!e5uW/s@uPNGfA__>ANL96;7KN8is/+I4_#!KIUm"%R1Og-1?)btWmVh&iQ.(H=t/3"?U7O9X%5h:SGopA9p>E^]B)Jq%2U)L+:LJ!-T#TWhb8-aFEI<%:8CG[G0-jE4QGB$VGm/kq/^gSE#"r0]CeE"D"*')r6.q7^%35\41LgsNVY_dtZ&<,I^^BUaQ!:f<2)1kjug;O33A'5WD)/%>":0,!N9Q\p\cp?(07>sXVM2cTZLbt26TYkiX3!U+uSeqPeP``B,fp+4;(ZB3M^WCVs+IROJU.A_[.j53`7A7pBGRbQeYP5,O+'uPqL2No&G*I**urRIM$e;Hr"8aR.s=Q&i;aMn6g$CO#Z5`V!egoQb3BXBP6s*EZlTTWKO2%+I!RC!+HQAHBi5t.;;f0OX*;jAB/[iHYeKOR!]H3\7EVfL`NT$e#;!6,`#P6T\!EagC-\'+*553XkF*n/"?P@CKhq%e-DDa!\5jJkF#lR]hq"6'TTh?n_%$gs[T(@C(sC[I6YM]EYbE,>B&Pq_bMq!WOJ(YmFr>14I5b3_;TN_1intL'5amRNX(fS:eH6.8"]2c&?S`k[B3Um$eiPO%;IZnG>4$\0,,b.:'sHc5@;t*J[$>F:d;.KuiUE+]h$E2k9HPdB-'9lB:KMKn>l`q1G"-SE6^*nk>e%HNeU()\:4Xg464OU]fXFK@E!/7Xj`!fUNjeC.N9L?pY4DX40P4M&2X53oQ%1,'J/p"^o_"oh<:ADLY9=i,tgTi@(]DbWKK)MJXS2G'dI54f>2VS(3UKqO`K;ZW1!#bb19*&Y:oPo5\g;IPZmBX^EGY5fDLN%/'^m\m_CU/;+M/lFt"EYssI4?aY!La?V'"b"H:A*JPh$%SW=oos[_9:k]r+-m=JndQ!JmXnLO'VP0bpY?tUTjmR95)O-mRHIR8H.V.81m7J8=A5%$&)''/J1Re]sOqWBCi3a:oi`bpTHub$#3.h_.obq(co_-M?:%+79$&"R=F[s&Aum&C&X"hSs7\`B$c:icXU#WSG`UGT/$s]JI1%ugS$H^>[qd;@:4LU^kj'4fn$37[QcnY,S*?425"&-+sI)\cB5[f[0+%'24JJZ$5fL'kLt#gU+,Y!`?r97QN/2p3#;PVF3>QI;DkCsKUMTMo-GWiV@Oc_R_@J[#'5fjUqid3Z<#FC%-Z2T[Do^)YVIq%91Ook*4?l74Ep)8k=Q'E'G9c]c8JI',f7(hM*-SnJYSP/.ptW2De"ekRFF@ei]KCV",s4K6KD1*Y6I5cEMKI59=Rts&d>V=_1/cMK$CPf.*BDO$,)'b^2B0Q9A3grM<7OQs#3e.9tKAE0XI6LhNU&n.cT\6pY,ChauqcZY$kt5kaFUY&mB'e:?=K5PbMumUTk>Ee_it5[OD5%D"=;&#WiXe]_3?Q766^p3Lfi^c?(ni]pQUhM<#:eN>N+AhhVeM$dGW72V8Hcdj*#qMRdo'6skZ*:SkcNhiQ18H3!b2>+Zu6i4ACX2Vln'I'u?,R[n50#V<_7j;(%>?-#oX2Zal'=2&0X\ia`'[Cb-ll$b6lT@TT`?%Tk!r0Uf9UN4+:iK,fAJn!_WtE'WCBWl?ls^ij&XAlh$P[WG.p5fJY0]V.,Va!q!^Oh:EP>gH.+###0,cc,?5,ZLZ(lq>gCZ*:"(6A@P3+)1]hJPQMJ*Y*FUYO(+VU-"7jJ[;IO'(t`t\Ls/hIC4!I/-oQC$Ce*%fIV<'ipi0^A30S,lcfR>=*FUY28j.dU8"=a4eIQ:MOf+2ng=``c5Jm&6++mIst_QK5Y9e7B?bNW9\m+@g%8/U.%%$;%gP'/[gfI6\gCR*'laY\m1fM`o[[&iTrMN@16D[d8`LE5([;GIaW\>s?-Z7o"s[j^/5-&]ou33fG!O6&EB.5t+ujU)4$S44m[kEHV4(P$PU0cVUI(+^r=3smJaP8]95`^_=`Nol%KaJ73E_7ra_5r6=aMV\2Z"ADE8X=b2+/>CMQA2^+i8\CJ!rD(cm\VU^>:0O!!V?OlQBW-LLK#'k7e(YQb`^%B^CnTmKi_W/?%,KGVK_5Yn)uHE)+HXMegQ_bdJ8(37$GjruU$Z.Pp\@20![J:nIu:%-Et#>YEefe+fto*:m)Z7n^Yap(BE>RdO'o^f^UDdqlc@\+)(7CP?H2'E8-s,&2&q:PN"q-n'b5-C@4\6E8k*fA7maHlkZ"(U&'0XI,k"5L3/T(Fg*(fSZ=!Ar1,LqlsO[De\,pHFCCSdl>9&A%>8f08.%TM2t6[mWKA;NBn1bLBZ50cnr%LA4g9rM`"qes^9o)uSBtl#,(GGb"9VMjO!h4@Z8H,iOb.[Zl!+:FMU;EQ`Z7arPo[sR%PS>N*"*K9QMTr=q1Tfr(o@a4R1UKQHA,ode%81iS;G-4.RG%rOh%SJ*rJlU#QBJ,V">S#$3Xe@#*gK5VadRj,aTVX.FuF8,mG5*iFa+7Q6Npg^`s-.i`aN`nn1N=DgG>R^/a-Nuu,&*+9L9HtaE!L9F@\=WgdB9a<]BQf;].\5ICF5neb4#.a-F)5BbJe21/MN'WfVP]UeTa"Db^lpN+,A0XGanK&J($LW><6[[#>T&$R"6]/Bi]/_aE[D0p8X:MUr^&Xkch4NL&_N@JChj3/KJf/9SGOQuV.e=Ckl'I@Ap:P#ru'1[;WS$c3U0RH)0Nt4\d:O#JJZFJeG"t1\i7)WjO,D)$=10Y0[KN!?dZ+i,f6)*j*+2*&$gmpp%5#pFK*WXesVT3eFRV%)6AZ>`4K,r"qH17tNC9s+@8ANoTBXIgojYJ]8&b8:6d>3?86p?36UKPOXQe>@e;"#=OedT9MF$oqa%![!%Kn;<#i1%*jIh8j=r^),/A>P@=jWak4Zt;IF#J1k(liUCDF(i")Bi6;6T/+c#=g@dOB.+@1pTZXDA$Knt6jCHJRI-$G3[.J#0Q`YCLscGT%b_n"hT&HgHl.d)k%BC,mG'5=0b&aOEL`mgc*4epP.e,A>J+5Ob)70!u-O,/8C+BdG@@h$?l0kM^hRa3fgdj?Fc#*tZ^]`s9ZoJ5JiDFmLb4&Os6aY\2((IE[*aAk]4-*F)-LlK&d?$$50d)@m2,,#(pC;-WgK3GLoR5d#o7>Ll-jsnpJdD$=hV2`SA(VCW;fU>G0E'B/q_I@:,%ZV"H3X1-k%2csj&L9iDk^a?&0>YT7[GmE&V]*,T@h^ZYE>V"Gube[e1"f!1DZ;h9/&AXd#[dYb39U.&(6[UfE:"Wf5PCGX+#!.(+d;NDTNG(/_1^e,)E.>N`ZuF459fE#l2_13'TSh[DE&=NfM[Q@[7m1%,c9Km?=mg>[d@,R-[--7E)Y\q/nLqN$oIZO;gbS(Imc_pO,`%:C,tK+%09V]ipULakO7ks;AnVhi\?NAk@^LtGW@SC`oa;$uQ6e>=#c@j6U?p_R+VBo%:h.j]Bh4UpQT=:PB]K1lt"fI]dIF%oKT6%l.BGIMSZpB1[AS3u0c(W?Z9?B:a\\(asoaC=M,t?[_(M.]\/Rr=I_1<)sQQbT0*9r6=GZ(E9\u02f:;[MVUE;Ha@76!(p+;@UN+@Sc+un>(jBiUXAAI&!-YO_,_MiVNHZ+F*`ij7On>E=F>:ags\'jLjJJk(2]E0u5OT#PslRH/@b`&cM5%XJXQA&\@dp`+n(blrXI6B!;X_QlF.WBqCZL4#V.1\Y'ZmG,rb1[Eh#ah4k@lAr[!]q^tNMk-ERa=A`n3bh?V,U/+Db[mPh%=.cpi#jRTFSikEKQMmW!_Y,Zs0?bq"6%OICUHWOM:E1?et\j01']F)qnpnDbu<\gR'1kL^M_1uKm["A)'"'+G"_&mG$jSUqc#'9n-LG:6;l97EnVb9R.La2ihd(1=9=J?ij'S$EWa^%&I\q#p+ZSY"qW.e0X#83Vi+M\4H"'WB2kkQ=L.A\-_aSRTXoHEk[AK75h_Ck!?smjdX[fP7CXt([05EHNo6/NZ>Q-=8g,1:>*=&+b`]7VSO.61#jB70%GD3d8L#VEdFHmkE&#qkGaf!cUhh1_Wm:12i84nT6Rn)X16[*Wq5E[ICbd#:j^mr2j`(;eR3)"H?tGOC#R*hqF8CH1MTZFe=0r>;eL!:9?CMc6nF\'WZNcJ`K"?E&aY$ld2B\:[K->*tf6ce,3F&Q:bj^RVoFJ`s4[AM/_h)]1E(_c=,0]-[nq>m<*``^rrC5lDGD4#3)tF74'!sIPh-j"?fOVaag.Cb_9g8WeHEQ@.]&%Jf>l!]UNU9q-HNjlfYj!=]p`$>ajaGjTkAZ(Wu2P%-t,(uaX+8E_M0a6C93Hp(T.E)u4rVU,T#1841h(Yg-?Ls@fc<&l#/,<6^^Mf)M[*7TiI^-FJ2/ok2giu2bADhG+@+nrUhUr.GpO(7(cTDV/rHse6Ih#j3fME,:GH?F,;"7m0V.&Af1nPHsXHmk(?r6G%63/?0&S#/.q#X_6R2rVLa!;kuAQ3umftti\fnKk>=rXh;aH`\8UU+s$,%k1%a'$)W/4!@SbaX.@7*]])!L^&o-/Dpe%Xs+V33Y3%:7uS`$6KR!'(qBg1%in(18]j\AK$C45@b8@#^C&XY:H;-4eqFSJq^ciXr+%^:;KiE\_*ccCco]P!d(65>)"=*al,?B"QcH+#\QFTm4%,SDFEDZN(fotDdN]]`bP/0ikXQ$b2L5u5[onR)O/Z&<((r#jt]r0kO5("*9F((:;MuKSU18m+DEQ`13N\5Y``/-!VtAP1EmLWCp:$?)P&&Y-tK[0"j0d!/?t>XTUg"+$K_mc's)olXmcqCn+M![3Za+Wam-;I(#$#bEb_<;;^a,G+o"U)W2pHmOJ7(RZSS,\2>I;dE=>L<1c=10VduMBl!GueG>B3mFTDh)!=sdE'=jE)LE\KBgd"32;;FF+ap:RB,']a^i;ed?C9;LZG5qUr\q\[TMg`_l7+!^uhs/uIelM5"oB-d.gck#*.!-@8D6EYM&3Y=iu'o3EI2tWi$.#$2HSV=pHETcqb)jKl%9XB[\l/U0-A+5nL/2YS/_t9E#Y!E;7,\;c\]s??/s#,A<5"R$/e`modK>['hFP3!9uR3-:t])X[k5RL9:h`Xj%[DdF/.fk<7b1eJ8[#&)7HNQaeAZ>mGg#Y6YPM@dre67e^;3^"CdO@8+7=b,,g"3/ZpDU^%9s?kM\8BfCuDdck#D8VD1*2$ZqQ'-a'!%0IE$it2<63K")2OPXEdfY@\c^OkcCs&+VDHm4F5K@Rmt\A**1cN4kHN'.s[+Ae^hX:'sHSU16"%$2=q!mFt)$lXGN3il=5LNWSNpLESJ1,b"+fK#hP8`Fln'`#2,DYR)`X=eQr=7S+H&/l3+3B>3=eue!18:>r`+5)8r!]K6!p!Zh["m#r]i_iGNRsp8XQ)@I51i]CD$ZQa%G+e1E7%jX7S-[hhJJh,.TW9,:fpPqYIj`u##[#LSVh,",^*55_Cq96"Z)I_LI@bl6e[/:V;Ka:/P$52O!U%aJk5!8e9,=J>S#Tm'PKA-lX_*D/&BrJ&LRuWL6Ou8BIX`c9r4LOJP2a^$>F((7d0K]`(16TkW\L5?l&X^i!FEN&8>rR4?#i\j`FBM'<,I5Xo_7c!";oj1'E`:AH7<1ok&KR#$T:[5V3C#P*sa:pFG?qp=BN6Jc.*jM^g;qlH:7VN&EES"d]7L=[9i,@Ik=Oqp30[Y2Mr+7s`=4!7K(bfQ8g%j%0OpFQ[(N*KZB#<$Lj($8c_014VS9Jd`g,69)R`pn^Gr"Ui2`-J(!rcFJ*EN:NXoUXs/,+rRD@;g00P>bIk?^k_kp@H,p+(7#=0N,=G#Mee7?&d*YFcsp!BMF@riC&Ah&RI_@1:J(4#t$Bu\.`X6B;o*EN@"];]\"6C@:mV9NYJg5$HlI"%Xl#_o?rn/BGH7M>]mZ@Za\97g\G^ID"i'qpcQ38ac:*R``ic,@Lj)s6CT5*[7e4VSRg(f)p<=k%?f#i((.E`e@&:+RkQA]-gu+/!&<7Pl+R[!%Xf>`2pfbf!m&n^HfcgtW"d?+lC\o]*?(+OcFHm-,^*l?+ZtQXltZr9._Pp^H+6$r]3[f=AA;ZXO8SmZ?Kp`Ya7@7-u>48SoEKRV8J3A&2L_0T"?@L?jQ;0HFUk.H`NmrgJ(.(e#2+1cZtb5jq=@S-Tj^NGs8OamO>n_PR5*?MVJdbk>STg!?mDj(/bgHh<2t7eE\LfVVL_!A(T#85cm[dQgaa0q*s:.9k&CQN&FY.[tHn"?RB_R3a6;3/!VG_V(Fb3m2W<,`/+t%SedHY>)EiTc9QmdC:Z">LQN$I,J,\%Bs'C$9DduT.s3UbO3.:pgMATn/%S<*J&/a+,07>ON.(#Y'98Zb0jP$!PfooTqlZS`RV6LGfi;b\teKu/XMQ.mIj$4Tm4m[m_pc/RpMi>%nSVT*/>q;8>+jb]hK58_QJ`hHs.NJLt;l(-iKG`c3NqnBm0;$q4H"R)Rid^K,j/27rNTFfbZh&=ZL/%Pnj!rBi('@H!$pR8>i,iD5JqHW'b6F7LTJ@:8LrL=>"Hme9QOT,K;[tZM$_HeB>SbGL64SZXm$,M!a"(Bc;Am8%($EiKo0E,npX*iX;8FVPPN:,jgJ/blZ3`*rp5t)%$lBMI.>`A3WG,,j_^o:(a$Ol,nH=,??PpUkJQ*!",E":Wf0Ur!(h@#C`@N_006$5MTUT5"f>N,o+Ng2:W?ArajC=Sn_qcSb6eflZZ-:6_@82jU?\&.Me[ZG3d0;H^1I>?6X_WmZOZSjA8NgSp*ZZXr]q[XG9CmE:t']amA'i@t[,:M%`_VXJC!,HZfn(lj?6'4o^NnMs$q;ptJos69l\lYc7sk+1ohY1YA)QdP$7$X#TqItu1]YDk_#YCHFgUlo3NK`WhFJV1N3P809Y6J%Tpc4R]TNEKLp!]qi/H#bW",ZQ@biE0?Q\%#J?"HE;`+D)`Sg7NsTfNXp0\fP,Y5\Ua^?gXZ6aKo`$KVD:o>EXZZ9.'eU(ro_*Ck)p[poLS#lRo*@'("6iB'`sPn1O_ZOpsf!kVs20n?;LrDeiFuP(#gOBp+_p'LQq<0J2%LMJ9Yu(9$,i]5Jo,^lsMk(RUZ5+4BU6s)Q$8^l@_bCH"0YVR9LYleQG&t$0P?P'S&&E'"KaM(L2fT-HA;^6@b:O#6eM9]Tn8LW]U=n$W#_BB!WKLUb]?X/P[jgM-h6U)BJh%lec8@XFD8j>%<,A3U75%)GWNJ%3&u45_:KCn!7;8^Mk,>u2:e]W]o.-4cG7"W8G:31CI_S1h`$qACA\YrtuBrV2[_4jmYUC_9CTp94J;VYOb\HVp.g6`O,psB#H8.SV9i:!Y<2k]t%*`4E'O=csU'-+s,#$]8Q@k"mP!]6QciS]Z<'BSEX$!R3V%bV(ebRHP\AmnrdCu(mU9d.`Fh7KD97SjD'IK5.rTZagMo(9$VLbLm]@^.CQZZ9K>.Y[j1oj<2D3$E[Z]%:#F=Z?cIik,I3saMhbcT])d@?eH@j#c'[EBOtf(j]u-QV;m-1^KKD77+Zie1)e[2n/VC'T"H:EnmW-/_'DT;k@4fO70MCjdL!?n8D-1cN;B\Sb"mA]UXPo#Yhg=[2"kq%lUB,^R.U7LE<:/_:7Fcfme`7i:""1KV/-i[IMi$$p0u]48d.mBD&hklI[VQ]j-F!f%Sk*,Mhg"-GUGRP$D5A&.=TZc6@S,?S"nR"71V-0(Z*dCYm]3LZrM'4-:`Kcr4U,Bt)t'b?=*#0nE:%QccMHh-8SqDX7_[nFc24;#X1f*?[[1g*QK2/C`(Np/n+LikY30&p1HPN_ZtJcVl-2K?+!MNDlMQo%_2.+jspNA4C!XMF\'1'DV#Emg1$23BnlVFJ]dFW/i+*`/\D0*lR32$u;MFVu,Z3c`_e3p_b9!>\Z.8raUSV>6<'@>i-3$>b(jLM!d/:UtIo">U\GYbA88.^&f3kejp[-E2MS;-21\KU*P:Wc3X%LLNE!l3,E?bW?A^>He*d9IV>4dr\R*5g'G$s/DZnp"_'Tlqq-fttk.83_Ygd^C0@LOVJ/VRD)I"92Pt3\uUigUMgoJ_mJ]U':DO%s,tS2.N=hCn^?jEKm]E(c;*)'d@04g@oW'2WdE_P)gl-;N46D=!Sp.*^F$CZ"ja)QWMVg?C*)-;NO>,mQ:6p$hpAMBEd"M9K0C+97QMgj6#Y:,b>r>Efh`Z@^?J?:>fli8!CL[h*WR]d`8Jk7OeC9fU7"9?2&O)2!e3;fAZ.3g\#2-)7;!<7J?+':+@tkEUita\_0SZ5k)'7]Q=$@Wpp?6f?i4cqUVmO(7lLQ,[6Umf/if-2/MS"aCCm;Voo]3,sC8Y%l@eSMUraTo6NUi;jAg/J)0^!\qTt"0Vg,6]RL'U`Y3Y3k1f!LW^PD7&pPM<7p..M2EC`f*a5:D5tJH^ISEKN$N5bVf<2HC/$I1IiNW;AV0n>OctG>@fPCg32NRFkpAS9SY4M`7NgMRe1RR!p,(LcIGoCttDSs6_SmT/6X38dFs(kEO8oPG\Pj1*S\QW2_<%[Q#8dW#b]Wm8J.q:Xq$;s(O6q)5[?5Q3nI%SW=MH,<5&DfF6[hjL9Esl)+3Z$-V#[VFRE;sk>rhHTQqH")+KlP2t8H5[i!IHhgBQmt72pkr?4.ZN1WcF\i+[k^bs!0;N*N#2Ds+8WeAV]PF-r"0B`Qgk::n/qK/ok]"??i9+/Xko:PCBN7#^XnF53Suf!UC4.9,(C#MGu#pfI/qmiq;2gcgsJ:H74PQs(jEK7MH^J,H[kD1@N8D=ME\%Y+<)`-TSZS<&R!q;,^(p]J$"r$q,.n3<_cO9YH&W&W/n2Ps!1HBoQ4NNr_>uH_B#n1:A"\+l:!#Gerh7rk`^c@]d$-'[ind]/(WV"4as+n&9aTF+Hnu&IT>3)7t%Z58s+jF2>TnN7q!nLm]"eUh8+nY:BoD7VP7W!jS0bXCuTABhd+Ma]l7-3\rcMTLd/^E$V=sO=a;P%'?a_0Co2FU$J;%Or-:W,Gc1DJtRb!M]V-24*VaPl#J@sN/;7$CT7oaeut'][0F96Q]2j]h#nOG]A)rI6Ueh/r=q^>OLA@d[]Kt/s#mK$8'Tlgk]I,Xn!9`74Z9'[ct/Qs^Cb+eA\];eQ9!*,YbfKP5c!Fh)P`UM=HbE<"HQ8FX1T6&U,f,P@dhNnQWNg148dZ7l9Z.CVESX>dUd^"3,M/BVIY$EEplStcAP3(a[(cdjTBt?_[+5/(1`Y9pOa3eV\7`fSegZ+>!%T"&qq5&M%9>R1E/,a(Tlrn]Y^p9hGb^PK@C!\5I%cTpi`8b5pj&$/#fm/)PZI1-[%EXKAZS6\E9b:Ng`"&=5lK9$`]$XW3M.Th@^BBTggb!qeRbVjI4fF'T7a?/St\WD^@#-.V)in;\@aV5mkAAQhI!s0m.kj!=oHiD,^lr'g28O5g6%Q3/?T7R"F-Q/(e'9PfZ;,X!diL#J2%ioXd:nkl.)(0=$Fl*TnsJDYRrK$FN\Fk@GgUY*=2EYlG%)->IC4^gM!qRpGagZdX7Po^Q99XPn1T@2F9H._.%erDTTa=t5J_XY)h\@Hmn+k[O[qY^6b,geM$LZ;T9s$49N['tKMJ5G+Im]I:$;iP.6PmU,$#>\@"R\NjGa*QTmL*%WH'I(a`DlX-I_IpRBntiQ1gt(BMmR,pjUOTUUFJ6(U4U!GrmqDW1K'0=NEWr0qIVT,\=:6geOpoNX0h\sZLA`I#s4"j1h:Q]CKWl+V(W!u`DakGmN;Uc)`j#3H61buR%Cis3JELM`_F39.]a/]8//r)NBD/Kdf&d,P_6C%Sj5iHejaDiBNCQElZ%2#DAKc#Ht"V=R&^28;6S<)has/g&a/:&_JUM':=ijE*1B"NnPMXneQUd^#8?ctn3(Mr@3(OuGCkA,u!c&G8,5d?UBcFHN->r6/@3Z!nWih=>$JLo*+g,_R(QT6gu%hq>pXsl+VoiM_,Lm&kd:?MV%=dsbi7Zjc08SiE.nl(9VF=n_e2jk.#-GUO%6=fdNm!S#2D0+Xjh']BFq;%Me/UOi\K5KN4:rg=c]QV3P=#cO@'GE*bN/+PYofs8;Jm&ln7Jnjhe$N]=J]nH8qA1eWk;:+#22=7m5qjun#T,5h9qJ"3+uVN+j7qC@PS-D0J4Qk`0efCHrfQ-\NaTA79U3Ilc=0W.c=g[aZ2WD!^Y#Qmt73n5nOtDbrVqK!MOd+/"0QpfC]P@m)/*_'PK6IRc+\-.0k7i*CE(#"-k5jZZt$T>(O':4Wnh+AJYQ9IWG"JdHB>*oVs9sK%DWOVO?VOqQ&W5NXY0&=W:G=qbSI)_4Z+j9M?I#qM`5k,G^$l5LK=oYKH1O`A!Sa?FNj%HjWO>K4UZt/Js2:=.8+>0b0^["1DbiRllC.L*<@&ClLR(5$^RT0]T#&R;.F.'r]NT)q8KmL+KsOBk!2X`bRb.ftsp1C((]dA_2G/D>d*f<=6ECrg9gqW3n[U3jm<78H[>R'd.!\iWf4/2^N?P8)_tYB\n1&@&`P=i3D;LUL8c\FI>s[IY[?M)7>XB`l't`gR;3.cQ$cn2Y)[NiC)*#N;$7h\8&cLMI\gA^57:JEN(u^8R[V(SFc*=e#u!5Il"aj:u5>k(0@Ej/F<#$`)TcH+tjD#@$%_HUCrYSI#&mi8q;2p'?3:F$j,E&s-;k;"dsH6^Y+F8WIAm#jKf\f=:AZD88Ng"\cF)8`Kj`Zici3pJqYD0[G.>a-A,,:=nAqWWWYs0#Kj,-aN:'_p@`17P+Zr=6_%NO,$fMVh`(d=T1UApdF6(Sp%1^nk-i_2amnWNpc-"LFpA#Zbi_R(OYY.8;O--<<[Ka>F&))d.Di'nNn/QEnA39mZ0bM9,a\dZ5I^Bo.mJBTJm>f)p6H^bU?j,2q)Xbiq:NL7'mW/=rpHHgLZO.Ukc4$4(j$XS2nU>)a8=f4M=H`TtLF[L67!-Ghk80=(l\lAPdqSIKG21oN7B3@Rm?e]n)UIf'g'M(o4CRnRlH89:C/aAjm2pg!%paQWdg+?ER;`bmX\Z?NK;+e(9d[fUQG9I?f`XA3Rg910:&)`ss6iVc8,s&uZ&6+O(L[lSA.iDm-nU-QAe;.S!&-nUe>-cUA`WCT,.3ejUSmUlDLr@M,]4fb>D614#[8\a)!pAh=;O""m(GD!YW76g":m8jikZNns7523kkSC]&\I_^9rCYbdXXoF#r5Zpa;R>ZYb,\u5m4pTBQ8G<+rqXcod%bDJ02T-Pi0U=XQF82UqU3<@H9rE?dL.]%*62:9Q&+Ngm#k%0P`o*2PlI2P/C&ROsmW54jn[UP[=Pe1K'R)q/O6tBMK\$%CIq*:n*]%Go1AVqZf4/^C'mSi=4I_bO-__0jgJu->KT3E+4Jk$r(\PaZ]^(l5eWN3!kE*$Rh&a@%jfZ:l%R_7i9DH*Qtc+3`10d<0LT].f>-!G^ROYi&K"36YqkY$7,u53"#sAf@Y`;rj#%0f4:>($,_g7a#:HI_aF/HAA767VpQ5dAE%%DP4-[2mR+kPuO;;6GEspA_9i.S$9bm>pa"=6>]?bsrP)=8-#/GOL@d=VNYTcbMJMe35Eb(rq7Te8n"'So.1]OllaS=IX6u%3;AVQJK05:k?o$`Q%Z;";-cU_l'VSb$fau(_&EU!91(5'F#n_HC&%U7Q1s@dl`5\;A.t)<.$lBq#,%)^h$l-#_Y:Xbh9#G9fGWlHI)/MRh&?S7&q!__W2NUHm,[AGOh:R/."mS2J\pJ.*\bS=!sgfag""o(,EX5meUq_f%\KHr\\GM`f="M]RLpi5]CZF)2jm?Cag!N)^pj`0pUf'ErH\c#l[Te("_l6klQ[9[U_f+S(_s#2-*B[Ij?pk,qtV'B&kUVJZt$eYVLW3(6.ft\Gc4_dd4#N(:AD6Ths4p0-V3Q)#sV3!d<>NB[qTE^npmhUIUp`Ei9>C,[k;TNQ$#P[b="eVDq^bQ;-_K1?I0&(5ZhJl+K\+kS7]UIi@'>p@bC2P>PNSd]8@L2]/pDJ,m>.Q0Ulp_T*@V5Ych;L/d3[8DJpt!t5R4b)(ChY&Fq3'2:64)KUXEO>%#jBZ@fC1N2M?F-cZ?hbObTFEd-b*/=fQIBk&c5"6>J8/!$1\'&^_@uK&R>;#k+?@KIK%5FY,#T%_)8N]IEqsDON^5!#r%Hr.:7V`i1si3q1.7b?)YrS#X?u_frIi/-9H7_)8I[>f2k`gosTWUbkRkD>rI8;4hO#+.$qV1h&uaV"6]#ljKc$.D/-]C(PE`;00K3H"Gk-['Qr"WHJ0M97D!^dN>$fka#`(]B4puIdeFX=+,2_]O<*&,H8e8!7#Aa-OYf$,t#C`5I.uSpdHE>X?#A-(J[3ll=8/Pp@NVhS\OM]k:aGaf$`"ca<.JFmpgrmQZ-ET&UW*J&%QbPq"@&R>O(A@UUTnmUkT';;V8D2k.9@]XPSppr+Jm\pj3oY;j(8rHV$tb5^=m>E1fF\tdQ`4?I`b?AC,X)7d,=QBO2j!?a7#GV%W=5&gf"KpK'.#?#rtuRn(uq8'fAjhK@hX:JKZLa,CBiII'E"k#k1fB2Ym4Ds\tUZP#HHFt[]rlDW$,!kJ+2Ki(l91P0Nc25Sl-(gR7Eq_$K3hd[:;(cK_e.Zn#0?cl@IEMEaJ<,Xn]\Vds-*W.J.209`9Ah$\YTDFH"8+NF:/u`+IYP'Rq:EX4DTdGT),"jI$Kpd1'6:WM[U:4?Yln//V_h6GCQ=Ap%pmc%mF:eh9(t@)dN#FENLnGr5b4.!ZZ=D;4IAdljhWP;[.j4Y'E!bahVdR(>nPRGb\^CJOCs/90eqenhWOJ_`5-]##&K@<9TR)5U)7qp%i'[K734@`:1%EFPQjGlZIr_d2+X[uI5#s!ER`dK?e[:)lPC;jL"1@o`,Bb4:ADgteZYOGoCX%=NBaEB@g=Zk/U&W-^c;W>]<8R4c9!*Bq50e_n]u^\gUlpeCBO6Vn%JJD9<[MCh/_CK:S2^g5*K"]755%h39mU$NO0r,FriI>d$$+bYi5#^*r>]YIds=#s7s'HhgLQAi,>g4q5aOAnbu%.21OH<@ufIAOYQGgGsY;l6/_r"`j#QIE-8*rs&gEb2>;0U`Yc?W9(!g:f`$#MdS:9]K2a$X*1V`n++9),f>Ao]fDnc%umsb<-PL'6r#<+j:eaHhLa5K[G$9FO%RFf9;Oc2Jq9V;7ulV?G9->rR@X>O632sUifK,h4+07g;UZDSkD&HN-,/SP2/)(<#MZ6Adn._O.P7ZjS*Q:oeU%8K,mh@5$\LbR`r8=Vo^G1RuiOhqqh78I8@L45CJ;A$]7ib:\NnmNG.Y:,A2LB_M[.rYMF'dRXG!Cn\=k'[f$!DC4Et\PLYFn[q.%#j-'>OdijX,'A(rMGN3#\VT#daMJlSe37qXQfC31,P:%EmX=q5?(?(D_lG-fG"-8\c/iMF':uW:&VcueiQ+rjU:HUGO@8$Gn]*)94Rn`f_MH;?%;abRpUI6NV=FUb.mkY^V'48/O/*6o]_]k\10th)6L>YX:&D,:qZ]#7:/.>lDniPlG%iKnj!-Df"ViN4-3S5^%(5h^]*Un=5NT1f?V'AcbgR>JL@k/<;gtU*\A_//.IJMBn&"S,ETug3^bsGC5dSf9(_*r7*O7_qPpOD;3lZP@)oem'![Fq+1,S[a\NGUn+_4g7CVQP>ZlIr0-G0G`>c%fpm>P7I/CK;a0Y9YH#_Va8Dc:[HXEdc`o2Isg7uhD9Y+eC$ju$I;^X^%ENJ3bcRn+"d7HNuO]UnZjS1RR4kKcc#8&)I6A.R^2(T0:dJZd!lOpK3NQ_Or+@Gg<%$_+8BZ<>05qlcR<+;(bN%jC==*EWcUu.2&s'uR68ahdOA8KplQr-7SuNi4*lA=h+Y7=X7/!m!.Kfrq8$G7`mq_L`>5&J/d;r!M?J6bN$)c!r&&.mQ"N7B>pBtb+ucH(-nb<)rKbb?mGF=.h0JY*Z^9PF]0EqjfLGGH\)2W^0@m"kH26%Q'e;)%nrcVjni,Fqh!9H>^U-=W3=B25ocs>R[CglJPN6'g'oTlUcHjYtl!*No*d[b9YQ&Hq1<@5#..`"^2Z&6b`\$OPjsT:g,?1uD+kSW#f3WfF-t<,QT6X?)+&c2M)c8_IA)^>$:qV9DP"XC=MV4d9+1uQbj*ra8-]@J7;OaL1Jk"#9Tt,bJ4Zd*B_`>-lI-?`4m?K6gXsLW8?Q8NmfUeFM#Foq[UudY[_L?m#]2L&R#Nkj[mRGT!o'lSHdkI/%?b/o(aL_0;7emZYRIa%`-kM7MmOg\jSE1ScEj]0F;Hn!qefD5G"T5k*5%!]h,O@X5,ER43VeR[Lb`krkrI\,IRMCZl9-Rqae?8lirZA5=pIji'b2#%HL_M/^ZSnF*Df:@/#TrFbLUISijZDrrA)(B".,07WleJt$p#25cVGE9[O;J$XR@DgqT3QF'op^%]=;s)l+Yf/L="0(^-M1Lb^#OmU%^^%dWbIeqV[GpqW(dfhf,_j^f^G<]9Nq.'G=l"Q.2f:PS/@Wu6]S4=bg-.F/r)$B+KS,ERp"kNHe@-N`'e9U03r.K1fMHtp.4CJ+,;[3+noS+D#g>NgIj'`.4dmpXD^PmR>ZHoWBR4Y[%o@%Pg%l*S@CF)q99S/?:XWL>%p@!i=g4m)pke(njORZD:%1L7r?3WJMqm"K_1bM@$RY0F/\)bsZ9n;#%:n?%C8W'WGeg\=SV4Y@rq"+IV-[#%1c()f]FH8M1IT=3gHc\#!FplWtq0"g>oGM_51F8b">Isq9s7CR)W_!KKJns3pl]&TuDI=9:CmejcmY@fcl@H;Fo[i3(DnWZlXYeu$5rcA'5^]3>$58XE9s8Mek=3d31_]=V[Ea&^JTGKiR6LHa\nZDP':0i8heDG>:s#B;Roq+BVa\\W0HpN#V1N0f]a"KI2Hai(m=1t,GPKpji;<("EAaecZ4>Inio#WP7rMn-h=.POFas/'N+uj]<]u4FjFUuH1R%$05?kP4Z[M/JM3A*h,3gOFua%-R.KbtB0Jn6ds]_?;:U3o4+!P\@_i.n:>atVTD;A^:/$7h;d6'+V`WDZisH,%FMkH<^qTpl,,seqmrr[%g*C/g"a'N`d6l,h)dK[M=Yi9_b*ih?k3!N@HW.(jQ\0#O/I'X\r+hpZ6(l(MYZdmY8o?dD:0R0U?Hbksa_VHd,!_k"YFKd,b?HIN.JVR_46C..'<\8"ra]To1_VG&17>#7EW!eJKb&kd%jW=,lk`3a&gr;4?hYDt^?JpD-]r8sJQ<;G7_='g=8PeQJS.Vu_ZZPTeAnJcEGo7LfR?cCHsHQN+(h@l4blN*8sW8ot\8&ib[]^ajnrG#Znb!NG1$7m=S^[c#9Win`"W#,s5JM4HQp^!';t1TC!C)Xm[(8NWSe'`2T=1&TJ:")^pWofMp"fVitGH52ZNcE25DlnXfFgAGgj>i4#(^GUudYcp8\u?G74Fen;7&nY:4;GAnQ5KT=`Sg;Brmk?Q$#i^L9+sLl(A95I@'7^KY?WS'fS_rG1RT2C]YGIs0o0:o(BPfV5JA4;Nip/94IZCbRfd7EFO"`b0l!nQ;b8c(56&1R0+#j6*J)e:_N^1P7C5=V_O4"M-<&+&p9LtRT<15G<;R$9g4il4roo,<5G2/k#HnPLPd5WQ@:0pNBQ`jS.;&^)IJMO\iW,7@E%22nkEX;1'*K"qnme$Y'rEXjV.N=m?6ET[tf4YKDb&G$$)=!h6ZPIo!dP-V3Kl/RJI:r-MdPAg5fj0I^;XnS]?A$7]E^`mp*!J_^UU4!)'(L_@:J'H2bQ:L=%Q-RQ"_gc.PFVf@UTAenFDp4o8:s/u6Kp43U5;m=$;CV[^[rWRD-O,RFlq"t@$\C:mb\F2)NTV"ugo<.3+=Z5m$kDm0A>TilBDtd;Z>n1))9;p<[)6=HJNWg8]/;g(*1OlpZJTHE6(6':FHGVr:OhrW`b:NbD1#,iBKErQ%6(!5uL#iS#Mrs"aWqA7=E8fOjnX.S,CfF&4\I4qbW8lBD+J(5sNs+^C%-R;""-pPDAB_][%nbR/t8,Yhn$>0;*Ur8EJe(Sp$K%Z1KhgFAVJ$ekL0t3:s7cS<%:[@$S=%uor9G4U*k$3n$cFJ/rc>D(6R'g"cc.YV4Ujh1Qs-Mf9\h<6(^A\u'"3Tj\9,lkBTDsuOjlE`6iqp49CXq.V7eC94Y5@H:rq(\;_Z0K$^[rSRDHM\;pd1I0HcM_#jo>>qHKq]G(uEP&GOA%jhjJJa-OVE`.cL^md8W%NeY^J=L?)uA>l=(DLFo>Rh3-U&UZNWmrEEp3C02?-dll9e_ZnLf0&b;;:ZlksaO7>0D\RE2mJlS>MTaHNc#qc3$O?Gq^EdRM.^IhLLX1J>,NWK2=069;[C"q8fNm31gj^RO>14=#i;h+[JJe7ql:NUcs,NQ0'h9loG_UtflTO7Z([dOU7^64'djkmkdq>ZuqRX=X3ci7>dP5aJ?n,CVW8n$\EUp_IWV]p6FL?D'sIY5muXU`MXRFB_H$+VtaiM+NaZuL&F=&b=6CiR%+dtBhTkhN5eB-RDXdjW06jQ&0gYC(BK1k9m,h3E1d)`I?[bbdj1=]If(bT>XN.Z$,./:Ci:seVp#oCOI]SnV-K\mBXLtb"o]pWPWq*)`C:a,,4f3.RfY@n)$CPW$s*X(mfDkK[X"V0YqO;C3IIYrs?@MjWY?tt@F"K*:1@q0BD>>eSj3[b^h](RC,$b_'R-5>SW[R(D87^:Ut7P;fug,6&HcI+6S743u4Ra6ZuWq_>X7pP9!@+r4U+kX=n&neaH;mX8Tj]e(mt%U\_@jHYdm4hB!qF=,/GkJ)&kFnKf_\IqB(F8O0HNqWK<(Y35*d$_Ae':?ll*ma/X.BB)2d9/HBREtFa#4$P5)0NPI`[6_2f71F,s&sIW*FSd^B7M^/r%"8Nsbk"3lh>"re.V+rf>ls;LF/]EO(Vq$R)&"I]3lY^e62sk_+e9XSMt"[[_hss2VnJXh=TsVQSWmoXl26c/!iugeWr;2"@'%gj&"'DnYhh('aJ>rT;G4RBYXNE9,Cq3k],LpC>=[EqbLL?aRL3F3;;/"=8q9qJ+qC7fUufjdnm$cbmVnZg[^GR5'_NeC49`_2Afkqlt#^[AS9=`TL%lJ\Q\!a8b=_]=:ekpinb`OP_m'd6h:;qNZ>WZd"&Bo@da@"7d^GhT%"Ff^G;2:L*H],/ttAaFhp'9-5a(=-<<%Y)PTAY+N#b8Q_R$j-;0(MP"o&N1G+C(JhSNO"'C8#sWmWMGHrLqtUmX*HU'X`H/`L?edO[*RhcKjEGMp(Uhla05A^&>Oh0NlMfZXm\%9"]tjKFpU>::^JWRs#"@PN?Xae6e'QZrWFIW\j51R&BNOjtl"ujL;C-BbX!./PhXI!!GWiLon1(=q3aQp%P^H_Y\Ppp?P5.h\Jl[:.a\Ga.8YNG,as0m7PA-oe/8uEbQK=@g\nL^rl3\,U5'q\A+`Ebgr]5(62(E>/0nZu=GEbir::#e+%8)]Gr48/S6`O0CeAWH*eS,^8ONa1+KXTuMQHm$tBPLgeZnA4MmEENd,1@43tnTdXcq!FU/ZSR)uSpjZ:>O7c`lD]2-\nq7rk1fV9Pg?hrm\"it4mq;SQTd1"^K(HAk_nbhEcV!>&^0E!A%MXS2.g[2HYZFIBT!5V]_8F"5iM_")L]2#ZHL"mrcom&s!ZAdDXl#-G+.-q].M_#ON%*fH8T$h*r(bJ1$@F30!@X-MYrsq$Y9C=B17J8GBC@`a]BTpWXHH4N[-]5>^HpH.6CD62F>SN,2k+KT!dg-09"#ULX*[7publE/GW/LI"tSNEM@(9C?Vu;QTam*Dhf+Vs7t5-hckKoYRu8@=V*Z5r5n,N2h[K8#efo^43K:gJ%LiLLOm3.IJ1rkpT*3LH*GPZJ+gTFgOo^-hOlH(QJ&7O-F`SV/'No!sQ5,326e`=,.'p#3>5t6R9]]F/#]6C3Fo2@I_]@^iQOq(?,FJIT`5*l]oQ#@`>b=+p`bK=J!0'*o(YhNe&Cg\rcoa1j6m20=#oO@)eG&*le`-XI3u4-M4U[dq6q*j?a0c_dMQ+Bgj^#\K's,jMrNUBDd`PJ4KC"-`QYc=!c$?c8+c1pe>fLKT,'e[=t0`*pqhfp+#BPUeTCGJGP?fTY@(>V#OHR'MT9d.lct.I[80J;Ym*uTUCp^X25=hFRc]KESP-he7_#\AeL!79J>[K1q)bD8:Zd/Aq"9Q;R8?"Xc*hG+Yf\!LH])bZ>*\s>k!+GG/WrC9-:.6/mU`fA'TP$?3AAhN3,`1k3P41ZWoN$7b>m/G.+BNTDI2n`%=5(u.Gh;o+VI9e^"J/_fa0lp#FJ],2Nj9T%8dA_M%o4H"cp_@!9kY[.M:J\_dj$+6n-EKWnd'uT3iOe^1l:0PpTl^\H@XLS8Acbq!X^R&4&fQPfh*i9_/U#i+Oc`ueBGk&0b1k*hpO)8):e2EXI9/?Kps&l,2])L$*q:f:]mddQl-C?_LnsHg<%_eoh+9'6^it`-j@I$a]p9Ck1mX&KkjSm#SYDtY]_cG`m#,T"&oUXRE@0d\#f3SCF[NjO)]OnRQC[;?HLUOWCXM8KcceR0$b51P>IPm=!k^Cq35J-Yk05C,](q2*0$Yl0Eh`%a,R>P9*?uC4Z!\Q\N\+oqWW[g07W#^-:OD5i)qFNiQtI9qpj;4CS'3p`^Y9g-)K_"W4Pi.GP%m_oUW+i&hJ2I\`>+[XfcRX-$EWMs*T<%rTf9Zh#H,\!#=))<&/[[T>,7N-t5P*[:4eBleg^uDgY;No)9l[$_DYg2a(N^JSW:%k9dBW@cEP@%dCV&T^Ud,'4T:sYKOER:V3L:2[A3SOIA):j!q#AT>/dh%pf/t?r$/.2`O\;:jM?5/%]8+Q#gN!-0578fsEOKnsNu@$;%"p&=_4Xf?Ua'St"!8f4kguhToGDGV2)L7\DQ;A2@UV68^16Z(H+nG)i$Z:.Z_b^j(r4Dk$`K*1XS&)Q2c[WZWqRi:]K[4_4*+Q&Jq`]JmU?;c2YAV1kGM'8S0;VH]h=/E,MorNdIV8B.+#hCg"@[')i%QP'=Y&nWlr14]p:iWVVE?fALD?N4hJ6n14jo]i>>UlDb[dejpo/Cu!Hd(]Gd;S062C9WG@HTa.I-K_8Gm+[=6;E%-SpYhZ^=r#PK)>'bgjZTEqC+'q3rI_G:%P>5lT5XJQ'@i,1X@Su]oTe8]^Nk`eg+>al-&C7o*#q-/%cTGlDc^"YZd1W5J$!B7DKJF,s5il--n2C[qD]c)P;TMk]`/Of1B$Y'p$c;`AMogn$dsd/5[;\GcZVkYrp/WDu#R-0;/>hUM/o=U=ND3>P6S]-QnSc,=#&"JQ`JIureoh5>44F-0VnW(Sg+tGh#RogN]*8%dE(-UZ^GnGZ+G++923%#tl_>O^$,GHVIc=S)4\O7>eS2q>;jTk79?ZrS.#'"V3iflbU$9l'Hnr`5)g"=dqZiiKP:!X8Q\=fDg*"NW1M6s"2i0p%66"QVq(\ru4`R2uB3+EH=^0kICK7Ynt4ae)H<;F>'Gj=QAG:TiBqO+L@$O-?7T:XG;c+nO,S*l'u5#5>W`9sK>/9u*YR2:YqmKi4!&"WAjVd/1cSo3h-KlmRrSoErd%C-@3qM%&S9<6>&rhJlJoj=.e9VjRSrA.co.7Ajro-Wt1b25,(s6^fZY)jh)G+\e>bs-R/=JT/YC-6idCX4rFW1DpPQ"l0*-"j`Lljo\2<\nB@Za0V9a&UrF"CUnP=VEm/_:,)RAn89Sk&5`K#asCkF_@5PERlZ?u*b7?8L*eT)7kU0.n0/n:/3h/gS*VKg!f&1p6efY;.m3Ob97s"4$_mQX=>>PrRuZi8+e>K:m,#M8MJLQ,eb*8gSTYA+T:s2MSgfg?Ve`f)BAKlS(u[MIleS"dX9.Hi;0=4RHYeqk&&fqf(([6,Q3rId5r,=4su<@(X_<\b>7YmXPUn7D!a?;J1]lX\TrJ;J'gKOAS]h9>-`OQC1i5Ko*-Se"+qNV:lf!p#EnCF%IZ=A!_\#3<.c^jSo.5,2GSbI/Dguc!#J=OSF%RC92nF--h"rm_ILCjki-dG!lqe`7I+-YBVug45N)iOO.8#-Vm"b]0rJaKD5ulr;;KS;Fr"H0XC-1O7IZ5;8'X<.FZ38b3q.ajLX16Ykqu.i$?ZH)Xf"Wq$!ipGrB8iI0s3BX?'/fR+9`ERjs)0Aonhc-j?SFFJ)PZK!InnM.OB94mqd`@2#h;YhVH(`?/ObCHEj0u#=>nhd>\!HR8U0A^TPoOg):Z[/ael.gnrqUg#Z2>cXt+<5jWRRD9SkMQ'=[5C/f\5T5o#^=#oq4TD45ps;hk5LKkeb->lLtmqVV1@^Erf9POi1FJ:HTbS33W2C\#&Xiu?YL9H=7kDHJl/p-%LH&[=X7^X"rTk;e=XQ8nl_]$g1gs5r/oDqqq8TjUuB^X\]mnZe:h5mW=2Q9Dh&iQI!VQ`A6.B#!adq!#gHY)ZT$lU,P)/TW\9\E)%S&"4=0GC.((BE7Ugr#6K.JmL&/-H2"kIh$.Sp\t_b.WkK1g:Cqj3W99)\PsP's-?dSnultqM;GJtHGboE%H_#i7M;N%F9Q9#>a]Ll+1gOS,sSAsRAlohK4(Z.I00&CjEX]*NU2V_`3IlQYFrYGd\^G'!'d)F^SWtDJ]?eb(*+hdo"[,Kp$,MT!=^29`h\n%&3?MWCO3VVt?eVgk#BV'X!&\B2m9S$^38p>BR:1\b8iX(MaNeKi[OB(GiiSX>l\M-5@g.;fjoUU%%?1h0+Y\le2inr-rhc;p^YCq*pE/05&5ur@YHr6:Q\bP.SOk2u('Rt_SErIXdN%^^d5%M1ub)[S2r'0>\T,tQ8Z0`$ihlQ83EVKL%Us!gj;.e+lkANVM_[:h%?2okjQnHYCqi:gY%\r\uSd;8eh-dV$jH2PP$j#%fXdmdUqWD5-ZiPYso?W"JT`14U@iSPi.9>":Xpb'73H392oBt]&K-fgT;TYK!_%2o-IMY3:IGDeB2KA9+I*VU0ft#:6[P)/nZ$ti'!Wl+m$2ih(ANq-Lm-g6GfidFXph$tF&W>X,[2-2&R=>^uIlWS4U1T/"^G!P%Q^Kf)d^f?=.d,\T(R9+BDs&8e$Z7$&6UK(*qBL>!)3P+aeR*_!\$)I()O.hU_8PRlpgY"GY^#H.qlI^E)r-Z0qP]Lfqu;5u-Un6L4"0T@N?,WJFOKosAkf*^&bkcQ%"7??f@+>6Q<[q/UUReD+3f3H=/Vn9h6^k,fm^q6taA"mESTRA4Vn4kDd:Pml-OTt"^867\<7X0SHhahMkt>+.T;'#c%jOo?4<`0/8=`=<>^)>*J_)l5'6K]ScA.g)aF4k;;],G>R=F!?V&a-@AE^\W"L7PMW[4I,1%->Kr>6JF\=`[m/bQg<[RXOWdj'r@l6$rjFg[a2HU$^\GtasGbY9j,d,2ug>CuW?NS6O&Ue"Mp$+S&V)J30*RT/Hg`geYV@dk0lk/-hDC51na;/5+"ZI,g2KUl(1&lDMol_F,6kR3j43%]@;N0!9@_6i6DCoWIs,%\W+g6AR[s[aWT[hJVc9Kc@"OFk5tbG2&>PYL,SQ%D1_J(]s`OoCffffAA`m]&^6KLqXbi>Wl1dhgYIYe,$69^2K,\B.B.3[bGPq2hTl^O%S$Y@I1l$SV"qmfEPEe_'\=.E]0>op6e;Emb7QjM`s7H@M,R/Eus6QdNf.Y?4)]g`$Df7dZ:@ECE^bcZ?(arbWY(*=LaamS%r[f25nml$\J1@!#D@N8Kf@)2b<8S-OC>\L&J(2n:51Y"d\=kf^nA]M!k9h-]M>>kgU].ZEZC28u4oQ;Q55/8IV,RD36--H0B*'nj*qY$QD^?u8mX<(Po?cd[4"<22OZ\!Pi+If9^MhE.EN\;h5(qE(Tul]g7ETX[=`>WmC1t5q&FY:PF&W8hk;]X&'s,=dA_1Ks#Rf`T7TjrMlAB]Y.fmfGQ/IT\RO_h(H78meILmW?@_Pk_T)08?ILi.%52^G5BGk=KR(u;l'_LBR_%oc;qL3emSh^*?@7i=*l1$egr2:aE53WGVinfEdo":0h=6Tp44j$XmW/*.8]r3:F,U2J$l/g1:g?;]S/bI1#][9"VJWN7l^1&chl$[LDGA5H;;?Z.ReW3N<6Q4(s(W;\cR6!d56Cfnf7+%b5mtOmAmA^c@;8\C48!#;Ypp0Jn,J*.;q&t$q]MJ[L"AC)pAQ9P=:HWY`,oXsRoV*rkO,s>csE5@q_Y;ith7cQ;GIU+!'*kLPjt^p!hY0!"=c4IqXJ.*mAQY?^h-fjSbYs/%V5XF'niW;PCK:,92c3FMR"f+-o9'/RtHk23m.$PK[YG(TKJs8R"E3WJ_?[gli3f/7b7)bR4Bs.2.pr]U"E@3Znrq'Dm[,l\W3k>fs/Z[_$D]`BnI%6B6.:XV4CaWi%U\7*u6=*5T""o#C4)pZ!-N]JPq4b8+IdV:fn=T@0`FjIe*D12-\7!O'LNaf1`1\/+eVf>?3s*f@Tb4q,*>r(p$%fa!*mM=2^abOD2:*"?99Ec&9AO&lC/>kR!X8-Ci*3W^Nn,M4g/p9[@Z/F-XIuY3lmbnWQ)rjg*s0D;L/T.#_nd/7Sg%^t/!mCP[mJ8=n]:u6fY0p4TDcTfK"7WLqXC5^&,SDeagp7JMlXn67C6rGl7t0Q(f+(=?1u`jMX@MpAa?Ou24K8C?DFr?l^ph(r#aYL_r%Vsg)g89I\6A"S.c/s3_6MP'a8XH-D?)LdR[.678^u)(6F]+:3uBjL>K2/+@Qj'hFkYeml_EY=a=$NI_2,`ef82DFi(hYQd>KgF7)5=Y;Oq%A'Qglg2!ltnF*#.I@>Z]=*+?MBoa`(6E&\AHN(mm]_:'0hnnlb#@@ca/*l*I#24[j?OJd>m81Sph#H2AA09g8^&On9S_'Ej].jsbTV,jbOE+F+^`2t.3t@[mBt)KJkTOr(G&n$?A=LQ`(r_]LG,EOhE".b3.$%r'o\N%kXWXi%bi@@J%F8'Z9K1._^r'f&l+H%6(&`AcD)$n'R=FX9rXC%&`WXj326"of'7_RF:ZV&YHBRildt^N7/;o3V_$G(U;)AjbV995b2"Fbdhq15*Y/;#`/(!2st76YC;]Mq4F]!%@gP_,bf_>,FAk_p`mZIH\m,L%!1p4OslAG]G)MII7P>(pROd6]lOq[\V!u%?)G5D.=IKqKGr);&#l'X=\#Z+OsERruH0+F3NJC!uTCrRe(af]^J\Iu]@KL6plmrC?P5k6,X8Y.Lg=1$eXJSuE)emqEe!Ac;8*n6h`T.Mt=8Mo59MICW?Nec)M*mu.eRdH)cenT)re&*Jo\l\U]ZYnXU:.7AgfSN>@()^m[enJk_U8mQ+#(>0#u37A8"l3rArj-E30S8b:^hne]02;@PK"f)q/GPAr"5KEHC,6g70SF^[(rH3FKSs?bHhgm@bcMu`"i%)^F#.%cenkf+JP8Pi,Z6;tt>Y,HY#7MS1F6hoKO4"S:Tr0[(nJf@Tg.Y!>7.U4VBS8gW9UmdFt^Z0,/mHJuTm&fCHGr8kNqLCO`Y16[)KgFImeC7Bb_pH(l3^89HH2eK+O&/3o-ZneV:>^^TfaJnNiO#T1+0c+\N>d6VqeoGq.%`_-d)08k^F1G2rJ\7&FOf9XA/MF]?gM#507A,Fo;\HC1^A<80n!0De^a.l(0A?4)8IR_]G^.*OkM=g%`NfH]^7iJ*&oC2UX3[`Cmu_4cl_52\NT[=[2JFq@'5"D=k2O$:,83..qMjH60M2D8`AA?bPcZJN!("`P3cUs,rP_:BgcIBs@MNn,ElWIgL8)W+P7OiI_?-nKOab0Xc+2'c$[-6OfrrbBplaYQ(FTf04KX"h0e%d>#-(+chjXE[;]PhT_RS-NZqu7t:lDI!4.t=P1W=@.n>"`WN,VW2)$2hi`K$(#TRY(\R56Zi4+j75GDoSD;i;71u6#mV#S3R^hfNil!'VN8FRRift66I.u2VHPXQrRbiO)pfDJr?j@m3*KugS]^PW\32QOf7/GHpgZN285;0XT(qFYfC;;H2o$#iLhc3MZB/\G#Y,T=&gOST7,&$lcb8fMC;`n8CP"n+2"fq5Ha^FSOH#O>hh1)kYsdN-,jjo2tYAcLM]Tgm\Y'*WFk,p_SNUs#,U4s6_)lW1Y%eGlIY_[2CF<^ThfSC?PM>HJ`rhS&RA.fK,criH^VYsb+\rJU>Ml^rIs\5hM`hoNR3GlT;2c2=on>FIV`obmgj8._)d7Q*)?gZ`kTT1hK+'lN$[qQ%R")W9MDk"%t<[f0k;[1i=M'VOKDIikZbQ]d#mI[]*TT-a$.oomS=:C.%r'L@'Gr+cLMRD!#R!8V#MC$dujc'dmhAs=bZb9>rF47.oPWt"(*`;<'M^LaQ#g`k"08'8NQ+"VfjA9:L[p-(IQ&+0pS[o_L.R<9n.`E&LY7YD$V`U=O7C-2ePMY6H3*Bs2HEOKju*F"FEM>THpjMbW3\@:UEDa)U+MW5$doH6BnVZl&ceD9C\so?ZKBO&s&,H^Nq%$orusQjV:gs]58X!2Vp4pk;2_UUqGRK5jK5rk\aVA#ZW0[6C5WL_J#c$C^]*N(HMphn59+G:gKBJ*;`\es=af3!Zt2auF3V4Khj[p=d?3ES-_u*9(J)>+ktBq%CdVY%dW5:dc+d$(K7TAfXe^pNWO>FeIs[f,k4Y.BgM5^In+OlXEP]#ga2h@j4gLQ68ckC8i9rf\t"_iYs^rO^52_(nGni$(W(VFpgsmiV0jXa1,3>Q2%XcOOL\W:^)8$L.C_i89K+COq(a>9CE6[Uf:64((&H4(`>Yr]S`>e4U$NYg*]J9:%!>P[AdibcO>CkI*%J(bN;?5j[u@?T8"_esO\k^GI\O@bP)rneoJJ-hM+!Opu]YC\c&.Q/D:8I38=a?e_7L18OSEG5oZ-4TBc_J"1H]JX263N0Q3l"\ZT&qS*74C0eINC.S9W,LKN\=k:??h2K<8N!;484=Gq*\:m4iImU;U'.bcN:T5Ug3#$F:sHiY3GC\)V2Q9T]8Z:?sJjlT52Y"/%Ugb[.B'CBMW*gsCpZ*E[$p,]nDs/ImTm-OpHfn,VFNR.Xu+:`bQ*+:+3iVM!2V<3k<"Zg=k2.?M8-h?^+J[]c6.VShkU0S_\q#.r;*RI2H?2p@?@1E,55o0MXRo,g/iSP[gbd_r39-iXUp&8%FX;'J=]NM)dC5CT5^%Db>l"jWTkjec[Dhs>3MrfIL\?[9gbJ*bmLZorhmS@Por##_%reeNgKm9H\nCK2`Ra;hH:-X&^^P`cm=/ZYjpn/Bdt8V60f!ZWPolRHrEqd7n"+-Fuf_Y+Jps+M2'-C><`s/T;\1cp!5KU\gA@Ws43ZjRlY=t.Hn#,rOfb%>'/te/\MtV5&JOXn1M@Qaj;?U#>[!re/;T--GEX><;f)T@L-13D\LtaQ>1BRNqiY[,hits%B^kRCT1oOgG(QU6e)+6=m9p5YTcX?Hdt9eU0$._Ij[6UUiRCDR"i7[MLYkPXXLf$q=TOBDL7UY-@+*c!1!`turOH->jEk+.Zq5TYO?`r:9e-A2*V(POAg\Jcfb09>IqgYB/m/G>L^REQ=#eiuNb9^sTSPVZg4ct*u@b,WMU.9EM1ShdHk+$?#d\0*q`ej>N:Y0Ar:@)Zq\Mpu1FIuXC"76)9c97H%H4bg#amR@DbLPN4up@%GtKLK3B"&;Dm1I2s+g>%7)VPU;[U^_*&qfqXA."ZSL!c];N0D5%\:<_GHnj%Y<$alPELl58lfT5',E_bioKq>h`+91O:,k(RU%7TOH0J6,7=lbG$=;k[/eMG:lOBQ-+F:TdkLW#4V(uE"onC*l=*s2&'b:\ZA$GZ`9V5;^tm2r76B4l4kAUJq1R!Q9_l;#g+K`p#==pYW4@YGu6]SKn4Wq[MUAH.g)Yrn/V&kZ0qUe\UbSL&)"/q_T'"[(/hFVmR`W%("8%\Tpq7_BUHt^\]habjV#V["=F).BDd;?W:*<1J^1]M9k3G5Kar5B?[nIkJGXF9TFNMeG>G>@f`'oE+LkG:h/Y6`5s"\Ha'?n3*)'keL=Rokm:bBu;6>US-Z%Q*slLL_[2m4k0\$c+49;g.;/%XdMFUXdDo'`f/+&;&ZG#WTIioJ((L,8,S4&>_D*S"eerES\2m/=fg#Fr%G9WI1Ol`@kdBCRN7f_mb1l85sfY4mEEltKsVLOU*ErU]mk0m.KsXM3?MIjr%bfgRhTli%j)&B"8dXYR6$QJsLK\ui_>qSE_jZ_?I^gJKXsmh`b+^I,j0=RkkX.ppT9E-n2GHmg)BmX.H5Y:eW$_Y`J5-cIhQo;n)Q?`2Lh1ebpur+b\&,SGn<&+H6F7@_:W;qH5Bj.erJ5a/'D],OGf2VojD)mRQku$O=$4VEkL,>tC1Os0J^E2`NUA@hcfMb+^;e7.ijD]0b@TNT4+f,FF9^T'LfF@Vb1>/uH_f_PN];=+KLHFBA?!bejth)=1C$Z]chqQ(,lZW[e>3foIW,4NY>igp(]P;DY0T(GIsKVBk74,p-.jid^PN[kaM4rtE7VJoXH!h[G5jLh6&"KOUHb4A+0j5$OT9p9s.l?@mQo00[Olb'aQ#[[Q_s^/jge-AJ),C>DZ#E(]0%P[j=aO=IIu7=bH0AYG^3iils&@kpGd$3a^;T:-Z.*++KOcV.lo>lYaVp,687sdMePfPno#MC<5+*IR>?]=.8`rG2]&pX%#r,ZlhQ*Tn_4$BA'4UK&$)air6))&DZ@t"#0aikI/DUUU#u"`"pFprJ&u));B2;n.UeqS]b."Ua3U\QeX,)]0,cRFpj]bMn>Ulb)(-qO*X_T\Zi$%\n)h3h99*;-k&5bF,G4pL'nJm9FL1W:E=38C0B=p+p#?:IZ*s6.3\9dBor@Bnkc`d,-OFe-Ln<18UDKPGg"fD_A+-;:&FsL[n?bn5B;q&V5KLOeip;HY_)lt6#s,Q@0Sj$QQ\r]YVr%l`OB;Xtm8&b=;SlL:d[K:aX!:(1BUqbJu*&9R'l$m\&Mg6sB"T"8A._?U^3"p%^!q57PJDa"`1KJX+3?A>K"qOM)6#'SruYV1uk'[j*qU*Q/EZS>n0*$L;QLUcGpkE_aHI'3&tq@MLJ3%+362:=B3A8(;4m\uOJ'r6$N]Zk__")[5[Vgc'u\]LOl9>XjUn)AlHQTaiZNs==W+928JO3HDoej&>):7Sr\B0ZEgJ[Y1FMuPZ/I)<%#Pc6G<`sE,+>'9!NVW-Y8)eD)9:#0dZ-$Pr.EV[_k>]N@1IspD;o#Sf3_;bLmqjjLsI)eP'X++dqdM(OdAG^iXK;(;IlV7qQ[fnU5Jfo;7PX1;r<_qi"`:Flajid-]pQ\O_!>hQNH!0(%)rBCYuY#7[TX[>rK$q4g@)ZdSF@.smW6V&T%(O[YMP^G__SZ.+'u[m=eO_q_#NHQ2t_"S-JTh/;9L\+<:/Qknnm>k2ggJ&=.-6crhMBq'r^D%gOsP;&mc):uSe\R*.[?bSed\`;#Nq91]lbYt04``Tr4ksM)U8HYh'6F$+PR8Ikc7/'A0TM0Za9euts(d0T,D4M%I$!Qt!pG0,Q^YSUUXSI(V&DmF+g>N'5A@0D!6fHq4HLq*!=247QJ7$.^ZiC$B_3bs9Bc3.s-TQrV>4mN?$s:WTr:i5>S['TD^WKbBB'S(jYP`..mHjW92*1uCLj`(1[>ph1*[.XEL2ZB#Q),XQ%k`9*.REY$A@D6Pj0B\)g(sUiJmZR%2IoW8!+(lhZkC7sUr*/<:8,M-#,I[_qG!"fKmu/YA.uFL!fb\OMmf./\%71Gn@/g/3Y,4@hNAm!O[r_P>:G8-4U/e4YS<6$`_,nlbc,(YH4RXVp8FKa]kL'0Z+2=DI0OtEUakZ?D[BRj*cDNB)lHCcLSBEr&G51g*o_N35#oVS!2'J).Cc_#lkdp4lh0uX.3Em?*7-gINj:K'FriN(4iZonI2naI3'=;!#qZkTXWi:J.P1ZTgSb:<9L\^,3RH.Xup\lhN)blIV$/tF)7[/YGTij1GfpeV+\G1X93Xm<<@JpY]*'A'_KhBT)77b0AUM5hl+Zn,C`S(269=\!f):OXp7GH(4g2g42,3^?`KRqq$2Z2p3ZE6cLa.igHDL[%76pn)'`kF2KVVV_s*`L##O>?[^+JDc4>]*sSp?\N'%IE5;*>AdEUkcPHFo&k1E5necVejE9RmGfXY=a37="r[mHn]Zlt<]#8H@43CO]p^:ssZ9_Z-eq=`EEhYe3F[']JjFpb!MsWTd3qrJZojZik\HM5Ho<2V,/DK7)Zrk9>I/`HmqbFf(UY2=s[s%HbUN#L=EIWancWKo1Lp4?94b)Ni[`a^f2a&,RT*/"Yr+H"ooReDGh`La_;OW*ILkc:(VuFXT#/[?`1SPKH?Ni\2(!0Yme:N[OG*7??*0$\CIsFa)dn3HjHfo2u[uB)#.*!?mGdftfkBiea:L*NWGVEL4C2#ETjU8VBheAs?&:t<=5h#FD.nn8'uMk(@:rbnGKu_CA-hnqqL!5[Ve,*\*_1*G)mU+'jpYQ^$*1#Ilu)$rq+7G:;5Z?c79/p5%_WmCO=sfQ@A#2*R+]q(EWP(\%noNk+/@C3q&FLVZR*5DtNuQ9EGFfh(^;*KarPHM6j]g[&CF>T3oBh%9>.23Y1a[c)INe>N%h2nfFJM\V@3ZIX$Yh,lnkdrc7k3M)$)dk881\7K$6@r_G^"^>n++uGJ7^PA4G>T3%1K/oZ$r60"LIKX@0fK.@Yf)'AbqD@Y*8e\?-_nLUs,#VlIWk_=j/5T,O7P#7%m?MUt(JTnU5;JbT1&D#RoaF"$d4j8.q:RK%9DJkK-ok?n8cpOLtCj,Gu6DRls"YHF'7"=jm"fikoMhRq_H[K#BYDgl-VS\'hc?o,1&]5)>7AjG_tUAk%L$Wl1f-;0HP=lABnIphQqTDdr'D_Ae92e+;g35,?nX1PM0oE&XM^IOlDN@o2oQRkc]%/$TcdFh=0jN_N>3H&HCM/*Js9?%F6O",;fCJ.\mZ1kbndFg=>kTV#h4Dj,;p%[rS>k[F#Y5XcbXa+CUM/+LZ^&.H`':4+(\bjrriu99f0BLUPh.)de+LRo9dct_F(QV_gh0IA3[nR!Snka_nB>6>e>8Y^.h`oa(Rd\8Vj`KT]B4#L#IgCAoP=Ok7?bXG6lcG"ZobZ;2Z5(tUDi^3,?isY7mse?h^ID1if[k/O&aNej-'QPapOD>47/?TE'\B`fns5>$5MlDtM69OZRUU$`d>LbZmii1WHdD#g_H:o6o=)GY7!V/?9e]NT"Z)9TLlb$I9acLD-^M4ZWL=3$c&5h8E'uqrp.MQ>_7oITpt+*ZG!td1s"[u:aM69s^Hq5dGN+315'chi#QEN'SbMU*n$Jp+"k*#!-SN2Pi/=dfs81EfT6F;&i=Gj5g$8&(Hf1s4YP[%;H^5>L"I7omH-=Yh\G!*.I(6]_([KtAIh//u-&6K32WVmlo#PdeVf-^M\S)hh.T\nhbN!$jSsgGrqTEF(/8a,4e>;2/M'XHc9^\"]$V-b/D55.s+dd(%#ar(bW3:SCAI.GVKI%._[l&jlEg]_;e3(uA<3%U;T36Fg?1*#5@0^SHi^dB_T,I>\Tn(7D#5oU*o4D*j!;18Q:>uJYAXU^)(YiU*"9&aMNYoHSr1XF[&+.g7lS&&4_9u$LrWV3CUh[f^+_.u;8H):pN.L6j^Ib..q`f]X+=Z7?8*S'^WL'_?p6KVg0]C_3$TKoC[rpIRDjh%e7bLpNXaYpU5BZYZ`KNfT))BmeS0r_>5K(%MtoiQiW#@I*ZW,XkI9s[Dr/ujcJ2CenX+S!F'C&u+?_p]ZFc$#Q)LEFGGlR=R,P1a;?j-#SA0KmZ(JPJ-JKau]%pM`l%Z8NcaW@&mIGTnS@g*mKY0l^sIodr&7hbFE,37GhbsOGC)jke%kpJei^D)[X\pkA>_EKVCY11q%4TPQ--lkJ$):`4$7Baj\j)FjQBGJU`Hcq`f"?p0Xg<%+Co\Q;5!WSpH;'R8L&G'T:gL:KdKqZkpu-'O;r<9kT14@WQ:!]O5FsUKsYpP/DgNR#tj:P6(E>F(UDck'E>g#*;+IlVtTj`3c*=ukWD=qQ'Ul:4+-7>;S4')lZJ#iI]^qU)26`GRYpE+\YgL6g"5CXC"VqOaYgPq7([&H"AI'`k8a*%gk,\&u=8]&&iml[#I]`"/:LSL=qM^l,Wr7k#]rL_[Gg>G3qq>-GDIG8cR!2cZ:jHMMT]KG*\V"to&[q]d[M//ukI+5dOL3$2BBDZ&)]'Ag6-`h(T?mlMAHEDt_5'77/il]-n;6eI+@5G>K_DW_cqqa8EqlGe'R4tqq<2'*J+m@!f^(b],bI>-BUH`p-Z2%^@i1UP&&8#j+iP">B5W4d)U$odr)eN(8buBHd7NEC!(:Qt?n`]rcf1L!NUfm+ge09Nm?9+E;cjk1o:cCjEi8e5n:=?fChI!>:6QAO9WBc6`WYMmcgr#E!,Uf)G;G`o'9CH/0JSn"'^>))c;gh@rtGS3dI!'gC\Rlk/sM1)9/Fse92Q4enL/8V243VS0;>I+C"4iRFuHdl2GT9EYguE_NAnQr7aU/%1$j<@fPVF6bE@+"E`56\,>W3"0O/(o=Mc]r;7#AMEQtb"'(*FXqMSp^@;!V$uj7er86E2ri\=h\4KaqjZ1G6A!]@NfRT;rjo:q0n]Ts)XF&R?\D;&/IZc2l'FQkU4,?U%Wdj^=(HV6XSu44&BCO@^fQ_3-]\e`WFmD-j0Mc(t:IaouCMM9e&b9#O+[,n!P4:-<-kpn)6Irq:@en!R?kEJ(%Pl"5.S_7`lQ((Ej*`)2ZIk+.4LGPWKBu5b3&Wl,3h+q07[WPqTR5e+!l)67`];X:r-OR,Qg3RP,E@Z)K'l$:m.$DuJD(cr[_6"F/p7V4oc@XIPFo#H+Z!=D*+Ye6'?DfHKYil+ZBMAeI/6LN=$Y.9F_=nHQ>;:uQeSZ-%g+?$TB:4J>)!fegSeCCfi8=-E%djXC[6Bb_r4u1cjK'k>gaXJ]fQ5G!8"?l\)G[^+>%d^iiSSrp`T+ruS9S)tm<^d$/C.f:S[#_V2h,8K)6b.rGGunPp-r%/VX_/lfa9J__kAtKFP>,hY7S;_eWuGT\Go%]QClD)nCIEnpYVqD^N,O(15`dZqbNZH&"Bfoale+-d+7c;5Q1EH5'G&M#G&T13O7;S,1fEcIq*$H!FqIeqitB8o[B"jq0ci>eR8j?=T;qIc:"2eb$J^OG`Ph-Tln.$1+(prcsO;eh,S7rEm+e#.(0FX4tr!PPqFd(fX#*YY.u/XXl%5We'\kZ`io>mNdmU;9[nfr2H%=rP#i@qbCDfmaG8*ESAibO'T]Hh.Rr-M4e+($Et8+s>KgbZGYn1T:eqtIi)_e&cWHu?nDo=fUq7B=20XT*Y)Hh`Brqq&Y8B6sOLIp]oJ^0DNHZ1be!/spkQc$>A&B_dWHhL,6hT7:J32m^&aF1^V-1Hp4]cK9c3rlb9s0;ImPc_Je"Ap0OtllP%,D\0D;UJBbkosiJl]`X?*"PETc4?k43k>b/6*_BtD52RTGNE^3mu(UZ6DtQ+:u0*6h-@'8G?j4dJPZFn$Jtm\+oFR'ujJ4B.oWm,=J+3fimF*>6DFj\'Q1ce6,]LQs31*OTSQ`HUBkc-[re060*DMG6+nCjA4JcDll:\dqDc@9A9VThjJQ6(;@Zq#Z0>DdfejDM'tbCIO]&G]Pc-T*P(ogR(!0#E4\3`KV].6lu&WoglmbBmod*\)H_q"Kf;ZO@j*0g@X0bi*S5\nfXNhc7Srej`mkR#lRZGrNt'rfSL:g(F*3J[,QWqWq3ES+][!cG?>D@Da50S?4Fao%&N*lKZBBjqYIcp`1rgB8KW:FLJa0c6[o%:eptaCN?Qfd*W?eo);a,ZAEBA7HNrZ(qY.1C^Ad6UG;SF;`tkD]B'lF!mX'"OCR+oQrfn"h>oDtchJ-opfB8u^gJ5qppo9l*]TL^hCWoP8aY1uNHbYDQjCRtS,/&@?iT!,^.!<7p3mmo_omYTHepVnfRglL,*T@pFnr.;a9Ie2-.BhstBdsgp)R$p:][1`Y2ju,I]-4FC3dfN0R2_d_p-tW+2/Fj0kD`+mT:m0.a4ll/bOs3/EBO6neeB89WqZO^.^&`_$2DNBBsHf-\%jQ_3;7h"lV<*#&_HI$I+5a*luVSk]1Jtp0bA6_b$A)nL$V,T/Vf=3c,@"_RPLuG$(+pJb7.h;rSk.V:Z'QPIK*\frKYLO5_nI;+lE=]Bn;qO+[1D*J1#=tht&b`1Od:`pUrE12W(chDn^Ag"0W\*@3n#a,aD4JmQNC=@p[(P?\n4'^]$#BO9]la^'lMnmfAX(9b";0[4=2kFY@#E^Ej.h;A.a##E?n_B5`7eW/k9NeIEbGD&rAMS'/EI#tD/t3kQfPO:p:eh>HXn:L3pDnH+$(,4kUhfB3`Y>s2uPZW(G[fg`mJ)LM!L>WQ_@oNWp[>P-i;j&UlSNaad!gN`pHHrqfIIJ>'QZ?ifLj1IESM:aYS$Too_F4M6+hR`\HoV-J;h0"L&]kZ'd00Y"khn#rI^EE10.]:%FkK4'r#D_]o#2hn`r_*7(2XJRZ_6u\mHfo5.X\.Ehqd2[VM;NC!O)*Xf>Q*88Q[ak2;XpAO&s,-/0i-=0BH6bhRHnrXdu%@"uHsr(uh]QL>mu]A'.FUpIN-i5`#2[+TZah^^p;ootMT)]%bI3<+q([dsQGeWkc7>dqnkJ,\d,S%eUGc[R[R?*N\=3.`(?d.a50hGc$GUA3sWJ#<8YWeI+>;j$4dEX)DocePt`W'rF$PQ_e]o'Nn6J)rc`;B\3B)K)YE69S)tY[b]LViR3p($uc3db6C_gZV'No)^0obJdtIH]mQjdY%bJVYWC49-#pgeZ"-iOq@JMqUi4RW,aBY9Dn7QhUu+>R(Dick;E?a6#5=tRE&Q]pMTZ+l:Tu:s/MKMi.V%VQ((#Fa;8hLF<<;&Kt2+n0FEjEe?1/Nm()>Lc9+R_bVn!ci*UDo[_h+>'3<.2(lZ/2$bYfSntbIoT>%_T'=Js'GtX^M9n7MgG'5YfQlN8mn77A'1XEAKK7-^V1*nkq&kZf&G*,J;9M?!^(0q*6'gA(V'L1bJ/na[f632mE:^.$ia*MbXL5ur2L']+.UqOkGi1(du&X['ICI10m_5]Qf#]aMK\B]4dM_nS";]Pk*AKljLf6\ED.3]HC?d5fhQ##jqT*KlGf0!UnMpdAAs(o'_2X2`/Yg3.:bs*<"B#oW%pP](NrOJ9O[]>a<6?7nXea/33aLUc1P2VbBqW#Li??Po4F[,iXi:pA[7bQ8EHi0lu$h![h]Y#8F92=7[YE*g5&Tq`'I."r!IPncT!?;a[iQf8K[Fg/_`AYffD+A6]N]2K7>M9!6F0]L0%q!f:4E9H8<2ABJ3X@-R4,^7?Y^WbU7ns#E#^45#5cDF01R3?fEC%K:9i%m;d=o!r">^]j`77LLWDh=H3\UJR.)KEo_W7^,*URH[(;-'*D]!D=+YR1I9(e\!e\1PAnW65u5OKeabE;:CY/V8*;B;+o3pehEB@\N+c=FYJ]FiqIb?ZJq&rdrm^a4AW%(d'5LD;R'^fu#h#j22/>BPna+MT$Fr*b5@!8ni?eM\P$E?^t#;&n\ubj_=DunkbrC1@H<$HK0q^"aXA4cF`B3B7<%kpEg;8Sqis9l1e%\21-bW@qX`SRkZZi%'G7k,fG10qHq3ulP0Sl\A!&jtjnL]pj5^r9*-(]&@DO`'.sp<2P2X%\53Y_tEh4Euk#F&*6>3[If_WJ;ep["d?[M(MWXXKK*u6SMO40DdnCb"i.Q56ai/PK(5P=?(MeRjLIJ4a=AHOr;nA,;YZdSZC1H'HcMc@^__@,3M\B-6BX'QCmH2f"T4#Nt*J#BAo@`0]g@j,QYs6\5lCF7p<39XV=^qtZfu/q-/TSXh?Y!V9"H23d]q[%TW$M!hVHc7.:NZ:]u8ci1r+iD(Q+joX:Xj6]&X7c*%r2pqgYYNIU3L_I>5E6fkIe1^V-a8msc);?Rn%k;^h85T"Y_1?aoic7t13EGMjVbpYTn:B!p[?G?ibQ/t<6Qg#OaiecME;!\p(YPrieHGEB%?K+-Ap*RYm?_`!qHh]jE2JH/sCa0`qj=gQJ__$21#:eDt1>`mO@l*5PemAjXGMIiU`g$5**d.5]0CMX7CQ7025[Lpd`WEH*8sq:0c0mrOR_@I)rs!@H7W]";CTOLlH#:(O_0Y4=mjs,&,hptYgf*l,LVZ6Iaf;^.#7EdpDC;WqId!Yin7\O5/:5J^/aS/rV\*m3pHRC6Pmd:?iT_)%#f[/0O,K57[U[g?EimOeTp,>Q`.7"4?n>mbOpKV4"r"'WTicdkoJ;ZDK0l@rR7Mp\atpIRs,gZW)7K.kB[K5YFZ!d4`8eikMMe"l.KVrgW?%6Pkj@b=&i^kLRkEF*^AVi?ThfFg>Uo<(3t5ra]_G5J?VtBp?jXcNr?nU',Eg"QgKL*@9Z/JGt=-)*K"oPkEjWZ@mBrK?O`D3Ti(X;&okEl^PQa30A\m6j0SE[rXPi5d9^D5)&o22ktB"@>uagKZLQmLh,LfBIcbq]oUTM0lLe5mjP/X%.sjD17X4rb3u86h=5?r?jdrd=LpO9&fD]*Up6Q26Xca>Jag]!OPG:<^!l;+=Dq@jE:;5f7q?7YjWd(P"o1SW_H2hXB[%5MI4#L*+F6oMn_()]rd%T'p:qZU\5T[b6g4:+T,lXd\^O72k\FT(V^&4Xtr:Yn1q9@[lr9,NCH2PdVAS5l9AYdum9!%U>MJc176uJs#;/>@nM"nEa=1mW?2^=lT)[,dr:BTPjpARPJ,S[t++7>+7'S`0K>_Z%@i?4Pc)kuSTE&SMsm1Cm/++I4]akqYQL)4bHk/!m)W[*IasC":Q95IpQ88/G0lKH`Ir=2\io@O"A%j,+[+aVb4r3ml-",kF'>3AimF9P43oh!Nc2^GT`i_a^8TOD"s3h?GIE,el#l7kX1kk?O43h=u#BIjG4$Bu@IO=FKu2D0_W"f00MeX[%1Dm9\FerR7ZLHIq,^[dH&"O^7sKQY*cOVO!kDKtc//*m$XWk,5A0Cr2nO%[aUMg:c.cEnQi'mjWbRS6::^24r0dZ2KrKSppJu`Ec,/jDa!^5Z`VAlc=.MY*og*71&94VP*!1h&lO!CD"?W-J:YkKTgHm5()LY'0c/uENT,a>l/&gh?(LS:1Db6UP8TpT,7&3o)*@Yb/Z\"s2nb5XX<1-R\1`#n`pju8oSd*IpX8OGMaI>/8<2.L(,[ih&MIWM_['A!mh3ZDq\Vh<\BJ6m^=-d4moMM%aNQDD`"pnN*:Jee?pBg\KUtm4*/+2ZG-05IQ!S^`D9!r\SeVAL$"j'fhQU@*^!lMLM"rq)oBW:$/^f8^2D9,E7*jD7[[R(11?1l<\Q"EhLJYt0e3G7Z'Qef)ZbC/9ZJ&cW6r9?d:rTu7fq8Zk@qN#n>pqO$2^&$gIJ+`+lrUQ;)aFAX;Q!\t*rg-])J)K*TD`qP.QFqo`:MUf87T[c3>%OM;a&2$%,GqR4Lg`2,BaQk/mNWF2Kf?2a*N!6N2HUQLdY1=-7,HHhd6arOj"r,:CM6Vl\eIe7I`f3HNZlS!((6-n3W_D>ZRA(NTGR_e*iaaS@dXC&dtI&*:4X[+16#_G">2e>uBjQJt%hZP9UqY\V4Q':(bF1WW)3^ZD\&>Or3)\eArQi9R1KICnBT`hGqmaOEp]R%1O&T5c@lRD/KLT=A=ZQbGV#i<*^DHXpk;lImUueXE#=nX9=$r8cGLKaG6Mc,NYMOK?lMUZeX8>qio$@5,4ApXcVtt,El;l[_tmlo/qWmc@V0$K0]g:[@L1rLL>9Wkf%h?gOJ4OK-m_D5DN"kr8-,]o$?:$[N0DNVLp5!gMaso4\f3^/]=btg4J)0[W!A/XU$r$8H/.ZQ]?`o(@M%/+#J7[??G@A=s[T0hLUmB*cOTRGO^L:M`^C?X2WO1^s"=;<\`rIG"t(1cL6SC)EqopSu40`20RoR6I`nf;%K/$q;<^fo7Qq!?b'gCb_:%/]LQt\j\Gu>=LF@EZOY02]:ZYkO7S(jAoFf).EjhmocC"`/X0;Z@$oQ(cTObIo)#Wk#5p57faHh?iFP:DV4+U'/WhKLP=nAHc(]6Q,Z\_WP$nRF:*@[r5@0"5V=fN.Zu,7=JLPpIaSkp4HZG.4j$%U,f/rb6;7s#Uo'!c.qMdST\EA,]`om2.-)jDg[Y&$i'bskj@M_eBCV^Z(1H@<\o*/fA)QhHqd7M$nFeU3uL4]KJl*q-Ks%t0#bW4B$G!oMc#\I/28TJ^pWJ!Q3L'q,pO[j4(;ATc-WCXR2'::h9Bpm4&&Dh(OHe]T,aT1ub3+Xja4>Ua'ENJTM!o9CNrrcI6;UQ[9j.;EhW%WLn#0gH^;(MfRFer<#46Yio>Ut!oprAP2<(tF&N`$?PKpuuCI;l0jqOCme'gQao!F_\X!j+'U,D]RA8W$Z&Fd\l=>L4agB&`tCbN\nI'Ub#&ACl*TL#+ZSJ)tGUJT_;c?Y3b-(m?2Y6U<7BgVrZTK6gJ^_PiM@Y<:3-n/2l:>6oo=(6iekX<)l>h/HOG@4bKJ1qH+Ei<0g&NFf^KSte9-iE1J`D:G677I#Xo*Ve2AgXq0b.gdaosNrE6Gj5<).nQ-Vu^t.mjSN,nL4eK$@W7r^;HhhbD$)K(^oACY'OQX+_+BN.ed'bGu1SG:(^-rEiqMrOr*<@QU"*<@5Q_g1(u9K@Ys_oolXA-=]$$K[58-\UMru1o"5SoP4@@/Hr*loC&sI?9]gmr8%(0;[#7,KQkYnqVh`EEJ+*7N$Z92?LmE-R0srMkBr_BV`mYET1KUD`<[YQ0+Te`7[LUt2"5(n#=KT#@S)-iE-J/cE"N1LFeY96MVl&/R;O_%NBuj::4.e>8;o(uV+&XOF!H895L'U4\mnb`5FMu.-"pqi38Db8cFJ)m@hbHnl8Cn>O6Z/M+'VJ`U_,&%qdBa,_(7@u\?66N!4OY!iE#WWQ>MDHLHlo>cscl(Wp>(=SYL"%IL#7rY/]BO%tJ1q+LpaVTA5Ub4JHNfPC\gj"07H/>5&&2I?<\?)O6FdD];NE'saeI%@\4%35ZU:lacHEjFPR$0(bL4b8/=)*FI%:+Yc%"B(oke#:mA1oOQXkL*8UcqH/,afPkOkMB35bR/H*or($L@;p::ZFGU?b:tUu>V59Xbd+R9(1ft\FaKP4<3W6p,%%T@A#,*=,CH$4!)Jq8@dj\18]++UHQ/FU)_#CU4a+f?A`)Z`mc]3Wn&aI,mJHW?%:6>3ej1h8_9*b;/gMKPac07*"7^AdpT;u]'2;(mo+(i'XDR-t[)]aPN\KB0ph.aQ3I7&teDVjq8[oPh\I2eM!D(^p#S>>+5a*,L.uSaf="d=+lMlNo3Y7U:>*N)M5]S&6b%)YT0\D&j/VXR57S!r?0[+Q1:In27Ca+TkVM4Q/o-$.,d_c%X$gGnL"(JcQ5!NAAR+ZAM_Rfi\/,nSNFDmDoP)PTn'jJ$@?P$L"E&pa8Q`"!O1%+Q[.4*4`6h6rN+hI3Y/cX8:?(%2k8R?C?WY)F^Lp:^F$:p`;$7`moSS*ip\0l3e8B6udrk'VL9"9;JS`T??O'2$DLY`1Z6L8I&hY#"cj&h8E2]5FpCdD0di"/&N`8K/f+n!dQ4G-rY`Tk+MiAl,"c,f5P+XXDLG`)SoJPR=du!5GP:5.@qhS>WCIRSq3-WZ6VATUGQ`WUpL7#e;WfCT&n6il+Tgk0;#Zb64JKnQ]*h::#js]>,R3i2PF\0_H7YbGTb$uBthco)N04"iE'&`7^><"EttF:-fB,(+SfGl$E.OM<*b$Q"?B7WG-hAnR)E97]69%r2;s[K@E,$K)"dCFLf9UuD;RR]hqc"Ehn$4jr02,[?MieIp$UL`5iYZd0T%,8Tpd1h0NGK7p+mO+"5]e/kfE6[(]6A!pG2?eFTVeDNt[JO``c+'4ZWYi%I-J9*lMXT0BcI1:F@,n:2A?be$qk;X"cOH0Z]cmkE!=\*QO9k?O6+W&8,I74U4<2rFr/s&5TdXZ2Ju?FfdA#Up`;)e\)+m+j/=D*H=tI9!PHN/(7(N$"%ApYGp`]\4n-_5m;/mCmnh:NuE)6P;/KCg5^rGol[Fcf:.d@[-_Q\IM/n+YmR2EaNtBLW,N8'`-kssTTJIrjjpYHKe*iA_$RL-S(7H*9oSlDm)o>$AAY/8].UTkGHa@^Y?ha0]PcGl-fE,(eE.]^r]*4C[*.kI]>0i#>7O3&^r\i12X!0$,E(<4.bUB]39bhF=Nu4%`rYWR4ZODrd,IhroWYKU?T@J!mcI>;64#6E?5NG$'HWh<=fPD0k%:idW#8keYVlBD_[Tib=>[I1.r\#ijod%U3Ms(JoWSCd@InkVU_*eG`Q-6D5#l(R:M2D:Au;-[,"segDI[W!LHm\Y$-JW!k/`QF3F%GTYkdC^%82X94t]DKu4_9r:E1'u>Df*=ui\B1#N^_(YsAf8s[$_+)8H(pZ[d)E$6X:+A*lPRV9"71AI%r]TE(2jA7[mJ99_,i=K/5BPaV,U(Elf\qKj!U[]p/_K7iRTGX+$4Ico&i$*>,,/.&=FIFQD70PjfTIltj;;'?J0M"6Zuc`[jC138:)Jb'ORZU-'8Fb>h1?ZK25T6I\cr5M_F#L\+Ia]?(D6ogFfl37N!Nf0B%.SPTMgK'A;MeBWuM@SL6BL+35?q6U0j9Int#kMYuUf5)5+rELb3Lff,4huA/:>6Qs#&nQs4&MfGm:&-T7(!BHZS@7T@EU`46"J]:_1dM>>YFi@%B7I`$n:06#V'].J,U-n'k/TGAPdTG[BC1/h-R25Lde*N?N="NRm:"9nlT>(om1'*tOfQOl\3-9Z!=e*GXPHU^$-NF"Hq^@itXZdO&[^cP/#DKt<*l'n^OW#\BoM(&ecTKpQZI=tho$R?jdW&C.q8c6P@gPt/8LN0%@+-`(67!]T.'YW7W62m&<9s5cZ6:+H!J#3)LF[oi#ib_pmH8hM9n$G4F&(t^>*(7!+M?W226]o_m6seh/Nc\l;L9RQ&7SM%I!JEFGFFc_UfpHJn6<7cG@n^mRWtX#rZsYpuVVm-l!S`_hmk1F7?G-"+oG(;+4bf$lRTF>Qk+_J,GN+d@p):9=@J,J.U7&jhL0Y)%6uTtk19FufEX]n#L&k-#l\*1n8SB4VWf^qNE$^+HXt%l..9tmLlOb^0=kg-l<\I!!YFJiVOpF$LV^+mO,\ONd1O>&LKW:Ius/'m2ojI]l@@@(pD>Va7!">hu&Um:V1eQ]_=hTDVebF`]BC5bX([?r/XH(DOrS!_SI@s'q;uLOc\Um)d?Ekeeu*\[kqJI-iKRVIFfK^Q5)'-_=&ZLJ%jYSDZo=[-A_t>qNhS\upbeWDp(i=MUd]"bL:pd,,qp=RA?>09Q850a<8`Fg7>7G'gI?&tf@nA>lbSrWiW3X"'uPu"76&WUR5+sg>B]g+LeSa0R7Np:b-9EUO#5<%WD4@O#ebeaG"pZs#MrPlMb_WG2q[eS"DoSrg!=@-_l6S+gfm(Uee7'!t=7h4_e;uH6RjiGiJR[GarJ""''R6-/-^XA_Y?n20k7M,HDj1Ba&Rq6TrEi8(e#oS;`Z]a"^q3SOC(j(:?8nI]:mj[!FKHUR&r^f$*gnoM^OQ,J=F=MfWVjKgKAg0IE.akTA4Y-C.GoJc,@/+6sTd[\dFh6(pO$!AX9t#E?HK$FZ=.3),rR)eHkE-lcos7r,*lmUc/g,Qom=OTVU7_g2$i#Mb.7dp0+ZIlV.hUOeWI^/SAH.J0_.AdYpr)[i\>-`23R?!!MgN>D,)i@9iLR_(u396DGTgFJ@#3HN@.n$.l2t)7:SIb"N:Y/>W#F-%YeJ0Gq)"cp?S03MKj2jFJQq:]ALr?oV_EH.kX]XTbI@Yc)!g.G@-%/qBjKIIu+NE]YQMK#K/Q)#9('HNcooa<4WJO!2B[.p$#l]RHgR0kT7!_k$X@/Ujg31+OYEL4WRjafIW;?6'(m']=JKcT9mS3/3V6'CS9H-Gh3QY+5kRs:,#XFGU_',s8JTl`/nQNr%cB3?fjV1j%dh=eR)+:^RR>.]GX$!].bM[`R.[LiaeOq1[\9:BBQL%(A5Hb9]IA&/@ZUe]I;Slqb,pLMV'>B2Jd"eKl?Og=&%G*Sg@g3?-S*BlIQ%ch3*NPKMM$QQPJGr*uc3`Z>_EU7Fb8''dlWt#.%KD_3r*o.i/rR;!Tr)4ehe8VFp:Yh4,KH5W0(K!oMp.UD!E2;o^2DoMS_.F,XB9!$4^#4(2BKNE!%iQ)%ti.6;:PE*;[#$OXS(F',SPd[(D&pI1:CGcH%:62dAW$N)`a[<`A+qV`I9(W3W-5e!9+"^5/8pFAqBh0Il7!`#='1hdp/#SY/P`pu[oYDI!`=GP'UeZs)hC)P1-b1_<5K.%LHUHLY"h,h+Jt^rQ0<6"^;3BP9D5IP)FRDu'SaSN:aXM2=ODC13VkN:QKYFHDHPh2]\2[/1E)*$Ae5"qoqa&=jfMFZlI]BT5jLU'kIk'5&bmL$Q/_T*d.Z[KbTkM&cq(Zl$+RO]ic(njK=-hlP@%^Z`q(D[[5d_:fIE%c/#B^/fK1OF!!-ei<4.>brm<1p2%cn`gnu5B:h(64U+FLqqW'Dc"Mq.0Pdu^k;!-gbORa(NNBX+V]Sfj'm%ELa513:[QM\19h!%=JAb(;(O?QlC]."!q^.:.X2kF&c>U@P2E[aMJU12HXI]GJLRVXn"MLlI>G&r@'l)MnI#\/I@?gq;^0jB')sjL`.p`?.:"Y10m/._db[P-..G?&CPZG+6]"Os4`0X4lg4p[KB7R:/IdL:<%UtDh4/jb_7pEQ83*s5/m#GDGm[A8Tb$qHM,h6GVn->5dQ5mC:?o92,9XQ=37)&dO5_mV4tUY:`m!(4q;6qPmr3,+0'0o]/3U^BOJA1n.cWX;1]CG1u3"&c!i_d&4Q4iCe#79*35+*lg(j2rn)m4)pp[:AWJXFg=VR^;\+,LZOq\l@^UCp9BI"X#^124G-SRXarDD9_Er]K:i&QL75s`gh0"qErY`"jY5ZQUZd=Iu)+I<4fKV>Ylj"fR"l=0$mTnX`,i4+Q!#=+*-_bh,ge^?oXk5$4Y:!I*6U4iX@a@[#ZdlD_pW_EaAbS35e3V[T4(npM[Pr1R1nMm,=eSLbri1Lu]@GY0dE96E%TFQSV6B4N'I)/*B&tA<,A`]9>QE2/7h=f%]E5Jn&0tQt[%`J4("F2YniOpU"'rq-=HY./?B#]S'B<:RmH)CAO4tT!Ko(#3gJq"aC;Le@C+7cog-r@S,q$Bld+^8OJQ/\Y,>:Q0;Fm-G/TVD4+ON\5S$cj.]U:[K?t):(ejeIm\@n%oCs1qW?aU_c!^)GM0c0a;Z\`p%JjIR?%![<8U3DtP[Gb19qLE+5Mo3oS-t0ir+i&&AVk@`Ze^acr>PFqg,<$X4i_k[m?>Jd)SOKq6V5_BLN2=Hd"m9La!$@IJG(b&!h0pk"&LYXA*LDPIsf4D"I7dl)A5BBGg\op:Zspn@N"1H3>"[#G;b?G"tU7=kcmJ-)UE8u!VkhT4pC.=O3\OOjc"6CWQ9q&[]jeU/PM,7RQoZ:]A2IBhFLh^:0.ScC7b,4'.pK7kM8-q_\0"jE)*4VA7,5tQ=n+1!)KN'JWXoGk#Nl7SVAZ(1^f2#(;]MJ8i7!^b+uQ[.k887Jqk6%Tm*[Q_8jHMmj[0GjSPZReY*o,_HTb$-qB5j-6mIjGd_m3Dp.FG[NN16?g&4slka>K=.)*s*uhBV#V'WoQu\n7lp+8A'#[JZ;3'cU6G^pXD,4qL:[rqBNE,X_)#W8me@G7=qTh?$]`Lae7%8i@&]8T"*aLE6ZsDF#LbLFX.Wpm#Boj]2>>8ah2U4!0R'A?GMPuOaXkiA1_P((=nHf:&`0+renVh=9f/c+J0_%tlJ/+-9.kr(3@"9P9@WG%nrZif::G,`6_D^g.^a"uS8RKP2L^0Cd=K):C&e$W(jA&92el#gn[][Z7Ck>[YC[=g4(-P;I@qDf3;@WNqVj<<'_:\(rgo*Bl2JXY='($ocm6Jbb`omC;<,!AGiqb\T79c>i=L$AEPPdC<-,`'UVt?8^G=HUmq-F%E2s"U4%LJk>C.M,D%K$B.AQOjliI$Y/-6`_OCgLe\SYCW0S<]=5+t=#MVT3!Q@jeckL6^]7o:N#U>o.I^d-/FKLu#VZM;_=<9iASjZGnOOT@Yd<]dnk1@NusZG,[AbkInO3T[C+/JEk*N57kX:fF=S_(Ku8rLh/PS.fU]\%+2RcbKg7cPVc2ba]c(M4,7d1)$PX/%dX<-g97h1G."hM`Rj3U)=B%TXOJ&C&T;`oSLhE\70T,2=ZS_N1HN'-C3:gfbNV27O)6ejr5^-,+OHX\jN\TD,.kKK)i[j)Yq16!]8k$a)N3i.`,p)cSuS#aBLs8Sk!mb&;"Q768I2t8$JFnG#%ToHY@_\@e:9G^^Y_1OtKcE0MDh?3InB7VY312q8!N9_Pp;7]>hsqc>EXrYH@%BBNWS^ZXW!n%o5U'Vhm;cBe^W*&E*.I/2AD0RZrm0OW]NKV;g0q&q5OX4Aljd[-eKr7EqO>BO=%]8bn4X0^t74Y5YgXpQF$+(=J2`-B@[1#RUMsB"T,SY!e<^?(kh/$^_@m"7ZDn%),!2A67J6]&N4-rO_Z5EinSdot\Q[:1SdQl:Cr$Af)>j/I'F,!Y(N8%uj&rjB4$j.a]IBm$QZNqlL2EL2`Rfb6e5Tu#NHOl)0cnN]iD#]X/,NYGDLX,r?de;,%qBdQQ])VYk;V#m+-b-G+X]&k4W\t/t>JpA&Ff_Q1&b$`+!]:%qI)RT2tLs01E+RTfuDb([rs-A3g@QV$O_X>A.9fNd1ZrL;Z'gNR_[VJDBIUiR^JchX.(-K<]F=W#.FA)tKSrf@[6Sm.;p)_VNT`RTBm^RWkW_J=WRp9k<:`:XiSWPs3^>NX0ls(,ZL:_>m^U)]Ze8X?^F2_-9'Y&m@Dqi2_f_]@`7QkFCR,2;;a-6L^!LEh#NgOH9;YNf3KidF&n<(2_PAjO=b_1uE:((`=TpLBaT$En/UoZF4<_?pLC;MfGRckl,!1')b+*",?FBf/P*_6B3:jZ\aZ.Ls7D(&C/<.FgmTR$OYCF\$nU_0(st;>hhei-`UeR.Dm;g&Q4IERdDH.Md*68[)T2Z0pkON.Y_XtJ6(E(ZNA4UIG.&idtNEGFZo:00`e&-<'_oY_'j,'%s;F+TH+q(,>Bke@af%M0e\M3n4Vf3*Y;VW!^fHn"84^b*pY^oAQn%uR'B7$q(:#B\3OLGDXXYf6#XYc-oh?p>,boaZJn.mne**eV?[s-mXjpJGmIf6J#5cR>A?th+%R5*Kfun2b",O/Q0'<)NKXu=7HX[a/XV6b,2*mQ%'WGnJGB3NM@O'W_Atb#/J*.PYgY/?"0U2D/(G;n:79Tn^(I`W4%*R?=gQ[isudJLUg*EAu9!`@f@=@r$(4JmaN_Vcfl*=*u/i];^V[6?Zo"1:9-)ZTQ]n-h%\;(MR<5%>Y+'oj=JUkg#4(+>`l+2*EZbeo#fGp(?.J$iHo$.T1TN3i7TT#IK`DaLS681E<;GnrXR_G0%)jXd_`G1&-_j_W`,-AG6)]j2g6FGn=8$qBe7aXO.u-8X[nYo*jf'%d5kU7,jP0@b'tg^F2`T97ia`9jblHD+\M/l?q)/8g`Mk(qSV$:at:#,kWhif7CV:.hk;>#koK4,V9NPAUZsNiUp_3FXb!RO.Ma<82L]/&l+L3mQ\JEp%+^2s0i985^jiJ:l.GQWo^F^s`rV1gV[4E4qV=TS;PcHb3Fb>7oh*aHj]3U*>(HK_^RdA\*['pV?#\b<=OfZH"pm9K#;7>g+-E`Ob9M_$U6IFUd67Ck,D$<1cdjmQi=OWO7EYPEoc#U.Zu%>YRP#'QRuHDd_T:OO]TTk1#;ULg,$nKR*se(=lN.GpT?t.1SP$?R%%&<)Oap7tR"`TjtRIG4^t(]Noq^1R#6fTMJn%2lRf4P:eC,*>7D-Yokb$9bMqqfgpo&C\efZ7W=U\.br5C[8:nT(.csGpkVh'eV!35*\>i\/jd&a!?Mb;3#=Nr?oYNIa5&NbTuM4]/=0f^W=3%kK@#D(N/oIlL@:Vq:l`j_BtsM8`#2&IXO!1i$L'.!fPh>iUQaYUKTpe8]C7P.A$bUG="<=^2g"-rfSgO9/mAP*?2pi>[iaouaA8;n0\Q[5X$()*\95PM_!U5.EO),_$4$bLXI7Y5R]/q^AdU&"KOc[Z==ZNH$dXneA47sGMP\eb/l\[a2G#+nd-p30/)kpX";d\T%T"h)tD)Z:_Bnu8e/]YuCr4W[blgR?:97"#KnN6t&dla+GC@SoGjbFIHL83C%F21<8&C82&VkPY/PH']P;eKkBI]"A)N!Me1pAmCs#'CPD^2o*$kM,Z`Tm]K^;#*;*1C>IlZq.Pll_*=c]?H"T't="&-ZG61kh](APi)Qj\.1o+g7t@ti6s\qm4jJDrF!Bm9Vt"*Dj_1Ha55Y2]=mf%M?CSRUuQ30\\l0J63e7hQpHMQBjOJ#9m/$4eJG;d)C:"7c$4O%_Ht3J872Z-'^1ERcH35Q)M"5L#s=r0oe;+,XgLc)m8)B3S/:;bRQfu;T6%#dnr^@Ds8gM2n&,X@3n``'_\p^S"eFc1tfSQ*rWLR-4cRL/'u[&T`@mEp_8OuoTJngGOb7;*V&>'`tUC36''\`Ge3'4cJa,%)lTiX#o_JsXlmbeG;E0j[G-8s-"".?KZ^Lea=;0I.W=K42PF+N0*@OCT80fEO^;@QDD`LJX+[C@nS)":h8ROe1]pU?rF_,)d>%-%W-d[0h[_-9r:''Ihf#ge0jCGW[BuJFP#BcGIAR[=JDSSBEF-\T`ilf'ZDuVG:jbnS#=0Jmk#mG)Zl^m?uOji;&q&"'l]H2W;9TXF\t1M4dk=qr"P#$/(Y]_,cate--/<8B%g+<@H:o8Sgm`n,eLf"7L=I'Le2CC`3OAE$Kh!C0?s'HLk-R>P"4N]`V/#.5;[chI%@K@qZ;VrGeY^^ai`mrZs_fC*NKg`^s#M%$QrGE6Vc59fXWcJtPM.=,8%5Yl*#7iR4c>1=C^G+N92F1A+Y"(4%8%4c"F%cToT)OAZP)\:gW*:aP8Mm6m02&_jVF98JY!MlpNr>JF+Q'MItD15B:*lXa6a>&Vhk7-C4`_SBI#HL5tLNA=]qo&TmaEk+];`oULA;"3_("S?KJ"3^/-e:N82M'o_R`\!Pmai$nqJcl3@8r()\>f5)6VBgb`K7#%2JS.bp;\<*.NY"F,iM`na+,oARn0Gj&.8kCE*"cBd3jU5/[3J:u=pb/:D-JeD,J)Y:J%)@5^G\'g,lKY*:AqS7'kL*U7.$T%fhh$N8M6fLaj?4[>W`KZKbZr*@E8+QZW>H(U@5^%6cE5o-FG+*h!FMgSo1dq/89KG[RNk(I^.JJ3i1/9egq)jKML2Vc>"H[LgF6nV[mSj>Wn4d.s1%;SjX<0*+RGOcFnp2[KP'`pbVK#Pk1(oOjf"P07!/=u%O6H,6d%G+dYX+T'#U?Ef-*LO'GSL]<-3]BG.lf+el9YHei2Tm+P?Qc>"O:H0FkRP&7b!QjNf/0&7)L:#_&($#6c)Ot,Wqqf0MG8,f!n0j`=/u9Jr4l5%H;h#FcU#"NgrZ^f1*REJsJ/]52jrs=fut9+^5nJ/R3T!0-M))8k:np;`&RoKp=:lK_3._WXEXmQ)*cs0%.i\pfGAs(/NC(`m$A._co-%paB?5EjC:iV=%*,0Ol+]4oM>AGsm7qPT;'a+Y5EJL$@tJB6)#Vh4dl\VUJML0l0IAUX@hSFd;QEZ.-(0QO]DfI1EPm-iT!jbj\ek?Hj9+2$,-"\:EJ/D[5c&CHe4Xe+^_V.#q&=ia`Z43:9iD66$@'c6mGpCa-W*=QRna%,"9\d;*P25O"kJS<%^"@83rEM2X1:MY7Zh8"!+p\<2[50p.su`3^PM>iEOQQTC=mA0OC/u$!]Dj8N^Xb7De_'$kL[43f;0-#,31W8\"_tPK\Z=l3,q`%QUY1-^RYGPCkjAKpGX<_6,%RG;BggSge1N:.dA.Q9l.m0UYMY1:[sMVE+t:d9hPRe/[n#]nE(G1__6kW(8M(\fCL-Ns$`$S;9#u%a?n:H*SiW$Xh(;n@P%8]-]H%lSQ-%`\OK&!@1;c@l6Asg8"n,k$c],7M!)5kB_QoN0f/0VqcqdnD&adFW.G-VbqMdq>0GTd7&D5+R5R[dkU/@Zp=G0mjcVe;j_2MrU!@B9(['(8P`S''-T5M0``7K\+9rc4,aals.MG+R#\R%!(D2mFY4L6_U;9]*#/Ni2,h'52S7KD@C$&9^)U*VuW@K*J@3CH6VKri5,S6>MqfKA?i5%APk3e-9;0IgM9Zf3"2L@u"K"Nc9n)mHK(UQa^E];F/"**?:Id7^R)^GP)HL.oBQN7#Y^D3"(Hp,X1:]6MKi`6KOsK58ubN&U\-nSL.VNq9#b=8A#WFA(,f]@\B9^W`X?%tNQSVYd<#c[7eDW]nI>sh7U"4TMheN\dW4rMn]o"ZMXYL1mQIP]6+#63_PL>[-.t#:&5DCl]o9MVQf!^t9pD?0J\(L!a["EtrWM=Br2V7OM&k-00s.dR'4K-CS5jgT)4KFX_-X"NQpE0;@LI;s8Ya:k\Ikl!(-q9k\EY:1)MaLI4TZqcWfZ-T<1p'S?\[A_Ap8*]jEdb5'Zn"Xd02W;"DaQMEioN/IST0%#E>_aZ;e:^%\1.%jJ(.NB[^\Q'`Oc1a:<&&?D-_[67-sI6A?$fO$ZF@5'cKH9:)Ff?hiJ;;V,G3Sk77ijiSEG'Y2N+*f#2.L/*CJ%BK:hX!?`/e*Q^Ds(A/9UWb#]YnbhC;Z)Qh`JYmh3,ckD(0ug8@$7:+kKC$Ti+74\DehA2<5K\R3j'0VWfF&\CbC]DC\Tm?uf$)=UlO*U/?kdmpj[#cVQ_^auQTni21k4\elVUMAp31k\Z1'Km'Y[EQKr=iQ88mWj[N*TET#K7cH5N+?NZ#Pj6uG@iBI:G=t-j#$"%LYq>!YY,45&tQ*])>Po&b2odt]>,.,2p5]I;rm)Dqm`Do?NH-!<>]>(B7!#m0n6([@B8(^&ZO;;m5IkHXs%%E7YQq:+eg.hPa]2g(>F;VT&,Bfn>IMUkoG/5*6L`>n3P*fp#sW]8ZGe,+Fn-fb?9Dc%_8L$YU'C]eRZRr,(d``2I4tA&pi4GRB,'1-7mC>NqJC[64#m[%hFOt7(A'Rih7up#V]d'GLWQGDG%SB"h#tJa<-rJG-#H/\-_<'?+BT;;n@(DnIr7@\tc3IFV]2dL3u9Qc2gWZb+<3L;#:G+,9#6b3B0))`AFHUR&M!@XlK^AdK'*-;*m*Nr%hKI4$6/5SO&E-q*@+Z*d4[pOl/3AJc^1m)V#j0AT+F6.%W/E`$GUoVqApiRSYXHU&AtT#2FFr8e/P.=#%$970Qh2`6C8QI5ZF_toIb\6Xm)4I=)%,fiLCA@'+d$1"L=+?ZuTQ+X?f::nIU95H!H,qu&mM^ugM\&>6!N,;a&^.V";\?:U=Tl'WJETCe,J7iM`i(f$$:Jf!/+>qcZ`R5iq6[7LnQO&5j1mGq!2\/c^BAHT[bugHVRe&fdJp@J-j&)4S-$V:i&cRQj4uc?F95iKFD`7ao!)KUpk^GNp*c;Jg8Vh+jFdoS.1X)C/NqIAi![RgN)AMK^3?n1h7BJ!`ZgGi,**:HHHg2i)Gft@6^3g51:Q/'ctZ7,P2Y;3GEIHX,CUQu(u"VhXo.%p7\FT(Pn;odZ%0>9+@IDOXUP`h&gE:_F9pSOCXliV%c-Y3ob?Oh-\'Tia:SEYBR?U,,i^B/a`;g-M!.PmSHiFBg[ndg[I]*3X7gD2bV$&OMn@(;)iCB-g*gTr]G%\G+H:NTXYnmb)^&!+ApLJM-L(ai&?/4Y#Gj&[m$6F.=p-i!7!+)spbnGt\4D'11idsPAZ-Sg,mIR#8jI;@n"AUrd.S.'"Fp_]&/\&&Z169PRoq!E$$q&g>Xa9?KCUcKNBH!1I#t.8V\]UU4HP5R/:&?4?0t3K+L,e,FuMWFLOIXN$OAOH!gnVUT$U6q+JR&%;X[%=ig:.'n$+*,UH4X);\;PVKJZRa*/lq2Z*W^,`WiRWT+0p?o82Emnk$)Zh.\Qo6I^H]Vaf>rOph;Qk09i=_e4P$;./,T*&4O5RMoPQ6>4DAiH8m2[K>du;&[#i(*U)*$R]f3)G[,Go[7&#Yd96nZ3OONO5,%.]K6f_at5dC9N<4S,p4RF-0&]UV0Y&(f\o6[_&1\2FPE+a:Ke&2FD^DNb0FK0VHOT@8$s\E;c@*e0rQaJY4DI.PC5+q`t0$+Z3;^2B$QLOeYL!T\bX@N28CW$[MrfM5HUKn&']Cr7$To:rLOs_T2]K>"#-FR*lNH$@&hCM4g!Y'i1;@:\N*G_))q7*!E?XVr)E^:Uea`1N8s[Jb"2L<4:&6G!8n#(OsQ,:96(e.L*\<>'Y-8oem%?@NapL2JZu=p)0(E\&-bY3l7l'i]`@3Z6OE`lJ3+D$>Ld"E#B>"QtS47(HkbNBhq9#5'"FDUs@q#sd.<=@((?M)Tp@WiQLNHj3"X-(XHr?W$Wlr5bC)"HCKEOa&N`iWk9uGI#)s$&Fq>9hj2.]b3k&=0&QBF@`i9e'KWsN93U-2$NIjV$J@+84>\^uSQE3g,\);@e@i:ei6,pj`WH)RD0XXUl32u)fC2j(t6/Nna#:4[F7.9Mk=dmGnY,+$WU93-mc9#NhqIJ&Xni(i0pq&Q?a]ff10%L>:YaepOLb?oA](7`[N/"jbGSrNF"D'[Ka"Q)Fh9!.XfLRfUjh4Y:<..JFk@PI]Va@rns3FdIF-!;c,mPKg$OIi>F3O5JM`^lPo=Fc+58-hS9`;8D>PJ>Fmql:6h<&G%`iU>?Fo(A\Rl@UWQ1[,Q4HifGe4q6oB1_FOdt0X8e3/]o@Tc>ULJ6k%1WCbUfb0e/81W7F\#O:&[eP[X(7@"_+nct:aeT\0VtiLChXb2RPH?l5M[n,5S;--=hu*"I2d>&,^O:75XQob#+,^$JBAV(]?Y9*j/c0:@GI-^4m0U&n=)4M7q@rNkBi-gj3ZkE*aekO_H]:H)Cg37-rADclS]0'eSM@Qj7s;I$q[^lq.++(CS$tI0K36ZLX4NhDb\iQF[GIWGr@Kg;mt"Z&2!g*[@kEe*$At'$`-f.0g14LLOfm>6M:Ud@MF\FRZV:(7_5]N)?j)rKC<(1rcFg^Lc-?$`AVnV]K?[NDW^C['Us0[`Wmu:;ql6o2Zta^Fq/!;$Vrj5bt`kfO+B8YZM&d1'P'b,:H>J3H/7M#\gSm=tRFU,jb3EOD:NYK3p+F5Y$s1,(Ul>)@:\QG!)c9?0A]JdM:)<@V=U45!LEX](h1&3KkPt\]d3*N7]2mt\3N?ALY+AWRRJ$ZdR\+sI?hbiWZZ*`l;$u[$_E7hJ1JdAlrqV:M^\$219`S70Dc)7k#A;g^9AZVU_*_qOJe%97I#t6)6LR&PK)B)dIX^J)lBKB"HXqe,LR5\2;]09&-P:j-Fc-PUM8/W)k0f1I?@\\;sU5/h>I[T:8R)ZL%^]l'gI`m:p\D/q7LR?BYj:[_KTp_B@@`Q<2aPb,!\Fng*S54[`M[1`Ho`-gNuo`PTpHc\-L%6[!K(I=oJ.0SR,[STTc>nmoO8lP\\PZf7E\-7oYs#W;6:=jnbLiGAie">"uS-1AX>ZJ@"gN1g/INRHK^L:592VF\)B"?HJg;,_+TRn7%"=`<=SH$"@YT2pU?.nuoKF'>6p%QW.ik0.)SU\6&6A8cb`;*@cHsE2!"<.23?Ai,eJ:(DIN9Q+VH2q;0Be%69^2hQKNcf'F"#Sh-m'.p(UWDZKU!WZ'&"FH'#=d:Vr>@!lq;UU(_K"@3U;rQmIeCE&b-%6@@g2RC'T>]K^kM(1EUdaR&*4u<$(/@_Y;IMf-pK_:Q1D7.\L)`@m'`(.kj3!gH=T`U59p1QnfXSV`7VKk[Ku.VX06jG1)\M?8$[LJI2_Shg<;FUe(Kn^VK`&$qr_SI*'<"V2MLCXisanF2&@3I]u'HUDa\ZGT9=MPDXCc;.U=B6/2un@hX*ginDD!Q($/jl==>JpCF!DYSU,^0S\9di(MRcg3L7afV4^$ig7/F[q$@e6b2K\qW^D:CXXYE:H/l(&B6n(eLUh3ugpiLB<]>^/7q'>HKJod-99@]<-Ql[P2.h>6I6RVk(8=[Rj78O*sj$\KJ*5/#rR96.L<@bK!mfF?NdnH+<@OP_,5MKf.0P7N86jUJ:?n!`[^J.`E:?)TGbPc&\H9X5a>t9,@PQ^Vp"?+fP"N9-k\;H8OYGmh133$tD3!,LV-Ujg2+SY0!]"b,[^+Ujc.:Kje<$%O6KI#i[K#/\a6:c*QkJkk%YC)g$AUg@XC9R/ECK1R6EAQh3:Dr5PEsE*Ic'Dn`EsCs"K@c,jBqhT1A,QXgb!bS1<:HtGHD5]78KroY>ARAKl.'[OKkqH6j1U9O?+BnN'J>G5aW+ILtWNm9M6+APFFFXk<67D1=c6?B`:DVLrO`AbqpSl::`PPocV_(Xe:L4)%Y4tsu)Z8c-KM;r.*1(+P$5:ZH:i5J+357SAq*\SF[61N'fMO;&FFEu][.SZt,W`NV8\,PBh[[dZ$.*=Z$J,joU#L[]h]H\!-R?#WY;\L]P;;[VKG=>k,Zmj7Z_8I)D1`mg>c*(f/]+[/sSntOM-f$TfSSY@ImMt>cYhsWKkC)*e@q?>ieXT#Q6DDoT+V.]h]Bf]3;ZA;>!A']s'u\fZFg]l7dfPe``Xh_7dO\W/o6+=`U:=fBK#Z*%:T)U=c\ZbG8a@AV)m]HU0519Q$2ckH77n=_kV!`1"qS`sD[K>O6?33p`Aaoj-ZcEU=cX6S2&9,KS>,SPCiqtE1guGX*K`k9El>;I[QYnNdEe@oTBPfjV+"R8]]oqkAg%:n/GI36k=_O8j^QORhDbUITqYIRkW\3O&md^Bc!"EbVK>/pOj^]INr.@GKNB#V"Go"Q4opj'O!E8E8qhf(M8s*_a_OD$F*1C!BHM0bpt`YktRO#>d.CYD,(HtAnb/EE.jq:Z*$/4l'\5"R:OE39te\p;%C;_CElo8U4#gT>'3lQ:+hKDQ?qMOg=D:[L)tU7bKMX=L,/EiV">)f-^LkZdCb&-S]S2Do%p2+b[=q:Ed+dU[j[/Z*0Q"O$mr\sG4`-ak'6-F9ks4>BnNRbogBKV>8dJEL(6B/G&%3B#cfZa#)u&k2:(rZbSDVnJ7C*%:a^_8,#''#12>-lj#n*sW1H]Y@+*r-l-MV.?jafY_CB(t8GE`qtL6)C&*]h6q-BiA,:>E+C_Yc.k`l29%Tiga2mMJV%=nMq?je8se/OlYtAk60qOND7X%Ss23lsM&@V1%nin(;c.-]VHRbZm\R\l7>J5UETU#pWW+pGr:A-n;o,+(/7/*\K'69mU6ee(s*'")KJ"NEg?iG@OE9u$k7uHq.\6B6a[`h_=5U,bQX0DsDY9%127l:7-Y2LPL$C1boe6s"Wb?W^Xd.BoMJ=)AC0d[58ZC)d)k&TXqBl.SSR/L0j%L0=29rg38mV6,Q#G\^nta@6nie-CR!uSF<3(^nV=X7'):E(`3TZ=iEXF9S&@pZ^\q[%b?G1)P%^jaWmRL8XOa"OYQT)+WG'PAgGA5N]?rgqr380+Q?E(E2d&1RV7Ck3\MP=8,=uSg[cf7sUn,]XugAs(J-Fq*/?;H9DV=Eb[sWYc9ui@bj5i0!uiDTQZC&s'qa+_e7]BB>o:'m$OB/\+^gDW\G&X*3XVlkc]f,Hd?`h^NITf4p5nNTCV\.W&+T:9SekMqG5"22o7G69T=@0?hXPE4;'>pagaVo&k#06"f9sML($o'2/jM?EJ(EdPR6=l&+aE@3fp+]H09&=CL#l;(W3$^3`rc:[R2sj`@Vk:<3Foia3se%%a#`172rK@$FjII%DsnH!\QgdgT1@U1ZrF>=bV9:,0WC-VM=;bML!6^.2.<)iRGIlKr0hi\m1T>E"e)kUn=L5L6JPH;="q^4PM';mB,lk$"Q?OdXC&>So=MP/^C.qYkPsjNm]1hDeKuT.9/RVKi#-`VaN5.l/]jIomGP?[JS6F\Z7m]=]<%7O(tneh]q@>"a//=S-2C\67B:kGQ`mm1n)n&9>"'c?R`t@FFq#G"]VV]iNS>pel8DSc22JPJ1)P,ZQceXOMco_!+$fTT7:#J]b2DX(&prM[cFd]'"n^r$kPXE_Q2P[5&R/jk$/4N'(t,BQ`6hrVJn2i,eHR;jo4MSliGP>kdS#bh#tAD`KbG$@X]qq!q`_Vo+58@J2ok%%bak2jIb*X5'+IIC)7f;-n`RWI^af=bElK`I)PRYAE0io]G'$U;b]G'4gCJm>n;U]^a`%O^UH)i=d>RVNjI4rI::^Ie.[O[RX=$W^b0j3Mh7,s(_7GVSSJ1K9)d2X-9Q+O/fR[eE;_T%S1>YjArJ-Y#o_>HpU_1H+T6%IJ_s>hS#>B.0:%-D!qI8#?^"Zl\l2q-=03oPlY>pteM@?t7D,kRTu+p<8n)gV"P(hmS"j_7.]K>3ZZ@TQl14ZbZ"hIWlBQRYF0:gh^7a\4WYkZt=&L;?NN"-,Yt!401u>#>D;9@IB.k$H]L?%RhVsC]hj.JAQJ$')ir&gK(.XrE>('It;PmJQ@!HG)eUc,\W(+Bl:c%Q4=f4X8(RW`9-J5)/&#V"j$ZhGi2ENu67k*g)lk09r5XE>FU6-6+$ZD8ZSm;r!=-Ft2h^WCi;!BGJRMo;q7RCdiNeF?R9ol>3]1'-N1R4^g.XY0+YO%PP-HU9;1s.p`%Yo36?V7'$CASu&*1)pI>(-<;`3E32Ool.'*P`/F"0DeV1_.XRqLg=7giZuOo.D2?AsUCZBIKC'.knZSBW;8Ltl`HUqL;DUk#2QS0Ahs:B&N:.VRroMctdn*T7kQ<1ba?Ise:Znp&QcPJi2Y5*P-K41Uc$W/1i*[LaBr5,,s@K#e.mb(ce:(L/Wnld>eV=K2n1o5Cpal,JpuBqoAh7T0gAm23C8"daY8T[AcnduI^Vo!ktp@2b9\i%&`@+Q_@oZ?-Ws'd[RX=bccc?Y,&'5^B5qRVcm<:hc1_sB>U4W?n/od3f+/V3Y[LMBir**CRibY,'rmsSJX0;1F"qXOhrIPnMfCnJ62l^Z*$f?7R3)jXOsQi.*&8u/Aa%;Q:Pj2GO1dm:"r#4@(9a`0Yr"SH-r(J_JB&t;rIZ>b\@Z3=qac.,:]f0?@2>hp"T'n=pf0gpAHEIf-nbQ]"b&-Ftb_f(_as1>HWm'plkV37+3eDfiJ,'@5"[R/Gr>FuJF7=\\JI)\KQj->f(4eg['3>IITQOPr.pGj^MH#LO&)1U?1"G(ReS]DP"37]eLrjsFQ[hH&)=VY"1lYCL:(hkW\g87N#\n-)MiG#T),T)kj@SQG_!j5`nSEULtj'dKad9lWH?L@Lr"\AIbE6d"^_ZacYL;$'7=P&#FVGLNq4!:MnI_#)X#7D!MeOSB6$1)nZ'f"TJhR6p;,1!JuCPWu9])VZ`'(7'n!GA>?;-P,BT.-pi:oVET!=86I:smVm6gG.LI;E67-[1fM0.=UhJDp7KGF>!,[+XkYIV"dUEk_!M3c?&kGV)?>r4G-=Y9r_+4SXZ`?p4K'enUuOW^iSG;_uYAIc)(+D2JlZ-Nr\5,_7,31#lWiS"kF%m6Hs?*g;VrTE#3:*8;F^l(1@%*pl6)_uR3Nr4#@?VPnCej6Ci,Q4HcXq]1t$5$:R9Eid&qpbCKI2QD$7=i=mI;^r[]\,?7s')+Lko^2TLE:Bu=?K)!BB8n7O5,V,%/J/,2-I>upc\;Xp^9h3j]<$Ij8@:(N@bToVE0KOZ,%AGBY@o6m-`7X0c^U6&%IlRa0?/peNlb>XG+L"2B&e3H''Ra6e?^K"*G[8):5mlk?Fc;`h,sri*4'8/<0B'XNTYc>epL#!lm>.uk9d4tM-NB)273[C-B)@^e`qa/<++=TRCIceuq51tJ:DZ\q%/3+cZ4Ddr9eQRr-f60[#0MKRSeLC."k<>nkI9*(\Z?Z:ON+:,aGD8%`tC!mgL2.e9%Is=r#j@4F`e&C5fs,*5M2T5uBYT+SmJ2#_fW"Vi+^SB4QmjPB(2IPkQ(IW0oC.97EBg0kGLe'&m=hN+'BmX&?-g&1K[klAFFcASFoMUjno5N[XFN%>U.ZP:EnuB*7"d-[EK-5sh;laa:O(P#oG0Sj#+m7o-LC/NHLimVu/Rf-4D`1a8lrVp^".u!MhB`G&Q*&<2!"YW=1E[C=#AJ1>='26RqP_"&a^Q`A$oL/RQ!L-6**"67G`Y$Wpp52WGdrCP'sGi_3)ZDq>c#F0(kNmV/.Gs1A0AfatX\H!NFN)-Ar<,>r!Q2N,bu%Y;'nOHmATu0>rd[Sg`IfTISjm*&70-S740r=bA>0=?HGniXa-Do:=+,T=*bajm`4umud6&/)UB+s^UdK,0gjoB6qUgQBffJRSrG\TS,Ub_`4o(\%m;:9'%U0&X[*EYLcV++PcScbQ-r`4$4P=Cj(obP8W%?p*V6m2Z,bh?WL$7:5H<"*e,mhf=pT^&:GXS.:Lg+bV\dluNu"\/]N6gM?2j]:_V[&rP"[jOfQK[_&=MZ.T4]Jul*ksb75F1$kp`%3%_#+n"`(0qX3e#nXRJD)24X2Nqb[\/MB$Q;\V]LQbV_:?`Q?,NU>H(f@Fa1kH^2#I`7Uoq(Gj5LW>g'Deau%2oKp4;nu7bq/XpW1TZ$]q#7?6_bJ2-$"=G#BQG;E&#_G0[PVqZBPVrB+>"jPCOJX-;;1`.%Lu(*:KkLA?K;q#UqMNk,MFJ-[5obj:=VZjCZ^N5S8>T$4<./dWg&I$/Pn_?dFpSVIE7d-QcdQN"%;p^q1iVX1k@I,MNKU+RTSYi-1Fq]*(!tYE\l)Q+`D-C;+;Bcn@]5[gBJ]JYNJr%pPE\C\R$&;-DQ/T:eSfRL,d^/6;4Rg7\2$^O]u[GC.YUYju).M]PbaNdf8)S2U(ud/\YF?ou>BlL$0AsJ(uOlHER&/SB>WDolr5.5nN,A_!Wt_3BFi[=PL>e<4hXG=i`9[oR[>7gXX2,Rusi>BX4r6DcAR_!PtEJfrArTZ*YZ`ndBC7G#_1N_!Md,#h&O/tTE),:'M?Pb%Wb8.Z4j-U1k/17pFP(7a@]C@1RR(&tbH^c7*cGM\oOU+?#ZJV"1E'a_aG>jIbec[r,-"@3U2=Ns]AVi5-WCF3C@l#b!gaXlK*M4Td;$&TR4n='<9au2D].PX#joX%@cB.3$mAX**F8Rr1!nU/!;k/J=*f70>>l?8ocdlY]FMRk9s[B$?XHL6>-#_EW9Opn9.of(&52VtVWHqsZ]MV&UrbKAG3U\u.+6i:k[jMRJK%k;E?9=mFB-N/BbD=:EBcWa.%)fM2Y0NZf>RN`Vn;6_pd>#\uZ/-[RVJfk?9MN[hU;mO"/Dj?#3)n23P`Nd\>";pR^Tf)\C7.K>sP"X@fV;2?hV/KP6D;+ij3oGhlABk15L';"DBu$B1m,^3)0,"?0+j.ol^i1U9BIt#_G#@AOFpe*gO#+r"@3TPDoB&C4*.GmV9AmcO2Q"7QkEj/UV^;sb6h8!`["XZ''XOF!OJ!c(V<(@:<5?S<+]2odjL[u"@3TC5uFOQ(=l6k<:\a,j8JPABKtQqI9aa8f%T'ISF*Nf#l>nBe"jN1>7h'QSIt;\S&B5b9mVbK@,sZClehP&fJ2nF5DSU7ri3D/Ecm,Mr]5%HJDtIkNmQ/#,u&jQ%!h'I]6hL5#oH%F?9`lK[dl-$#WBSXo`Sd3CRg4B,<][aM+*qtKPp1`F*7l!3.l8L0H4-Vf'&@Df/a1PQA\gat;0hq-K7e'l@\bF#re^2G`[KnT*cdq?P-EM"jfQC*bQldi2lg0256f-4spMPQ)+rU>FEI.b9q\NDr(]?O#9dh<(B/\T9&9:+)TdS?DuIIZ=9;lDLE)J615UOO3*ZZ4;(_IP'AVuG&kh2_$s1Wp%NubiCdGh>gI(_0Z-0su)kVr8p8_\(7]K+?r59_qKA#&_\eu_`O?GhL+R6,chRT6D_US9P"1??En3h;:LPH\HJ-VFR>r&?T?#?,kL(d.=/5Q&=+nVC#@<)Y,<$47&PV*ok8rl^W[F/'_m#VG-72[B$L?\!Ml*T8sLF_2uIJd,8:C;mn,#-j]/Gg'q6Pl/;Y-%N7$/fdEDf*^*\-EAWrnKNGn+5Y-?S5NlE9?d1_1=o@bb)Z.STjeqfs>P]ej$qGlCQhD9eT_Y@`9;dr$PR"@t?lfJD(_@2)?Y:dhEW)U(:6Bl3T9Ycd&*?CN*+sJH#N)J+()3jIa]V\PLnFT_G$B+Sj9!`gUNC7bW:JJXnL,X6XrTFL5+q_9+U[(9QG&XTPNC*T(#!HX^(\cd3HBmA09<.Vc$>fco!R6R%QkQq>1[C1;p"mapQ=n?4ce:b%`X>K[r7?`+MU)rp>M6!,P6`huV)ju^cR8#Og%f,@8BeTn>A@C-Ao=Ffl0eJDS[n,M>ZpX!9&qS-)-]Dek7Q@Jbq`JYP1:R_R'*&Vctj%#0-9V0I"ak5SKqTC.1kCY]!T0b0ngLdUk^J"t8(%1ECFO6]QoQ7eVAc_2#o?_0YDiGi7DI2P[hHdFSmp*>co()@*$Pmu1md+]E(UIX4DY0/gNF/HkL&OCG%h0!;on@_+Fn6B>b8aeUrH00jDqtcm%gXE:ErB>l1HT*`:4=mS@[$:B+h:f7Ek._#UXBDt-s8MSU"8hi1pEPG(kFc'rE?kEn&dV)t=P30(Bfm,m)nGKfm;iDJs;LaN#FF&D+Q`_+Mgn#@18[OmE*gi:k&ZEJjg%`Ra/&_,pmNdZjFIWFn=aSC"#Zg$GBc\C?8&?$H<^fe),+j_]`"GK*MnUAMj/0h_8[-TQB:-9:'Bu+Ee"TYEPo`W9E-J0=23ijarM=ie.VU'F%((;F.57DXh:]6pm"?"fHNg[LdD1g.1Pj'BnTq)AL\`C'.JL9120kFuF",Gm->@dRg#nQc2?/mc$fPp[iEFo>siAO%2>[s%.m$gBF7N$Od36UO4IDI-d=_N`0+6+%"fbpET]8!eBMPlpnG62bpV=QqKgr$dgVM1ib:o('*[!e2Yab3n'!SXc4WI/0[m#7dQUc$?WriQr-S:Tq=8B5=nYNf?N2^Pl!\3dJ$ek+XD-?ER*Q*^=smiku-?W_]3C$#IR#q.JFs0]@PfZEcHuQoX7($b>ZTUW9dCf/dA(LJV/Xl@O"`bfP;2(^;JW)jnHL(kg!F50.<7X&DCI!?Hj%:L6)ZZ+qJ?Ib-2NL^(:EC:0s7Sf0UuKU8TL48]7sn`#03*,CNLZ\nVF5-WIB(ajh+jVNs%5]q3,aNEk;1SM[m@p'AKPan-)fIXE:\c.1hHZnk\J45.Li\J.6s6p<-$-qi4:`TdJT(JXom(WAG!#jPT`2M7D"[Po[;2=q%D?'Y:?(c:_l*_i2M)S*+4.JmT/(:OTX30U-[?Ksm&6HLporIm'2Eb[qtKK!7[?RfeDG4kCXAldhK&AfSiB!;;ND_NU*I;(r4II7SibO]pS]dqf@Q'&1PXEg0XH/A0."TB3JiTQp@n)oZd1JJU[s!GpAOaBHd#JP3n.LqJsH=]4&(2BPY1%-++=Kf_TJd/;8IEn0;`_$rFGsTm1LH]aJSD8nF[_`C6W5AEcP:X^Snmm>ft-$n'\!T;#ukJ_t%hhq(>9t>eYTBeKu^,ZBE*1%ltpk$1[P7o]6S6T,VP?BP,H=k`I*6Cu(`c^\uiY$(o"fAV+_F=G=c$`tcna)9_EQ1(HS#hs4t$khaI:7IDS?Q\lrBZB!71NncE!aWaTZY+P$ihHF`&[&"G5Z:SpoI&L3q@en>`7=Jr3.LpT:dADZ&?0jRsL5lGgM>YopBd$q=1N?%1Y4JrOg@.gO"*+Y#E"n`\ar;H@r*i'8IA?:!YT&k?)*KL!^=H\l2*>/Yc3^\B=hb+h)Hl'j6q>'hl_BT=R@6d,OHJcHS`?dq0DqY=df=bs$kS#SGVq9JLEU][(KDOn'\>K6,Vb`kX%N:FO*UkJ4%ia6PDS&P"V*;""mW8ndHPaOVbA7P.;a6MT.F9jGF@f:n\PJ#$$NPmS6<0XgIq8(dA+QF(CHgpqWgV\XStOr:i!*H#l^Y"VMI]aB]smcCMF\hTS^6bX)2M+F!;2AR_Dp7";3$g7sEiU#:]M`D+?W-D[oG2b?b`1/Im^2f<2#A_3c+,6T`2M7Y,oAnR4KO5N%ib?\#79UhgWaC``uPoJWE%nOKbVi$4%KqYJ)(B3emGu#3$LJT:k*o+4?:%4d?XD!dn`..;\8)n:TrWP9<1&Tp"*%l=hL,t*^]V/r6nI#os88U,h]0YmHOH>L(/MHc2tHNbLoo-(BjE_NGrb5Q*\orPq,mSP;-.ihdrF-6F[2W\_WpW8B+fh(f5]&Jlj:UN/.`GCs/HI[mllJI2`)1@95S5@PMt`K*MmfY--p!Ls;UlP(WVs7_#c'()7R,@A1GBW5$-rO$4b[J*tjn7r_BfP$#5lL(0f<8Nd)n+RNd?DnSc-GDs,pdh`[Ol$_@U14iE-uXj/"lm)KDOn'\?c+ZRl_F4&!E]hN;amVl:sL/e__U,&!MbtJ/11og,/5G*7Wl+Z[1.OP#_LSJ:N)ep8p0PIT!/P>@c=sK(]Z`.Ve-A*m84,l7Y/r^M\_JlL4+E[iec%i\/,(@N&O$IQf]9F%uV`l#bD,KHc'ZG5YKLEKDn*:k(Pt=]nnb5(2.toJrH0\3Bk%RFRqE1OhS[m=f10IdC0r7`.k:X[)h2#PH].E)$;]C:1B[c6UoL0RC9Ep<8qp\T4jP^Yo+g&6k)#[dWO/q=8),11g^TD[/;,Im:=n6P`AUoP*WaE!^&@8tgu)%se-M2."F="mRa$W5!5'C[1As/R-=uI`(AD-:a(9jre.B/uZMq*^&ZC[;26qOdWTPN?(0NqqrDh:k(RNgc9HR#c\uQo3&%l>5c!^f`b)hX8n^>)@iqcCB`3pE_q8A#T)"JUr3E"T*^Q!61Xd?)*`!YQVugXq?mgRaIki#0#@)Kn46;HG&"0`!qj#I4FHpc;&PO'bBEIP$%9QHi?ihHn@j>In8_*s'r\n.T`2M7/u?cG,%s77LU4Okh#N^$d@[QL!A[7_]s,p6]%=HE0KJ0R0,&ta!J+pop6ZJ?T3S=riZ:l98D[RkMEm*56&8g7"h`[l1Q8ki9nF&)*`!YpOVm;l#3aH4eUPOC^/&*b'#-YN>aMQg_7P;B1ea:S[gjNAd^-fSMFmln"%5ZE$7B8Yi7stJ6L[Tqri.5M%b]VBL\a=4aP1\0l95T-&925^0S`n_K*)/Zo^=.?M%"mU_>\VEM>1Tt_TT'S>D&7_4*I]j\(\E=1[,U\LZeE$2K;be]:f.d_b,E2!WiQ8(f4J]8J"!oj+7kc@U^Oh"!O&=f0]EnFGYR"j2R+M1OJi^R5oPFKQA!lq1^XFpslEHGqg5Jr\>79ZZg=)B$>"n`?7mH3-!<\J^CSeV$5s,hrid21jVG!KNi8U1S,`@hsc_(qNAdG@(g`QNc!m2e@K\jKhNiZhR+:o;[&rhl.)j-S#s!%ZDc]a"ALPbc[Y`:@1JpI@0PpL3NVk>l(Eb>*n6<)SRn6IA(id)lB%Y]_UqJZ^R"97%of2H$/P\HO`9m-2ShJ*;gINL)8;'L8q36IhEd&cCP#TM#'YQ(ZSSm`Ra[AYCW6&]@A#VuQI*[f0Hpc__6spZM:X>(dr/cP?[KPkK3UP1#(Jh!EY)pF0K(8l(`JYFN3PS%)0Du'LN>t-PQ\BIl\A%s&*]_[!o_368Amdl385S%S+Me)0^"]!'B"2jZH2uV>R,ELF*o4DIIoVd@e6d5mJ)(BSd9dIBY*"iTh1#Hc>*`G>k1?ZJtmh$CL:?fi'irVQ?b[[$q1fACPY(\7:hJ0u9V'aIDoa[,lJ,MYV86NR?7,9f)WEn(LLX2!Ve+ec`:nqI8P0E(+pgtZ/K9k=RZ?U@Fb4i`R',?1;n^n;b)]$#mWMD&OO&;DbG%1WjT#ft6VkXiAZJbi"LlE;/c(A\t>]>26K6//kefBIC)gWXg5QasA@jbafIZEs?b;N%4IZ=W!H"iOh.]GE/)8A7Pl$5_$Z2CbW$hlAI1/^%r?V^Af8X_crFK"c]f\F6?1KU\f@dWdC[*S%o:/$hNaLhR$0j/okj+*M#g^S=H[6`@)6OiHCP:+OjR5=;It*Pr-^D%R:k-SQrH0@?7=U:GfZV0RgmBf_JUg7c\Yf@X(Xo.+GF.#uAJ]Cc%HYKdTYD_+%RtbEjW*5l\_4Ri9IIme8m>I*WZ(jf&mcR+=2'pVl260bUC"!.]rRoK[6=siURU'9-n#6/G_s75rmTmG*[WfheUX;nbDqJ;&"a(Pp\7<_J=:"RYS6:^i29OIp:N=L6:I"OB,h&="5\S4OZ+(gHEoc^uBMF/drLi^Gmb$L^K!k^F00--+(LHgdp^,_gnj7X`q7mX9f-#>[*ac!QkO:Sjl#[^o>aRO"3nTkNblXK-4)b&Z)i*US:"\>&gMZrnY$\dVi(&)jH!%BPYtYT0%DN8Qfd7[eea@%GT6uVG3URGXsWLSkt#rIH10H#F?0\B*3ZQXV'(gMKbS`57Lp*5,m*\Za\?`OPl7Y/r^M\_*kqA-hS_^nj:\*%]:CiM)2f<_\Y0>j,Iqre6L(57kD@lTi/eJ[>c8WiVK)/-WrVQ?,JjW)sk7+1&*T!Z>dIqKOQ:e"0]+J=$*(HQB,J<$P;5!oOKDOn'\=ig&l07G`e9/5gSPLrQo0hB:SL&`SYV1[mLMgE);$Upho+]D\#X\Kc'$H3ds*+]X`+*QT;hbhUepDf'NS4QQ4L^2o7HFpBc9,Mmk(5icoV.e-4u@Iu@jC*lRJ<(k&)9'rn44as#kh/?$=#U/ItFdl.pP/inMGhgb)X&=o!XP*(k]B])/Hh2e5YZY.SEloG@#?ZJtmh$B@thkHhh:bKVD_4qu2A?]7>jsG$%lS#JWjU1S73+;HMl!/N_jIlL\ak="5a^%b2'C_au)F.ME?NT>#'a0T_3J2rE]93TqQQ4L^2o9/!pB_S&FsWjAKE_YbqYORokpL@(`f'h.ARu$B2mAK8%.j5`RJ>?d`^Z;Nj(&YbDju.DhYVtH@jO;*:94NT(jZ9[cgSUHQ5bILrfVp1lUJCirhcNgJVXk$,L=Z+USFQnaVZ]-X4Q\#c(,679-1Rehp3,(H,i/'Z(V*)%^d%O.uUe>^(P\G_hJZ_-;ZVc00,uGDM0P+Dgl"6F-Sl81\10Cqq5W;A;h?'"\tXK_(&%o]_MGLhfHk/3tTp!eqo7(l6oC4h^q@!Te62`)7p",1BAc7n;jj95_p".B&jmqNgA;i2?XfJL4Fa4"T%\2Y9a,_52l&Gi<[hZ8RXW(PP",#G@huA3/Z_7;\KDOn'\?c)L(DjF+hc3q#"Q2q&T?tjqX+Nt$8SqSEhGKp5&5[j\iV'BX6.F"<]8:f/nn`PtH9/ZB=T?oQjSBf:)M\*HqWep,ZMs:EZ,<&UY7YpGHtk,i)<5"P03u.WIX?2SI1YY6qL4\"`0CB_j&aAMtF9pq4OJ6npon&^t$8RDr.uI(5[\GJHHQ.&rG&cdsLiU74uD?SmFpJ*-%QiP*;%7of&Dd$tl8Y>S,Cl2o9/!pZ./EI`0(+?j,>i:S4Ye8oF4>]D_m/;GpW`_?pa+(U%,f;1+PX62e3f^:o'?W);V']=gmg,8-!WD!dI!!/mcaf`Y_rHJ#fTL#5%B1l;HQ34aIeY(HX`,CdJ$-jYE;/"Y-TG=BL#Y^/M?@P3;;s8"QO_.SG%^apbp=q;a[!).&`qr7S=N]"/D:Gi,R.#P:4_#7UBNj2T-#plBQMqWgV\T`44u\dq%#JCR+cE:.oPD9=',.aOsOG*4,;3-!epaa^pn(:Jd('BF*8@h/Z?F%KWF>j<1\6)XX3=lR%"?uNK\GIfsuq<(.]_3cRt0j-$JA=iT`J\H3OT'?Rlh2H*88PaIf6:LZe)9/k2h'DTG::Qh$B@q?\LhOGgR]g%o:(*_WWW]4'/Ohl+C9SiZe6rK^tTr@'fG)DP_$^4"eD44IUrJsH>PM!h;s^N=8rWiN/JNZFTIFXhK!e7'*]C*o-P'`,e[FcO^ES%+LXlC45Sc'V'DZiN2jE!eSWRaMPEoQTl%8N^UM"*/F&R/K>s#(]j-VgS9t6-cc+m4mfuH7B9oY#ir@$AH>gR7U(Gn0H;q#Zgd0h<*dT'."8_7>F^^Mi4pIZM*_BqrtCtK*D_aq&hn:A=fHS%IDueXL+4%UUc3[15"iOBueopTPV6%lRu?NqX^18DKMto3Il.HZG+'0):nRp_ZoZ>(Vh0,HhAlMYeoSYUP9#I_5-%o]Y1uOmb[!"bc'(WdA'2,'@.CI$1\TB*]ROm6:-9%g!5LHF?87RF6DF!5JDPI1P;1$l/2MaX>O/_p",12V8$I2&@Y0=DP2:r8_kR8i=gXP]qI3F56]fU#laPWKaZZTbsh8k!BR(9_hJ=-:D-![\jgip.,\P8d4XMV)c#QS+tTgJor[8RJ)>]"L(?Li`kclDf@8:Y))R.sO"iW/++Fhhc/7-VIJ5LL9nj-!X=Q#KP"i#CrH0@;l7^V;K*lfJK`hR%n:jkd#;6UKSNm+pMpYd%It=Ph42!d>_hkKc*>R8=eYu\d"`jPNUEqlV.&_dkbou>2J,XN2+pX_p5CMf2X+8Oci\RK.4#RUd6Id\tV[o"(;GN5c,HZC.DOp17A&8pJX"XfgTAI7/:Rq4ZHgcCYq<+6^s8MmiS'2Q@W[jDhJ*64.7unW-*ZF>(l,cWGOZ,#d*WS7%WuT-s7/_6Qg7c9o-`GA<+[E*eb@n&U^W"12X:DHgd0m"UX.>][Q=-Q(Y*5O$IJEg=N]"e=,tiWBf++0%b8'E86#AR-7?GR(#c!GNIC!@7oCAZVXdq1`>5RH5bo7uX'XV?5g[-?_-V.'2$+GE=:!@UQ4aW\V+`A1H?T5jhoJ\0P&0AmSc+Jo%'A(]?i/;aDfUe*c`8NTqF&7?(,[tb(QS.@1#*3TFlI?Bg!$P'29ljpk,+jI!7X)6t29sBC8P.$k;560#_9PflFAK;Sqf_/U_(M\$DM3B$0;r3%BP>QF^&/en"nhWhrVIbf4rMdOIHXG(:77j*l(";!>>Tee@\TX>YP2KIfk%(PY&,3UKJKgb"]Og\eB(Wac'#G13aqr20/a$q14cr#-0I]S:k.:,GL><@J,j7uDiGk-m$k^\E'aF+(+r]S^6f0`5L@aVqXs.oABYD1?U1[B^-u>r7Co)r3ih4,LT5*)*L-Y+8.,g;GO:T^rE4&]QFMkLC1g_hTS:aIDRb.EG0;f:dEs0gUA3rl0[EmOX$sY>@G;Y'B@je&l!mfVG3Tg]la.s#<=%a_-MZp"4sY\b>!>%$.N<@_PQl@*XCcEQTc2ohb9V$0n._,R7tW0OfWOsr<7?l-aO0*".eLshgWaChFsUAQC!m2IIk^VJ,mHI%e0-34(aFPX*)L][l;WEDt`E_SnI9e-]B"j9uJEP;6)j)nA(DgUR6JQjLa,,Sf$o8Wq@/Ho&-?c'06e[hHM*^cGOG1lgN.CUGhF**_W""B]KJAJap9;Fi=0GrX"5pme[$W&=2IH-NO7T4Dmh_U;#;(nFJtgm&,5b!K?:GuV^76:3Q(uuWMpqWF<^`uO%sV0ft>u]+5INpIe9m8-dlful\;@K:b>?enes<*ic]sZX=U"Q6\0gV!]32%9rVQ3uJhf52eB#\d?_j(p,NFO>`;`Vq::'Zae?BV2Pg4L\0Qh[Sibgk>$DYH>kd-Q'J+7Muk".%h7VO61+%P*oIud:55s9dX5!rDC^8j9g;FCQgFO\10':BLc']@JS3;4Bi.(jE5s]?PL!\2^J:MY"`^(X'/:51\O$=trSkCBn^`h$.[qp&?"jWZ##KE\$3=pQpoKRbMpCcQM463.u!q_lm@::=Tfad;u[;4($HbC"U,&3qXjrS[TS_Z6\6JPF`ch-f:fRIoZj!hGI\n*rl`N5nDHT@@:=;$24*%X-m6j_^nDGfjfRK(bXHe[3T1(b]Q8jZ%f48L1'*lk#;+;+T`IuPC?<6,B9/%!`30UjenXaTg:+$_];i`!UY^ZPX.8sVZ$?GLR#Ukn83#hSODto^uSoLUcD[-d95@aQ^YJ0oI]PO9IPq*-D[K7?+YD?2`I)`R3Dc"&-P91"@3S%5nF/b&-P91"@3S%5nF/b&-P91"@3S%5nF/b&-P91"@3S%5nF/b&-P91"@3S%5nF/b&-P91"@3S%5nF/b&-P91"@3S%5nF/b&-P91"@3S%5nF/b&-P91"@3S%5nF/b&-P91"@3S%5nF/b&-P91"@3S%5nF/b&-P91"@3S%5nF/b&-P91"@3S%5nF/b&-P91"@3S%5nF/b&-P91"@3S%5nF/b&-P91"@3S%5nF/b&-P91"@3S%5nF/b&-P91"@3S%5nF/b&-P91"@:bdrr[^3AS(~> +endstream +endobj +7 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 5 0 R +/Annots 8 0 R +>> +endobj +8 0 obj +[ +9 0 R +10 0 R +12 0 R +14 0 R +16 0 R +18 0 R +20 0 R +22 0 R +24 0 R +26 0 R +28 0 R +] +endobj +9 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 360.934 317.602 472.804 306.602 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A << /URI (http://www.breach.com) +/S /URI >> +/H /I +>> +endobj +10 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 120.0 231.744 146.884 220.744 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 11 0 R +/H /I +>> +endobj +12 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 216.344 205.373 205.344 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 13 0 R +/H /I +>> +endobj +14 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 200.944 229.21 189.944 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 15 0 R +/H /I +>> +endobj +16 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 185.544 140.594 174.544 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 17 0 R +/H /I +>> +endobj +18 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 170.144 136.326 159.144 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 19 0 R +/H /I +>> +endobj +20 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 154.744 233.159 143.744 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 21 0 R +/H /I +>> +endobj +22 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 139.344 186.75 128.344 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 23 0 R +/H /I +>> +endobj +24 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 120.0 123.944 165.529 112.944 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 25 0 R +/H /I +>> +endobj +26 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 108.544 118.0 97.544 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 27 0 R +/H /I +>> +endobj +28 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 93.144 168.413 82.144 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 29 0 R +/H /I +>> +endobj +30 0 obj +<< /Length 610 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gb"/%9on$O&A@sBE6Lo`jhplR]%Yt-V+RlT>L`h\M/C?=(U0Y4pVh!>A6;M'!u;^0@tkjBTUFsmq>;QNV3mq@S.O0s'Tk't.^QqPUr5:>;)P)?LWW6V-=cuf3\j"89(2bG;rmW%1d=r&gYT]_"Z[tM,s!O=A?4L`D8ie#Q`FSEWS+TN^!Vc57>XZ8;KNaLlMr)N")r+sERoOi5IaJ?R_ON*TJ'SXGE=QN!&rHJ")RW!%^QuVEres2'3YBX;Vip;0^D3]j0g^p@BhSP2Cc$`1/F8@7i4Bl13]R!YHuFl\,~> +endstream +endobj +31 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 30 0 R +/Annots 32 0 R +>> +endobj +32 0 obj +[ +33 0 R +] +endobj +33 0 obj +<< /Type /Annot +/Subtype /Link +/Rect [ 96.0 717.25 178.797 706.25 ] +/C [ 0 0 0 ] +/Border [ 0 0 0 ] +/A 34 0 R +/H /I +>> +endobj +35 0 obj +<< /Length 2810 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gb!#^l]9dY'*#[qKb.M:%1k=i7(rG6PO@;(f3DY-[>-^nBUcUL,"mqAa(q>tI/+I:[&e*39:Gp4Au$;bI[hdVBCh%Z2fTB@'F+0`M_MZQ^d6'AiZO.=0.g(dV0OcP"s5J$.b==Lj5=E$s+uX[!QIaULu9Zq10K3l37BY\qcT0&.*A9C"ID4(p5mbY6FuMHO_2X;g6YP$nR"3?GAO[*bPhcS*6P:5*4@H4h*&7n93jVF2*;pT>q:TMHE&!j1hk`\P)KT.J4[S8i/H:`nuae7/C;D'SQ8i'G""V*0Zh4@Zt&b%8>fA&^.lPiB4(nf'`BC1TD`7]_YasG?Uoe!:-\iLER+o-E03q:JS0`q8cXD/5AYQH/)HJ&0iUZS7C#g*QNFM"U7/edbI>G.ReIIpcF^DF%d8QPTQnHZbep&*h@7>M;&EQ2M;4T4jQj'6CDb"r]^)8t$lICc7!e<+ll`XGsZF-M>gu0imC=^U,8XNUhEOjiNc?Y<_nsXkrqj!pI,,ChQ[J)l%0h-F0U`m2ueI_cSYPJ+he&>n.d!nm^#9KI$K_XTenNS'tXn7X>Fk8^u]Y/dcrqbIKpXa=jc!NV`os=70bB&;@e/`XAUW3SGKpG&gQpX&:#E%@b&Y5#[Ss?1)5VBmFlO=SK<@5EBsr+XtG!Qr=6&VrJ&V\s*](hrmdpIX..#AIr540`W*RjG,>,)HZC84Op!#"V*&=H=qbpXk0A=SS/6WGpqJP?7_a=sP6I>h>c-#k"@Y:J2ZK]>fgPC0!gnaA,bn4)0Da\4m<$UK.&$/9S'IX])W[^nG+Hf2)WCS;[\Z3Do5pB0`U9OD#$Bf)O-,pF`Bp'2/UNA-EE.+RBO&MX?:$nK%rsiOlF.>`E0O&7J_pY[#_bg`ad_2j'L5G$V3:S7sZ?;F]bM-!c[e)jWU-r8-e1afHJN[IG"YFH-IfVRJl4E!1eFn@XJYJ`k]#`gKDl7Zm>;_q>lM^BI%q/nr2)!35)?UQ7Y`l'Ua&7E`/bQI5`0aoaPrT&p#+\miSRSg"f$:W'?j1Z5,mej$*g]*@j4tpkFT3@"ATBAKS[@3G&TESI%^ZaCH%;MmVc^/o+.O'3D]MIq7h%09[_Aa+$G[R'-LRPXqj"6q/@M)&Ne<%rPb61EGi9LQ%g,6g)XBh:C[7aHUKbK4UnSF`eBb[X,)i`mDFh=O=fXY"oT(`',hh>CI(^\Fujk*d_Ej$`&QU[R"$61F=S@!&=s.ll*oJ$2KM/UAJY*nGsX/bE]#)0"sp`p]oAS9IQJaIP.8rB)VjcZO*Vo"'S2CKZ%LFZg'aK`98ZC"ac_8UG>lbV>:_%?K1"du3@/%G5ce(6jNANe!`VG1)8K"62Q+i(4#s0NQNf([!g)$_EMQCa2-.KtbK=c&BN`G(?i%1O2&1mmZ7^k.-'CeN)K[C"5'^#Emo'X\)b_VUPHGB!2T(j`k(%I3C4h]o=",pIaa#&&8@+OpkMIDdK<2+A!.lKdS_L%d.80pY:f.>kI%XgMYGiDXrTVoUD.,j;6O9p<*P)m42=-rbC`_.W?U%3'"#tXijHFVb!n6@/eMu[U_e-hc2@C@">WS-[o>%"s[W5@6:@_@[#q0ZPugKQ#%#ru:O!L;a>'H[OD/)`=,$$%DYJM^l>jZEN:_NtPAV.MuL`mZ^0\2LQBWm5cm@%fVpL2M,=X#MfbVQ0+[Lu"A>%%Y]VC/jC-1dpsM99e\Y+'SbIMkG54bo5SZOlMO"lAs3DgC(t6<_F9_bk&*"q$t?L:"/P%nH'D[aaP;Q>Y9Yq_<$FBsMoT4:l1&*Ag/Nm+A^s\o"*#\jq=;YSG*&cta:YOgo%h=,so$<*((B8%2l\ZoD6\We70o1Y`V+g,fLb8QVNd]`u-'YsrlgG#tR\`IO\SU.G7@3md#8@pl6;F`tYb(n-XS=i-L?Ft-B]7&C>c9WtBJgFU71kT$bM>a>Vss2rA:,S^:hK1H-B^1bH=gG`sMZ4_Wj"Z$"T8D\B!,Xf;i&jOP0?5rkDA4mj'Du$;frEXU=(Y?_lr^_BKFM8@_Hh]6(E!IgX1#IN&1ulc;/&E\@&qWHVH>GJ;$(h4JHi~> +endstream +endobj +36 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 35 0 R +>> +endobj +37 0 obj +<< /Length 2351 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gau0F>Aqt_&:X)Oa9tn.W:A[R:SFLO#PD>P+HCPi*]D:jfn3diot%""rf$;%le%1)'bXs[J*WM@B>5>=\Qk`>^@l0)AXKgck00?4c`EN@J#o("\:upMbde=dn]QG>!%Q55q&BA0@H"iIVC4'R0\aRnYuiA>)NUg2V0Jbnt[e,ik^QXR9Jn@.5,\VIkX=<&-rkd[K%>+pr8+Pr)OpV]qlf\0'-G+L2+f";f=9H5Ro^`Aau&B1DM;?TNl9o,2kPtV+6!a5Fq,[98h%0b?K[0ooGcCKMT%Ml:tK:8>?Y^.Ff,X.,F0=Q4>33DDF8*>lTno\YSi7\`mIW2fU.fHKMq)BVY8Sd*u)H?"KZ2>c.J"Zg2W'aEX'@D**AMSpF)5N#ZI!gQuicW9/O@Pj*I(k=SAKV*\0L,Waa?X-VV0Ns](st,.23mKiHeB`*2!c%e[M]p"_#ag',7C*lC#!DR@)Sd9lGlXd>mD3j;B9/\1GSr+../nr0Ohl5O6$kOek:2!E;:kDf"G/Ap9Y!kHV2:*.F%6CYan/r)Q&O:K"@l-aU?i../SiG(Y-o,bW0Egu-T#Rg45+&]9aKQa4d.\l%00q//H)j[Z6(DuL#bZ\$DP$+"3GpNJKaD3#WtW"YLm,?aJ0S;MT8?MT\CR\lARZ++;K=MqKFjb)Qb=>Dq;fT'1#!a/p.$3Y==k/i,rX<<8Po*iA=_OiPh=QhI#.O4D8A.^of1QPJtbpSB!6+#.T>J>Hs;\S@DSXKQXrr!&_EY!s03>DTsPV("(Gf$0j1>ac)h!rLXIB&-_uFtj@PeYOfCl4-<\iGA*G@/``S6i$+FZ3*:V.[dhsTMb6k>-)FG'AD5g6SEcG6R5L:&JG6&rb]mI7VBOToequ0@T;(rC"afi;gcJa^W1%Oqg$R8<>5scCZaqON)"O5nHg_[s5E@;`q`58Rp#1p:rXJ1"2O?*>n="`'EUJ+*kt:-knM/?a+[H2__0?-&;Rta:GYler05G.FUd#\6>JP07VkXrobSW):"\]IULC_iQQs3,bJr!5+Z%4O10FKg%.5>]^FB:^SgDD4NaKskTth?jr($m-bh:K`aqZ8nQj%`@#Ej-cqrHBMa^?b1RQk?k3d,rdf7NL85T~> +endstream +endobj +38 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 37 0 R +>> +endobj +39 0 obj +<< /Length 3165 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gau0FlYkN;'*"Q<_Uug.%1mU"Vkj3sC$Kk_f;?$[Hc=fQEM.1&&LpGQ*bk6'hb[+3;/#\67D;kK%YsZ6b\osr\N9WL24n<9K%Xm_(W5,c`fVFpF'UEBjk'#J)4-A;N@#;r)81%`.4ndQGP<79qZ)MEoF>JeEsP@rW<+&8]ZqCKb.hh*[JGI;&D&:skZ)9j`uo!2#U01t4(1#]?Ro4MRO;0-"^mkV;;XjW_Mq-LI-=t-?H8q_5<+[K7$ppKnZ]8Jd<'O54SaDC1+'#NI^\Kg58i/p?Y!/2W*=`2'Xq`:!rXf2)>?bfBS_pP,9LU'UL^/_=U/$Ni5@8gUDq_kjXO14:i&o:eg6+lp3qO43@4&?n@8GEdJ];"ZTWi36uQZ,Z>DEee0S:)HZk'@rAAEWQUH+T@I5FqsqD<(>lHmL!MZD"FYHdlN3BDMN&,Es*il7?$k-\t;XW"6UU`I`Wd$qlo0RVWgNW;[0ep'i,W=9(EdVXK()%DV^TiZ<1LHZ0#In(Bo%BIC(`jA3WDU#a,*+7[l6boL83EI((V+jjR4;kWF[G2:ltC`8G5?Z<7^k7Y38I2PlaMd_=S;_HA5Q`u]f$)f%+eR#dC&0h]717dq-e)q@/Y^Uc+Ne-K.c&JKt0"$WfGGkIsL!\/sKq$n]!-3-g^%VbU)[Q/&X7)+bR?qtckTcSUTAC(X&S&;Jnd]ss2Q"Xk1A$!aKaPuYK3sB1em'-9/W,l7ZNh'QIF8_ffT3t-P__C+hog*3]6:'I5Rg/7&mZ4S"Kgkc`<7'6$3%F]^)%aa_Fo2APRd3VC#B\LkGp82sCdAGTPCdOY@X*;Io<8Z$`mf\b_Z=b!I5n\8-ZRpADc8+pELQf]Kbm]3)4`3"eIs_kARfqaGW;$LsM>Y*R\?l`84<7kP:I,)bj^"Z[bV`[Cn]CN1qlbP+ZeoSD_D.pPs$08_Fn'qEo]T.ZHhf/IVq_IC#I!HEfJ^G(No<7o:S\p4fE>kh2?e7B[jXt5#i()T4FR*Bc%oD6-R"p9_acH:cG_1P0qRT4X,6NkA"BZ!f1C)eZQe0\V"Mk3:N_VR.\N\:4a$s-l$isF6>fJKWGuj/9]n&?SR?_f&IlME$_QL0D&b(N`kiLV&+'4X4g?*dH9fcX,Sf%du+H6NlEauYBpJ(`d7@U?hJY5nkGjCaag]B+eqa4M^8]'-mS)6`U?E`.K,6sOYtIS<-Aj,?ne]TE*S6f$!5a0kk:BqUjI)J#\8f#?B/>cV.:\C0+t]Kq\JP.GI!h?KhRFuVU.i4ckn0?]9U]2SG)GBb`OQ;mHi/*a0e=;JWC7m"+tQb=(%=^-UR^L^@P*J]&EdHq/-^aAqUUeeH5^NgJ%l*[Z4.8hGeThCl)4rVgE*qjD^H[.t4"lK(ZG,[ud)J8NEk?-1J5LguO70PqkCm/Y;3I7!Vn'9gnq,pD3[OBW.nKI3s@hG.*Ps%c(:WE34)-ZkT\ZC_N$5H7*1DhlSlSUB[X$0Wq5$aO=#qQ.U8+Yebihb/_1d^CC:pWl5'K+)l^]Q"s*=N_ZjKhhctXU%!o!YHi>S]J>.5=5kZK$kd_OQi1'[VHjQ:]:N/,3g#"Q,(D[s#@>.A63*Yq"'aS_-c@/F?\gIB`oPl3/kSjp//ir$I(B!l)(PKcGuLT$^&p3=T~> +endstream +endobj +40 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 39 0 R +>> +endobj +41 0 obj +<< /Length 2828 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gat=->E@OI&q8_F@I2J*@*OQCFkaCMWRIY6HI/aOo+7f'/^_"'=`Pp)0E8a2OV0=5[>Q4oi;(;/%Yo,e^0b7GoH@=EN4d,UGNCFM=*W]?57CX&@,rU^ntX2#\G16bb3[sDqdTLS0I7smaP_h%oVp*@ffY9G_)Vlt;!bLC^0<-[i5*PT_KF'qh?mMseM&#@RQ\O*W;]HuGoL#pofno!-,L(eoJ7.KQA%QtV67>G[[5[fFhD=$5SXuj5st!_n(a7YeA4l1Zuc2T]D'lS_d0X_[=XjE?*UcCWp^1FRqGa5/\$f=BWK.(`XB"ZAJ51!3fLLaN">OR$/bsBAXFjuCp)sF'2fOT/@UX[D.B7"PY$WK-RD)l+.VQl"DH<^/7b8AS+!O;r/@R0]&.jqn&lUBGc6HM_khU&YOb95Y2[4/aa!!RQcn/DCqY[rEBH/,jnId0*]*&U(Wpm>j^^;%-\H7_?eOkSSe&@7;$PejW>C;]"%Q6AIgn?7G^!G=Jqr(V,b(,`3HbuVK-@LYm,AO;,g>:\T_J%ABk[HC.fMfSJCL5i_2<]jQ.mABL?Nn94Q]T+Dhn0PmoW%Wr8Jl[9?r9\:Ptk0ohop)1MO)-/C!=.>i`]KduN,:'mZQFb29T=2/+U?h\Q+TOd&>J-",$DYNOlm1'eU]m'Ei&qoQ-fXo&C>n@r^4YQZ7a`%.J9HYp-)'X]hXpg&X35XQY1F*g"(of,V'Iu6^NcM%Ogj`XY?2sS/p$cr#bN`)?U_!]_"B+/]7Q,f\i'p&Cg26NH5Ve"P,rSmbd-!*Fg$!\6#,X$-KShC.9L(WaZGBkjbBYiO&Htg1#I?")d3KEP.1a!QM\hQL/q9HO6J&[.]0*LK/ds+TR6l*7:M>LZ1dY#tiSWYW;e+:^):9M2?'*gfO#Bf6G3!7@rW_IeP?4UZ:%g90G#FO7PtFah3qBjoI@fX,+N';DPEVetZad]&;A:IOfSQ:UkW>BCC&8ZCd7TE'?LQN[@`s7:Gl&O]d#cu*^"(W`NN">uZc?!QC>MC.hs2^V]"Ilf8W5F=U;h4/a>?:qr2fB\>B\s]W*?/DhjT9!m+0_W_t3416brcsZK)Hprc6'6!AKSe>')!'r,m0Bm,f/cYA(h*%7&4V%Dg&6Z^2AJ6:>)TW<k]*6C$RO(B4O7O:D%[qXO8Ai;%XhGh_X)U)SSap\LFacUW/<6S9iCVt:$VN1Gf#M`^P*U2^mQ='?;O[4f#n=gg84C^st0W?g/->;i4XeP&#uNN*=1@*C6XW7kj0WhreU[JPCrD$@7f1tZQ1TT[%ZNOfEGZN7:&>;S5bZ`^1OV!)bV,S+=X+k:.A36,]8Woa.qY$%p<@d43&L>j3#<%WO1M#sh5.(!bF8DG%^JqVYH!am2r'=1-'1/=n"re"4,24C&qhS)8#ktTo4aab4=a)aM#cMdA8uPf=rB[:qA)Zd>'+1)c;d4g`LK+re6YNZ)*L4btaH:1:2CpN+^R%&#j7W10@#rcT]eUZDKM8DK/>+DBOm"Au#64R_3l,j)7\1]V(b\*+Vh\&-1itXBDYX6*Pi-aV,@=R%a+,B2$W4[B`NpojA:8*Frc@(n\CNXoG;a5A?/W4H;'rYc/Yt5S?WY#BZ$KOPol5-SoBPYZh&eKjbBo'(`XjNmO#@e:1Go#qB80/QicuAJRno-dH>bA0$53+[KqR)Y8A0k/.^SQZW#teh_\hj:XDOu48hLH3M/"]r;$6al<5n=H%":W!*c,r!9h(>8adu%kKg5JIE=Pgto8^W$VBEW#\u_~> +endstream +endobj +42 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 41 0 R +>> +endobj +43 0 obj +<< /Length 837 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +GarnU>u03/'Re<2Y]sp0@Vk5F#qo:e@q#KGBVe9F#e>e+4.6["#E"iGpY@YXEAZCJNpV1Ac`qP=c=YY:RIt#$*-mch[.rj5[jV\?6(AQ]OiKTJ44JnL8!/sJDV\K/1[F*G64o7)m)^HURN_eD7?eD*&#'?A;2Ag%\fY5$WY,\bC*P)KD05DKW-jj`E'JCg[$E31-ShBZANr;78)r&8Ie.C]r`.^o[7p552#]kW:dY/A[kfpg5dMOq0pglR6pV[J+Q+9HIBBp$(OFa[7@ia6(M.E$.h(`,W?Q-3k*+HP;CWR=#9^R8,<+g/)gjdI+Iol7SX!L"iuU['nYk><.+tsV\p/$uH(E2kP:Ql2YOY<+[K<=L;a)6&%Obr-+7<.)WSD0TV_Ti(d8Vc7\H/42$WMpM8YMVOa\kBDfg%6j[G7AKbPeuk(EkO*HG8kp;_eS:3S>q8jbFZua1D&#%'=34OC +endstream +endobj +44 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 43 0 R +>> +endobj +45 0 obj +<< /Length 2157 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gasa1Bli8loK0h)P:m@oaHh4[Z]cQEA@dhb(0!u4iAb=RP50B_87GU%4JQmk4WYkgN=;U?Xd=;E01+nSXi0%HTb+[7k!@'b%A'gY=\B/KEN$g7D.o/gCf%,pRWKT4)KH:GD(o5&qUE>`(s"HQUanoCgV0@ca>",MA'05_\oT4bmOBi0)f0-=aE1(Ep\UPal'@$CJ(X4VN">XJ#'-fn`cmlPI\sAB1sHnG1*H;+Zp4^d.l@$$K?kVsr,)AZ#k?U3p=mK(Gk&]I?,%GtkG$g!1_G,KEY464h_MSN)Xa/-j"Tk^%[2d@(dN+kkZAm]>:SUM+5ZL[?nKHm_boa3PWQ+66#NED3k!ltqhROKH'sCjXQ=>MUUH[7d.e!hfsm/kPUQc!mV(W5a4Ygfr?;19];"fqnuQUabu&%%RZ:33)Lj6%_/[c&no^KP?YlG'#OO^)`1\Z]!6#j61);W*N/mQa+S2O>1)TnLj;WTj1[J0KtY?s':jBU^]7JJ[J*\J^<@3WF*Yo!-sahOufkTL7AmmCPdD,-&[^O21f\n0ZiB-I*$+G%li;W22B+Pp'm;"?b];f5E*O`VY`1ZA38r"hrf4+3@+PA&a`rpdId3U0SRi$Z%2jZ4Gr.gJk#du*nI]J:CBjS,n5ZVZ]*n$<`k%1eq66L>FqXPecgbUH6UCJ`M;BtOm/e"(7#(9#:ZEqMb[#S"STfE'r=!L-T)jcl&7td::j`8KdS\H'sF:;C`ro^/\H;]bsVTdVR%&XfRckQm->"d&E9-E62&,H[eXFS2Sd?`(a[\T)!0L/@jtBe0&+69DoGjfn],V&4l*R9dWF])b(LDT#I\7=;@Z)#ajDKL);]`Z&%qVG0qi*'.rNAY=#G(;s2D!U[A(u-oc@:O/9)gBQ8_a<'KIH0?kH>Ob%/gMqA*d!/\rY-H/1'9jVZck/L6IG@dL[dK.Yi0*2sTU.Ld_jWm:6=GGSo8&0egS^NRpDGKWBT2.CsZ&qB#J9Ob_#23c00Ji79eEul*BKj_lW!pEOLR9,?t&eE]p-geP7WIVW/gPe;-i>~> +endstream +endobj +46 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 45 0 R +>> +endobj +47 0 obj +<< /Length 1692 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gau0D=``=W%"@rScso+@1ZG*\H#qP3PAJ[C)u!dqoKef-=L5Q"P\!A-bbd0:'>j8?"A"(+e%t:&APbumA%EME`m]GV-N'Wn["7A,OuV5OVCU]i#q)@(+_?rG+&;5J"fl)epX3Wdns<\Bq3aj*s-GIRelCFe&R)1K=QP2+ZQP9C7DW4t=g/02nel0!,RKRM\!lC.5LUa$$5'SgHE@h;9+`UPfg0G7+BF?D_Ut_=ENLBW]H@>EH2ppue4EgBdC)F`_nX_g,tJ^#]#52?rQP])o^mqjihWeuH6K>+/+#(7-!X@(,"-R\R0VD>r,hBR=^&pOHh,t#M'Er0>Ec0+ea#9gU'AJZJJ^KkV8X@SPKGpFW2j-H=<9#d9#oeVILg?/?dg:;/^R7Z6&MtAR8INtdfV4JH)+9:`(rFC,j.g5"eF<*mH'WkhK&fsi_hG*=tea<=[jEC*:3Z1/2C3:%0Mgk)&M+IsH0Rlmm%W.)bU1Z>u&f:#3f(b#k[\*f$j7Flh:#\eNR$dn%bZuV]RO5n74UY8R\Er,[k3mQmD**:Ao1oYCZYVLUWt'Y7^D?\A`lDf,g4WUj?X"U3I0:3Hb>XV7mbe<3+!*kaJ7,:bJ>"Dp2&_P4M.PCh.iD"Xe\OPqNudjJJ#OGQS&=[]"6ZiR=kfC`O8"3@r#I:s&]^<>Ro="h6q_mI/OlOXMq4\'kN&2laj!T:DK/hO(ZkM`Uf'qOSo-%:0]EQ/8$F\r,'JURb*'Z5-Kd;GARBh`_iZk:$pSb[cF(e7SDY<;o=eI/g=Rb!]^GDf=#VD$oA&d,?IXeb=J.^Nc2/"WO@gHVlS>Q;s+,!j:VYr+KjN,/9SH@?LXR_(?l7h^)Sp!?A"d)L1H%,B:kCbeh4.PE\L#YiW:[Yfu2>QC-/dW-UM$FWN4p=e[3?r:ia[BIk3lR$>+&Q!F,s$1pcblAeMkHL[rb=o%tn;6!*gU:^V;W)KG#_(npu1Y[[MheU:JY@kqff2/i8GkT^QC"W!o?r*^ +endstream +endobj +48 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 47 0 R +>> +endobj +49 0 obj +<< /Length 2768 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +GatU6=c_;s&q9:ViPuGT@3e_5bYp8gDmJ$>Oa&Q^D!qICdBPU8jH8MJqVP(G,fM7AXELfR!ed1J-gMtI2sZr7pW4ln=g2)uDM$E*RrB+XT5YN7!J"?@;@#`-*YXO)/LC[4eKmB2>lO`/bV44OLk7[6*irn@VcOd*$b0@eJX/qOa?8dirDZ3`GQ]5T42GK>1R%])?,GeWN8Q'ElLSUd-=);a!tD+Q2Ok@@BYB@c7GY)s#bN=:D`]3s$pD$C7N#9:?jb[7um]g)jHYZZ1j+\Sp!&U*nq.8&8Bn&7T4GfnK+nJq--+oP7p'KJF;=3!$j&6`.poU%esm\C[pS[\3+e"/^g_P>nI\l!:qen*BZH$DV`j(F$]4F,\iY/RZ4-&&C3F=,SUO)#"Y`.k!R2VsI2HeB6^3mmS/4&g'<8&'l9T]KqBc"S/t)SeB(R%D")T6,+meN@#71=R!ZZ4,n)oVEu-A;_85,-4*""[5^PmVDn$TJB175CiLcnCd*5kqCD6ii4`$+uKJ;(Oup@t3QZFf%m3!37-hGN9'(NrgV#BLLfdkTk5l;g0#*Ae0oO>iE)*H['/%(`aSD]9#6a[LcGbBKarZ`N6u`k\#cSUP""#_MV:"4TBEu(ERPdALZT-mM17LkmA?oP#0@9_uJLJpb#N#i2-So8%or4;%XZfutC26ruZY<+4#>&T15r!8a_UaF#:r^Fi<Ne%K"26K)(_391ORijFX#M`DK,SE31/WMY$:P5E(Xu'/6k(u;J.[ncI#Z&uJ#[5"_P`\gdqtrHkuso2"Qg^nFa>7I^7IAL?8/%S-5qsS)\/7jgThX/[tW:BlPU=";:*p)0nA6dI%GEEY]iaF!uo]7U]dRO,,qNtcKaC0='VuR1.-\dlaKekdYKBcW2KWhP4W#P'#">DTR]sl++r$L(QUV3"0Y&YO6I&^HVj,:fQF_&E"9k\+&'gk>13+j2Q"+sWEgVh5LZiPCCH!M/5o:lBWcU4NeX^UWN84V])CV!i;/sPdOhOep/Xq_*Q9spHSXMQaahLX%E-P^VS82%Fn;=]V%TACkr\bHI;.&4Gp=-FkK`_T8K(i4*rBS?gFuBi/L(5pgJF!K_5DtNrR)r!5iM+F@ZV%-nBKF6%'hukm0gEu"c)$Ql;5rr*8iU!@5n?0lCN84BS.*mBV1Ec+(5ui5?F]`3QN0-g^!FA0A4LHak'lGah(,?$nJ!//Eohi9Vc&0W4s0BS?Ac?u,H'Tg!lZ;M-r^XO8Gf)BD$Nl#F$nFo<]RS`I]5P![nVI='!s#^)uY/s@(Lc0TW!#,bb:t>]bP2:MX49WBK"Y%8c-IABA_:ISh.9Y'u$mR+q7?mY+N"Z\XBij]f"BJ0UYl/2%:N==Ps38Kdsp+eR;EVH`=W5m4Z5.L,&o0j$A9%I*U:ZhOU2VG?=["p=hm1qj![eT?p2CN.n#a,A51@hI#GJ>jtP)oIt:3UW:8H<1,OP=tq*_EMYCJ%d3`Fl.?I1%_djW,MnDng?ejo:Nm`fKC@4J`HA]Rg\^2~> +endstream +endobj +50 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 49 0 R +>> +endobj +51 0 obj +<< /Length 1863 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gat=,=`<%S&:Vs/&GhUk0eJPLqj(]\VMjgcgDVIU9cn&*NeGKJX!:C=rJj9<4KP?p+pak;aI+47VE\nBf%6UN1%N$&m`bFnc`lTM+8.DY!K?sk`AI9HHgf"#bNnT5>ELa21nmk2S[1AdJM/5I`jiQA8k*a$loJCrQ0/ZRcj]P4o.Tb1)HQPS'cp6I;R*r+qVN?.iGU0HK)CjSfX<>JE87pGIGYBe#HT"F9Y1Nl9nTWGh32IDuIF>BHq[W#=K>O$.r>c4Q[N>gt;ri@Pk%7P,nI58uc`5iH%H).XV4c!;,K;4$g%jHMSeD9qu]8Kgd:,M."e42>m\,9S%iG(2@&;`su^fC,aMXM__G^aA1FN#)R"u=/Z7OHGq,SP=@b1[TLD1H2'cQ(5"?e7QPo#`;rGG='!f)5XEgJU#"8%1,H*mC6O,"ehs=WWaD5bB`0u3scPlo\5lA$.qHLjFsf6]^0_Ir$CbgZ"[^.uHEO`aWfcF#>nQ2bS0-Ot_FcKdWYJnNdII:r+m):tP8QLFd8:qT_LTc#!Lj$Yti,<8I#PWXhgcC5EVWc1.U7K!S]?'E^H5AQIH`)Z,&%\M#IFMs>sahJ>*Zb>s4&N[H>+rAoT!TE`<(dMo1%5)Oao0gKb9EG-r3n%h,u2DBk9Q@]Jf/R:TBcP?j>Z7V4Q$Fq>T/2q.l7eVC2ag??1J/=J5p:F-$>lri;/BWPRrr;p(dAa;NO,)Tlt)0#Ul"J$\f0f+fqsbniR6-O[/>0g3(<@JLTKc^q1,&".SSaS3P%('FE+D41Q)=;brk,aC`&JqR"Q;KCe2Gm#t^#+LqG#?;iD>]:F!g!`#lUs1/dPr]%\=XgV0c[I*G+rZ@ZaW@3Ertf5NpUXQAfXG-+D'DrM5P)Lo%F][p!Rm\cbgK(2d'2"X.NPs=i^=>na5XV9l,$l;@S#DjZ";qZ?6?.Y.==W`^FiW%u42s+'J_``a2#MNm\S@m`So8*SeFokmHJ&PT?jlk#Te@7\t"VdeVnMF*n-laQoGtLisWB];a7)brA@kHq0f<_+M~> +endstream +endobj +52 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 51 0 R +>> +endobj +53 0 obj +<< /Length 2286 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +GauHMgN)=4&q0LUYl$>\*C0f6hBl%,1YHncZ;,5tY,hst65"&^Os-LGq!Y\;"e(`/ATqq50BrWrctINnDU:>#Mt`-f5;-7SF%Sf41]I7J"f2fNSWLF93h13b4ei#a4mLPFq0;GI`QdCOr_;at,^'sh$Q#&,j2)m\W(0Dn3C+Vu092RAcM@F`Y"Y*Sp3!7)86KlnCSg3.RI#.'cpDAV0t1c=6m\"uS29.(,g1E\0UXYDQiN);IUk@*T*P)lVQ_%9&(fD%6C?CA6iM%1ClrA(:(`$;q>(-Q*jaNI_KFT&^'U;V_)fL]RZ#-'kT8.e"bhZ\ahnShQgQOl`lt4.V[H5f/4_7.$mCB/[a>=e9-!QIW'\aQ,Ba9Z"ULj&qc,N4fhcVojlk/rfd7R6L=qA&*_q$^bRWp,;g*ZEDCE`4_[QWli;E9F]MJXoGN4dU&h5UD^C^Q*iIa4KE!bNZT%RGeEL!]n-)*G*RKiO"r@!p;rOVPYn[J/9"f,Y*/uB,H%igg7.Hj6`.=^9$1*OM7]o&Q>`e*:t@%!?4eE10=7$f@=XoqM7)p9^R!'\hqlU2%4(T+c[*QB8k$uI!!X#+!_aj79=pgO!QLV(O]mI^]@:CC^L_u8TopAVtpVn;g:f8I9NCA49EHh:R_'SN.7r6;Wm=#Z+FZ)7mb%Ua[AAb,e''Gpr0>fqo=,?cuO&eZVFsG9[a9n^'#:LghDj<t\#8KOnMKN`9**TXp0[D6ueuPS&nJ5*RXo).9ZE7U\\k59,Y-il;IG!Z-)cmOD>Nd#Wea?TG++?/fk:7[hj_dFi0ceK&/Gc-QKMaQ-$3CM6,:Kc%(8r>1LX;\+oP@IrFVN]1k2KnLEVEJg]B+!tKg.8TU_q\[:#j4gg`>?eiMCEOKI`'DKmWEttKPe,u,R?Zc$1%?\7-ja'Y*jB]6aU9=+;>1$eUp$XSa+5*1`sVt.7KX/aN?LE>>9g(*\rg1Kbk=ASoGD-,f\/k"b:,H`.FY3JU)≫RrbK-hu'k3/ljj@bNEso3ehA<)f+sG0.(Zj/-ClRe>jolD;&s?',n*@2WK:8*^)8<`9L+4Yr$61r[2Trd&-cnCij!'5k7ql>)f(pVj$d>gN"KM%-gpo!,-Nre$>jl`M#Z_O.WoYi`VOM\TF+bt[B7p`.mB#uJ2q3#=1loh%!fkZ>^a?i.O=;FjV8gDihj9-=Tm]B(m##]&*B+m^r3gRAIZe?:5nLJlbRo]g:TWh+m+LohH'8Dn"3?s!Pn6#k^$k'L6rksa[2kkXGpb/+=RU$-fclZXW79XUo2pG+Y@aGa_J5?7R6ti#\]HVDk,C7;eOcd;E<,O[F24P!1>R=qQsJ;_FY_(4$%Tl6Sb41X:5-;"X.6jDo:Y,_4fiMk16*qq)(9Y2"d8FMB`rOj@qO>^p2_EaA%:h:(r"CVJ/Z^bd,jc=bV*&&8hp5Q`+UpfOb&7Hq,%do@]Y3WS\U^9n.PGrRsk!oHSC02H0e>SnDD-5^56jI^duo^![;f@CTq!u9F#iHZk>$"G%)peUVVB_+cfBH?],'ct>#i'Gt/-]`rg/GA=<+`73\EnqUf60ha^!W/[uO=mT8R"B!dI38%R56sPGi](s`i]#i&m_WT^$1M"9_c4\r00JqVm\?,:T3hsX:lN:";'!%EhN[Mm$(?*&^:i\f\.9`HCegC$l/0"D#^u~> +endstream +endobj +54 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 53 0 R +>> +endobj +55 0 obj +<< /Length 2266 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +GauHM99\*g%)2U?BQE?T-g"%Nb=YQUG;DgZG26*+e"J)Ak,]Va8?K5u^rkUs[Qe,8ppR35QLek#'BP6fj@rWiJU_+I+m70(S\L`g]>a+/iq(#58`4kKQlc9R]CQ*=)WI_fnX/r&[ucppk4D$WT=Cd#E?7lTLju,c;UZKWGg4h"!h0I4l^"N_N7FDHh<^E3u"PJTHrSV.-0`-H]":(K-Yl[5I&lE6UfFURrB&HY+]gnp67P'friADtO&/:Y5eJL/GC);.5^I<,Cf@g2sP]7nKT"WFF2=E/D]nJ\.oV\)SWn0`A`C6)L;5Mc`?f7Cqe\2C9XYBJ#(:a[f:O/jiu'I.l[Zgq:W@hifM)E0]&pFKBpF#',UH)6Bk:p77V_0?EaZ%Q;tbd.(Hg7_[Z,9`=>s_))+HZRX.',cshL\80b1#ZrSm0^q`kQL.Fge"6Ve;-'TNmM*FIDdjQFC0p=:Yd!os/;%"h:3/N^C?;R(8j[,7tWFqMe8^od8:jm1eS*&S3k@7L9(C%T:/J`t`3s:c8:f"L(+U-08GXcLB)IitPZa8`[6a?KLX?E2Sl>U8`h4Lfh5>4VDC]'\"*Opd*bT2a!6s\O:^9LNkphBs8)Ymf7!nBFf\MV]uf0bfI0GA8(bd?XX7chLX]i/Gi)IG:qnYO>#u?*CRN(AfUa1+rk5\+_iZ2=$B3id9*Xp-&/iOpPW67Dr.;/k?&3)c;D)P8Hp+>.UX]p5,k^kRYki@Dd`s2I-`++[1nXn?ZUN0sU&H.1[u(AI6%Ja?((&V_9Wsa^9\\W328k:8PX[>C\+Q";3Y31B%@pD27sWLledoIO1SjYA809B$bub5n&h8)MTDN7H^DMABY\iDQ:q/]WJ6oN2AEJICp/8CG^P5K*3C1]d+pa49Z`)[8Ck\u#S*]un>J)\[CAlDuPpr_=2W,tH][iYYX3ZZ!V4?JcJ7,(!ABir1J,$MEDEqJrrZrUSFfod;q$OEK(G^FGcMgg]:TREsVLPfu(T8@E:VNSO,q/7V/J@4h0''LE7n9jNXo.dnd4XZ%pOsDQu-"6[Wg@k!3l"(mN7$YR9;#anGlmn1_5@6.!b4JF&>*cK96uWu^TKUo>H/EK/&DhN(ER37*rWNXd111~> +endstream +endobj +56 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 55 0 R +>> +endobj +57 0 obj +<< /Length 2805 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gat%&=``U]&q9SY;!#etA\eMcF5Ja0]qsE)Z"%XI[c0Eb+saE[OU;V5]YAob"@/V'MK3H>3Z.Y>-q"U17JG7+:5Y%cb4G0[R4QJW]PXTf_\0fn_Dq'TL4OOsD:]_B9%eWpC`ND<9,kLLjEFU21,?='JA5"V`^0@Rh2%8`.ugegHA#J%$!S)bY]3V+,*"Lr.!!1j]2I'\APWd/I&_[]BXR"I1Y`?J[^XhFXsW`6H4RdnPP,/_:_oQ/?6k00m['Se#n]J$+6fA?LL;<1WkqiHVl!F_-AfbM0aP]$gPo/UW(59*Vh-4%]%V3`7t%,j)S.;X-(_=W6lU"Fpo]-MRdem.68J*;NaE.t_TaATDbrX]97(U[AXh>R6=o6Tn<9%&R;@Jr>^0!Yds>t3[Y`co0\IK'5t?WTI@B43Gh0/'A5I`C;q?Cnk@aGm8;;R##9Us^VS>QsMgEk!V((lPja--LeG3#6mOT:rEPP2bV:`g]-6ik\"u&)rgu<1W&NO`a9>h#$jFVlj_)UMf`/kc<7b%DZUTE.N>K+#QrBTosuUU(f+`c'ZSFPP(I=YFf_/3f&0nkK;Cl'?[UNnqM<@l!ojb(s.GGImuhQf-&h\&/aYl7E%&a\58`X5q5RC3F[`cr.)%rdCM5o>NYPm%9a+ZT%p$_b)so+1OjTaeY9S;hP>pZLnrbBil$T^L='u(qLZ!(Zk-r]"Z2="lF_Pckcr99=[NR.dAL6>$&7TS#R4`!7fbMo24$K)^>BGUK=V8Q<`qI7+;7J`.u+LCn%?Lo5?58#7+Q^Q#]5s$B=8OAB+lTu[dqdN4#'2rW)q)6rR`LPA]@q<=0\,_&jO82B!r*,;"ZBFD1"U9bZ8ak#),l5+@'3f")pXc3UDX4,+ERA&:#Nr;f&>]O$-6""cInf)2#SD"R-n<&?A/Epb25?4c#c<7h#:SbKM+60`?bU`=/(SH+euD^pe[[Y_[,[bO#;?RYm^+YM-YiHP^:=N&pYnh=lAUU4*L;%C)g($'5Q""pZi8JUffnjZ)5'nnpNtORUV$1]Iftc-l?,g!,%;'*B^ga>:OQ1DUjSIOLgl)F*1lZceZ$sOjr(JQr9e;/q^Faf5!TKIqV'_5VYZc/!&rM5Xi*0FYh:'XFdP_B!g`VM^cOg(I5[rNO5<^Mj?qt=T1jl:E0Oe=!63&:%kBuA7s.q\.6$nNZ1-?&$VmT;q7sbU3biag[b9Q)8L##ud[c\!t&o:Ohb.@@aTq'W0a$L*Dc[RPB=>nPDRb_ZspiT41aVa,OT1+7KeQ'*bQ27LV+39d=++]E[JX,[L0r9KnnL/?7#9!U"]>mF"`(N?)RQ9g1sJXRbU`HD%#23pee1P%fDI")%h>03n_\iP3:N#7G5=emufe)#dP6a_,.Q'""S%@"2SKac9V(9OVJ_6?Nu(?3b\@`'@e4CD-YKO[?\=!)u)k#dc-:#-iEr8cerPJ)[lY>>uWF-[!r\LU0t]+UYc,-gj6I.igIPgZ81K0':7ed+9nHDuM9JC_WkM"OeV@J]StVY(0P:$YAj"A0gkLR`TYZ4Y^trRjln3cZcB#Dk_dZB'`d:2'r#=FJ/Z50WlWSP?0Y4#)j,$#"WKVpKn2rnjf2r5A2Y^Y*,RnEh5ZRc>dR/%$laeSFLSL6<8V*g)Y-RO1cW@(pg2^=/-qd/;4ABg(VAO$dE\WTR]1BdPE^foL[ba[IF`^Dhrd0JK+=BOE+a+8ub`#6~> +endstream +endobj +58 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 57 0 R +>> +endobj +59 0 obj +<< /Length 2326 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gatm>k5,1=3ArH>M2qskMR0Wc>=i::JPCWFW4BiN+5L6OeS?gFQq-_1"@qTn1/I^"?JPXOqkRu;8T0Vd,P_7\'Cn0X#;p&9`RC;q"1iT)EU0MiA\g%2ff&etEdBh,#-19iKi$=6Jo2HUR+qh1X)>Ve'.btB#k#IOeTm/!S]S'*F\GB7/5)HACo&eg(;RcP:XAi.6dbMrCSti.%.g<#>=-l\3Oq<'N&kW5m#rUHJ%mBCA@D2\4<.2%nhlRt4O!XM";nab`NBB.\7D!@+rD#I-#jZjcC-*aDAOMQaT[0P+`O$2b(,?c9Lm(5FLclquq#-gr$--=;'qG\;7#/0-Gh+W<_C@Eru"ra4K!7O:D#,tJSa:K)nChP7%frJQ]gT:/4pXE?Dju4p,PTo(L^$um*%L9>?4Ru8buZ>H24?=\Lfj^82eb.S89:"<2[2Fu&X8\.R`g8:`d\5hfO>#*a=50-*l%qT::M2TNh@irt3j1-h*Qd_)Y9YQIM0'pp]?!g83Rq5#sjHqc[TeALd6`S'-]0KJom7W>ui:Y05oDW=Q\$js-fof5[$+0o#qB$7ON=fLD@tLM"mDB^3fJNqYKlslhRUUDdPV:Sek>JipgGPIHoQ"N=Pe>V^.:849-9/obD-2r7?9:?X6sNJH,)q^A=V=lM_jc&'eVs7"N,OD2-X)HLYsGLY@6a5H0-@b0,=N-H,3h(\3jjk)DLs/9/H5u??0QkRm"1FK3_co$f6"oC8!^\!3\nIja1!n4+CC26-,dT!b4YG76,<^U[=$$+]MQ/ldrEaHm_/"Z9XO7:Y'JLsOfX[J3Ku9%<=DPk(ss5K2ApF'qT,2T'E^P&6J@PAX,FUldYHNYR!WKkui;QrY[VPBA/Z,BlRcUoP:)?8aLEG>31*.nN':D:lm`hafWj5K[lX!^!Gs$S`l">6qHe"Ul)f".X!9*`--l+,tXjT:$5]BEIe(7tQcUer&5%2WIa2'jcS3s5Z[aAfdSB9kk7oqX/3I!6i^(JW=QEc#^)+JU+s!4*4jer +endstream +endobj +60 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 59 0 R +>> +endobj +61 0 obj +<< /Length 2733 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gat%%968iI'#+6EkVdULc1"GIkEJXu235t!2HET=4[:8*V*U79Ba_;QMeDlJK'rE4:.Li[f`n[pSr<-a!Y=%+'fjhlZmagAF]KjCK.oBD#o8De8nDFLQL@Q3X6L]qd^UGi/,LE=q#%p+75:lkW_MAWU"p;)n+roYtg,pCH`e7/jZ_`K>3P370J8oW1umdMjdIh``YJ#ug#[-q6lO\PbZ-+C"$S2c5/D]KaqUe0^$I.7E7R&NeBZ7s1n%e.[))!Nht+2G!K;J3L3D6h[6A#9@?un'Q1;ITNi0M>aF:[DPasm%06+FFNt`S1fcM5@'%1<[QDo(SUQ(RL2Tl`oQ#shmp>ShR0ne?L'H\+d-(2@I;>,Y?Pka]V2C?Kh$>_^*L53Hu_;fXWa+gHYjR/!ZXP(c<34BSc.:1n1BIB9=^?G>ZP.l8?-s=Y]G3=f:`*4'?^Y,sQ+pl+A/Bq%P1b!IB&,\MiGpQYF&A70r8>)'FQq]=,Vo^u$3,7>25R`N/];N95]kp)AhcDOYmZsG#)Okc3KRDpqf_NZG5P2>mdrjX;&pZp#V*+Xld"><>I_;T'.t2dEXL39k@3$Q!)"SDkIY/*@T+J]t*$*eV>3lB($`U5eJPk\#S"%0i(VUm(V)`(Nl!edZ%C1d16lICQ=-n$gZor%i)`gGh>l?S0JQ-2.Z)8tAK'W$Suc#U'mI%T!FAUomh@Mf$pn8gdnjT@XZ.?7F!RTGEZKHGD#*$4\=EGC$5rkM<<0`)PhUZ5li1#uGg]@;\;dBBajq%,ZaI2i9$KG;4LfsDP2m08D(Z?EPq-o,H*QK^)GR*C%8T\qC..(&Nru6b#^90A6?K_`t/gbdP4\UE[&hZQKVXA(WK9PJkPNWD&fPHd#Gn1=s)=n#7PZkG'#\NfYX6J/$mOuT@SYUOmVQmSMe0#`BY<=fs^\uU(5sfF.-&eRC12L1uAS)A:lEt`F6W;!&"G!'JDVAKu*/j+J5*PB5)8lWA'MA)[6d:[OHu5S.TNmo19/CFbZ<7Mh$k6K^;NqsR%_e]q81L;bo.7"T<<3.#PeA/t`b<_&A_(O[Cg5RMYL>;4N_kUZV2,RbLZm)RH`SH7*2*n+dYs>((pmosF4WMt&GjgfI0CU&]-Jm("j&0?SAPc12*WTu-aUd'&Ob2dWp7P=h\US`"IT?c:XS'cRZFs,K#I5=E'(fpX6m"d)T&d!$.,)EVQb%1dWPM2Zh\Xe1KY>K.tb]r)IF3/\Ob0hf99<)L1GUXr;=>l[V`7q078,7Xm),eebHqEW#YX4"=eVJW#2Xr?-Bp_D]1]]-Wo85)IZN/>X0@R;HW$eYSiQn>nT5P;%a#qpft$bgp@gmE,8WfL.sJdAdOp7A$S`gqP^2o`WkOcXhAH?Q?V?-mR8i@%pL7U+h221:n^I;>>C%fl23B.=#`L:d/G*8pjQZHD=>H,X#AO=d:7-S:mTqmcC\i-3_aV\4`8JpKo]9`]S?\A33%EHLL[6NjLM__5Q;S@KU.(+5>;,lJnSaM?+q5o=GGEl?f4aTf,N*GZ)W)e#C^CM3%13]B't>,bq5j)Vk[Ch1ipu&R6$@r)V*,3S[U:J;%a+s&o`6V&Gj2j[!60Al(-Y%E2\uc+#b?(i=0Yak!Y15Lju84V#+!\\F9WaYH_qXQmCD'VX+Ec)(pe>&#GU]'Z;1VB/6"`9`g0lr$g!3p#Bk-1s8eJsYO`AbO+2DCI!#tjeLOOQRfRRn'(RA%OBa3khfdiJ`$l@Qk"47V-2TLEf"a9ome90o$cY3_pL7q-U*+t$VV@GXblFDn#kGdg1AZ=.Vt61"ofG&@Ni@3utUR.LKf0m3:#n@mL'Hq(aP\mK:GaOHp3ZlCl24CC`Bl;OMj(08l*duN#2_U2Ro1"4t(R-o`BdcB,ML,sQ5RJKF_bQZUWR"B+ND=YS,(u6tC)G=tR^"ZuLXp9Go4Uj+QYZeD+F')_N]m964lq/Mt$;32LhpFZ"rQ$-G`.4"lm!aCo!ug?MRaRC'PTWbS"9]S5nFH*@39"'ZK^KpeNmn".D<5q+~> +endstream +endobj +62 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 61 0 R +>> +endobj +63 0 obj +<< /Length 1541 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gat%#997gc&AJ$CkdUY&XsE;c>EeJ!.FJ:b)JFYu#HgI!7.kLEC*3I>,>g9X[!&!o0:pKG_r3O-qSR2lI2dN!5^[LZhtZ&:'6l]g!\]@W!)l*0.8@K]j8FJh3G[;/l%Jg&m(0D'HZ'f+-T@T%US`jTU_$OnVP$6O2Lm]b;A$_+\[s8W.&@CXTfir-6)^]"Ro'A][L;*0.AdU2-T=8)RBCKq$o\q`I:;q1p^MW>Eqn^AB2LHLC/ZIr.C9*5+=(8/M28]PnW$O.q3-XD55t-V6N,:0GkAtSXWnPM7pQ!cZG[I`>+B:k^3*L8=Y\]i&*eg[`l^TYp6=Qn]%N'`^on!_C0fh:V$tE/*8$U?RS.Vb]eT%V'@6JA*5oQ`c6WZKk],b+V*@o>&[+DZ99"s/;0o\a'6@WFg.#hVqLMuLsG^9Gdi>Xi*LO#HOb2AnLceHW=k>`BpWGpq_'nE!\.)p^2Q3HQEHNL:nJ&3,tN.GK`$HJ1;!Bbp24&6#-N;\G9Q5[`8BJ3IZrZiLKYg\'\kjp9_177X$C+-61^R:Oi7=2&&lW\\$hfL?#.*>,O.2RL*n)I?DN_6Iq';&;5+H:hG!W7!HOJD_4,HHZf]porA_&?@B6h+)P5925Au-e"UEYK)nUod0Qke1=^1kVR5Mo0XboG@F'J1oZoi[Pb`b2DIfb0;,q6t-bZX[PKEUcpW5e!"koX2Va!%QO=sY5YYJ2g6N-%.ZHWZ7MM$Se8ZEr/;5+_Ta*lD=4LBjgKoE,Fmp,2~> +endstream +endobj +64 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 612 792 ] +/Resources 3 0 R +/Contents 63 0 R +>> +endobj +65 0 obj +<< /Type /Font +/Subtype /Type1 +/Name /F11 +/BaseFont /Courier-Bold +/Encoding /WinAnsiEncoding >> +endobj +66 0 obj +<< /Type /Font +/Subtype /Type1 +/Name /F1 +/BaseFont /Helvetica +/Encoding /WinAnsiEncoding >> +endobj +67 0 obj +<< /Type /Font +/Subtype /Type1 +/Name /F5 +/BaseFont /Times-Roman +/Encoding /WinAnsiEncoding >> +endobj +68 0 obj +<< /Type /Font +/Subtype /Type1 +/Name /F3 +/BaseFont /Helvetica-Bold +/Encoding /WinAnsiEncoding >> +endobj +69 0 obj +<< /Type /Font +/Subtype /Type1 +/Name /F9 +/BaseFont /Courier +/Encoding /WinAnsiEncoding >> +endobj +70 0 obj +<< /Type /Font +/Subtype /Type1 +/Name /F6 +/BaseFont /Times-Italic +/Encoding /WinAnsiEncoding >> +endobj +71 0 obj +<< /Type /Font +/Subtype /Type1 +/Name /F7 +/BaseFont /Times-Bold +/Encoding /WinAnsiEncoding >> +endobj +1 0 obj +<< /Type /Pages +/Count 17 +/Kids [7 0 R 31 0 R 36 0 R 38 0 R 40 0 R 42 0 R 44 0 R 46 0 R 48 0 R 50 0 R 52 0 R 54 0 R 56 0 R 58 0 R 60 0 R 62 0 R 64 0 R ] >> +endobj +2 0 obj +<< /Type /Catalog +/Pages 1 0 R + >> +endobj +3 0 obj +<< +/Font << /F1 66 0 R /F11 65 0 R /F5 67 0 R /F3 68 0 R /F9 69 0 R /F6 70 0 R /F7 71 0 R >> +/ProcSet [ /PDF /ImageC /Text ] /XObject <> +>> +endobj +11 0 obj +<< +/S /GoTo +/D [36 0 R /XYZ 67.0 725.0 null] +>> +endobj +13 0 obj +<< +/S /GoTo +/D [36 0 R /XYZ 67.0 413.08 null] +>> +endobj +15 0 obj +<< +/S /GoTo +/D [38 0 R /XYZ 67.0 687.6 null] +>> +endobj +17 0 obj +<< +/S /GoTo +/D [40 0 R /XYZ 67.0 560.266 null] +>> +endobj +19 0 obj +<< +/S /GoTo +/D [40 0 R /XYZ 67.0 214.285 null] +>> +endobj +21 0 obj +<< +/S /GoTo +/D [42 0 R /XYZ 67.0 619.4 null] +>> +endobj +23 0 obj +<< +/S /GoTo +/D [42 0 R /XYZ 67.0 285.154 null] +>> +endobj +25 0 obj +<< +/S /GoTo +/D [46 0 R /XYZ 67.0 725.0 null] +>> +endobj +27 0 obj +<< +/S /GoTo +/D [48 0 R /XYZ 67.0 652.4 null] +>> +endobj +29 0 obj +<< +/S /GoTo +/D [60 0 R /XYZ 67.0 661.05 null] +>> +endobj +34 0 obj +<< +/S /GoTo +/D [62 0 R /XYZ 67.0 379.866 null] +>> +endobj +xref +0 72 +0000000000 65535 f +0000144156 00000 n +0000144327 00000 n +0000144377 00000 n +0000000015 00000 n +0000000071 00000 n +0000001144 00000 n +0000103215 00000 n +0000103335 00000 n +0000103430 00000 n +0000103604 00000 n +0000144550 00000 n +0000103741 00000 n +0000144614 00000 n +0000103877 00000 n +0000144679 00000 n +0000104012 00000 n +0000144743 00000 n +0000104148 00000 n +0000144809 00000 n +0000104284 00000 n +0000144875 00000 n +0000104420 00000 n +0000144939 00000 n +0000104555 00000 n +0000145005 00000 n +0000104692 00000 n +0000145069 00000 n +0000104825 00000 n +0000145133 00000 n +0000104959 00000 n +0000105661 00000 n +0000105784 00000 n +0000105811 00000 n +0000145198 00000 n +0000105945 00000 n +0000108848 00000 n +0000108956 00000 n +0000111400 00000 n +0000111508 00000 n +0000114766 00000 n +0000114874 00000 n +0000117795 00000 n +0000117903 00000 n +0000118832 00000 n +0000118940 00000 n +0000121190 00000 n +0000121298 00000 n +0000123083 00000 n +0000123191 00000 n +0000126052 00000 n +0000126160 00000 n +0000128116 00000 n +0000128224 00000 n +0000130603 00000 n +0000130711 00000 n +0000133070 00000 n +0000133178 00000 n +0000136076 00000 n +0000136184 00000 n +0000138603 00000 n +0000138711 00000 n +0000141537 00000 n +0000141645 00000 n +0000143279 00000 n +0000143387 00000 n +0000143499 00000 n +0000143607 00000 n +0000143717 00000 n +0000143830 00000 n +0000143936 00000 n +0000144047 00000 n +trailer +<< +/Size 72 +/Root 2 0 R +/Info 4 0 R +>> +startxref +145264 +%%EOF diff --git a/doc/modsecurity2-data-formats.xml b/doc/modsecurity2-data-formats.xml new file mode 100644 index 0000000..e8eb70d --- /dev/null +++ b/doc/modsecurity2-data-formats.xml @@ -0,0 +1,979 @@ + + +
+ ModSecurity 2 Data Formats + + Version 2.5.10-dev1 (March 24, 2009) + + 2004-2009 + Breach Security, Inc. (http://www.breach.com) + + + The purpose of this document is to describe the formats of the ModSecurity alert messages, + transaction logs and communication protocols, which would not only allow for a better + understanding what ModSecurity does but also for an easy integration with third-party tools + and products. +
+ Alerts + As part of its operations ModSecurity will emit alerts, which are either + warnings (non-fatal) or errors (fatal, + usually leading to the interception of the transaction in question). Below is an example + of a ModSecurity alert entry: + Access denied with code 505 (phase 1). Match of "rx + ^HTTP/(0\\\\.9|1\\\\.[01])$" against "REQUEST_PROTOCOL" required. + [id "960034"] [msg "HTTP protocol version is not allowed by policy"] + [severity "CRITICAL"] [uri "/"] [unique_id "PQaTTVBEUOkAAFwKXrYAAAAM"] + + Alerts will only ever contain one line of text but we've broken the above example + into multiple lines to make it fit into the page. + + Each alert entry begins with the engine message, which describes what ModSecurity did + and why. For + example:Access denied with code 505 (phase 1). Match of "rx + ^HTTP/(0\\\\.9|1\\\\.[01])$" against "REQUEST_PROTOCOL" required. +
+ Alert Action Description + The first part of the engine message tells you whether ModSecurity acted to + interrupt transaction or rule processing: + + + If the alert is only a warning, the first sentence will simply say + Warning. + + + If the transaction was intercepted, the first sentence will begin with + Access denied. What follows is the list of possible + messages related to transaction interception: + + + Access denied with code %0 - a response with + status code %0 was sent. + + + Access denied with connection close - + connection was abruptly closed. + + + Access denied with redirection to %0 using status + %1 - a redirection to URI %0 was + issued using status %1. + + + + + There is also a special message that ModSecurity emits where an allow action is executed. There are three variations of this + type of message: + + + Access allowed - rule engine stopped + processing rules (transaction was unaffected). + + + Access to phase allowed - rule engine stopped + processing rules in the current phase only. Subsequent phases will + be processed normally. Transaction was not affected by this rule but + it may be affected by any of the rules in the subsequent + phase. + + + Access to request allowed - rule engine + stopped processing rules in the current phase. Phases prior to + request execution in the backend (currently phases 1 and 2) will not + be processed. The response phases (currently phases 3 and 4) and + others (currently phase 5) will be processed as normal. Transaction + was not affected by this rule but it may be affected by any of the + rules in the subsequent phase. + + + + +
+
+ Alert Justification Description + The second part of the engine message explains why the alert + was generated. Since it is automatically generated from the rules it will be very + technical in nature, talking about operators and their parameters and give you + insight into what the rule looked like. But this message cannot give you insight + into the reasoning behind the rule. A well-written rule will always specify a + human-readable message (using the msg action) to provide further + information. + The format of the second part of the engine message depends on whether it was + generated by the operator (which happens on a match) or by the rule processor (which + happens where there is not a match, but the negation was used): + + + @beginsWith - String match %0 at + %1. + + + @contains - String match %0 at + %1. + + + @containsWord - String match %0 at + %1. + + + @endsWith - String match %0 at + %1. + + + @eq - Operator EQ matched %0 at + %1. + + + @ge - Operator GE matched %0 at + %1. + + + @geoLookup - Geo lookup for %0 succeeded at + %1. + + + @inspectFile - File %0 rejected by the + approver script %1: %2 + + + @le - Operator LE matched %0 at + %1. + + + @lt - Operator LT matched %0 at + %1. + + + @rbl - RBL lookup of %0 succeeded at + %1. + + + @rx - Pattern match %0 at + %1. + + + @streq - String match %0 at + %1. + + + @validateByteRange - Found %0 byte(s) in %1 + outside range: %2. + + + @validateDTD - XML: DTD validation + failed. + + + @validateSchema - XML: Schema validation + failed. + + + @validateUrlEncoding + + + Invalid URL Encoding: Non-hexadecimal digits used at + %0. + + + Invalid URL Encoding: Not enough characters at the end + of input at %0. + + + + + @validateUtf8Encoding + + + Invalid UTF-8 encoding: not enough bytes in character at + %0. + + + Invalid UTF-8 encoding: invalid byte value in character + at %0. + + + Invalid UTF-8 encoding: overlong character detected at + %0. + + + Invalid UTF-8 encoding: use of restricted character at + %0. + + + Invalid UTF-8 encoding: decoding error at + %0. + + + + + @verifyCC - CC# match %0 at + %1. + + + Messages not related to operators: + + + When SecAction directive is processed - + Unconditional match in SecAction. + + + When SecRule does not match but negation is used - + Match of %0 against %1 required. + + + + The parameters to the operators @rx and @pm (regular expression and text pattern, respectively) will be + truncated to 252 bytes if they are longer than this limit. In this case the + parameter in the alert message will be terminated with three dots. + +
+
+ Meta-data + The metadata fields are always placed at the end of the alert entry. Each metadata + field is a text fragment that consists of an open bracket followed by the metadata + field name, followed by the value and the closing bracket. What follows is the text + fragment that makes up the id metadata field. + [id "960034"] + The following metadata fields are currently used: + + + offset - The byte offset where a match occured within + the target data. This is not always available. + + + id - Unique rule ID, as specified by the id action. + + + rev - Rule revision, as specified by the rev action. + + + msg - Human-readable message, as specified by the + msg action. + + + severity - Event severity as text, as specified by the + severity action. The possible values (with their + corresponding numberical values in brackets) are EMERGENCY (0), ALERT (1), CRITICAL (2), ERROR (3), WARNING (4), NOTICE (5), INFO (6) and DEBUG (7). + + + unique_id - Unique event ID, generated + automatically. + + + uri - Request URI. + + + logdata - contains transaction data fragment, as + specified by the logdata action. + + +
+
+ Escaping + ModSecurity alerts will always contain text fragments that were taken from + configuration or the transaction. Such text fragments escaped before they are user + in messages, in order to sanitise the potentially dangerous characters. They are + also sometimes surrounded using double quotes. The escaping algorithm is as + follows: + + Characters 0x08 (BACKSPACE), + 0x0a (NEWLINE), 0x10 (CARRIAGE RETURN), 0x09 (HORIZONTAL TAB) and 0x0b (VERTICAL TAB) will be + represented as \b, \n, \r, \t and \v, + respectively. + + + Bytes from the ranges 0-0x1f and 0x7f-0xff (inclusive) will be represented as \xHH, where HH is the hexadecimal + value of the byte. + + + Backslash characters (\) will be represented as + \\. + + + Each double quote character will be represented as \", but only if the entire fragment is surrounded with + double quotes. + + +
+
+ Alerts in the Apache Error Log + Every ModSecurity alert conforms to the following format when it appears in the + Apache error log: + [Sun Jun 24 10:19:58 2007] [error] [client 192.168.0.1] + ModSecurity: ALERT_MESSAGE + The above is a standard Apache error log format. The ModSecurity: + prefix is specific to ModSecurity. It is used to allow quick + identification of ModSecurity alert messages when they appear in the same file next + to other Apache messages. + The actual message (ALERT_MESSAGE in the example above) is in + the same format as described in the Alerts section. + + Apache further escapes ModSecurity alert messages before writing them to the + error log. This means that all backslash characters will be doubled in the error + log. In practice, since ModSecurity will already represent a single backslash + within an untrusted text fragment as two backslashes, the end result in the + Apache error log will be four backslashes. Thus, if you + need to interpret a ModSecurity message from the error log, you should decode + the message part after the ModSecurity: prefix first. This + step will peel the first encoding layer. + +
+
+ Alerts in Audit Logs + Alerts are transported in the H section of the ModSecurity + Audit Log. Alerts will appear each on a separate line and in the order they were + generated by ModSecurity. Each line will be in the following format: + Message: ALERT_MESSAGE + Below is an example of an H section that contains two alert + messages: + --c7036611-H-- +Message: Warning. Match of "rx ^apache.*perl" against + "REQUEST_HEADERS:User-Agent" required. [id "990011"] [msg "Request + Indicates an automated program explored the site"] [severity "NOTICE"] +Message: Warning. Pattern match "(?:\\b(?:(?:s(?:elect\\b(?:.{1,100}?\\b + (?:(?:length|count|top)\\b.{1,100}?\\bfrom|from\\b.{1,100}?\\bwhere) + |.*?\\b(?:d(?:ump\\b.*\\bfrom|ata_type)|(?:to_(?:numbe|cha)|inst)r))|p_ + (?:(?:addextendedpro|sqlexe)c|(?:oacreat|prepar)e|execute(?:sql)?| + makewebt ..." at ARGS:c. [id "950001"] [msg "SQL Injection Attack. + Matched signature: union select"] [severity "CRITICAL"] +Stopwatch: 1199881676978327 2514 (396 2224 -) +Producer: ModSecurity v2.x.x (Apache 2.x) +Server: Apache/2.x.x + +--c7036611-Z-- +
+
+
+ Audit Log + ModSecurity records one transaction in a single audit log file. Below is an + example: + --c7036611-A-- +[09/Jan/2008:12:27:56 +0000] OSD4l1BEUOkAAHZ8Y3QAAAAH 209.90.77.54 64995 + 80.68.80.233 80 +--c7036611-B-- +GET //EvilBoard_0.1a/index.php?c='/**/union/**/select/**/1,concat(username, + char(77),password,char(77),email_address,char(77),info,char(77),user_level, + char(77))/**/from/**/eb_members/**/where/**/userid=1/*http://kamloopstutor. + com/images/banners/on.txt? HTTP/1.1 +TE: deflate,gzip;q=0.3 +Connection: TE, cslose +Host: www.example.com +User-Agent: libwww-perl/5.808 + +--c7036611-F-- +HTTP/1.1 404 Not Found +Content-Length: 223 +Connection: close +Content-Type: text/html; charset=iso-8859-1 + +--c7036611-H-- +Message: Warning. Match of "rx ^apache.*perl" against + "REQUEST_HEADERS:User-Agent" required. [id "990011"] [msg "Request + Indicates an automated program explored the site"] [severity "NOTICE"] +Message: Warning. Pattern match "(?:\\b(?:(?:s(?:elect\\b(?:.{1,100}?\\b + (?:(?:length|count|top)\\b.{1,100}?\\bfrom|from\\b.{1,100}?\\bwhere) + |.*?\\b(?:d(?:ump\\b.*\\bfrom|ata_type)|(?:to_(?:numbe|cha)|inst)r))|p_ + (?:(?:addextendedpro|sqlexe)c|(?:oacreat|prepar)e|execute(?:sql)?| + makewebt ..." at ARGS:c. [id "950001"] [msg "SQL Injection Attack. + Matched signature: union select"] [severity "CRITICAL"] +Stopwatch: 1199881676978327 2514 (396 2224 -) +Producer: ModSecurity v2.x.x (Apache 2.x) +Server: Apache/2.x.x + +--c7036611-Z-- + + The file consist of multiple sections, each in different format. Separators are used + to define sections: + --c7036611-A-- + A separator always begins on a new line and conforms to the following format: + + + Two dashes + + + Unique boundary, which consists from several hexadecimal characters. + + + One dash character. + + + Section identifier, currently a single uppercase letter. + + + Two trailing dashes. + + + Refer to the documentation for SecAuditLogParts for the explanation + of each part. +
+ Parts + This section documents the audit log parts available in ModSecurity 2.x. They are: + + A - audit log header + + + B - request headers + + + C - request body + + + D - intended response headers (NOT + IMPLEMENTED) + + + E - intended response body + + + F - response headers + + + G - response body (NOT + IMPLEMENTED) + + + H - audit log trailer + + + I - reduced multipart request + body + + + J - multipart files information + (NOT IMPLEMENTED) + + + K - matched rules + information + + + Z - audit log footer + + +
+ Audit Log Header (<literal>A</literal>) + ModSecurity 2.x audit log entries always begin with the header part. For + example: + --c7036611-A-- +[09/Jan/2008:12:27:56 +0000] OSD4l1BEUOkAAHZ8Y3QAAAAH 209.90.77.54 64995 + 80.68.80.233 80 + The header contains only one line, with the following information on + it: + + + Timestamp + + + Unique transaction ID + + + Source IP address (IPv4 or IPv6) + + + Source port + + + Destination IP address (IPv4 or IPv6) + + + Destination port + + +
+
+ Request Headers (<literal>B</literal>) + The request headers part contains the request line and the request headers. + The information present in this part will not be identical to that sent by the + client responsible for the transaction. ModSecurity 2.x for Apache does not have + access to the raw data; it sees what Apache itself sees. While the end result + may be identical to the raw request, differences are possible in some + areas: + + + If any of the fields are NUL-terminated, Apache + will only see the content prior to the NUL. + + + Headers that span multiple lines (feature known as header folding) + will be collapsed into a single line. + + + Multiple headers with the same name will be combined into a single + header (as allowed by the HTTP RFC). + + +
+
+ Request Body (<literal>C</literal>) + This part contains the request body of the transaction, after dechunking and + decompression (if applicable). +
+
+ Intended Response Headers (<literal>D</literal>) + This part contains the status line and the request headers that would have + been delivered to the client had ModSecurity not intervened. Thus this part + makes sense only for transactions where ModSecurity altered the data flow. By + differentiating before the intended and the final response headers, we are able + to record what was internally ready for sending, but also what was actually + sent. + + This part is reserved for future use. It is not implemented in ModSecurity + 2.x. + +
+
+ Intended Response Body (<literal>E</literal>) + This part contains the transaction response body (before compression and + chunking, where used) that was either sent or would have been sent had + ModSecurity not intervened. You can find whether interception took place by + looking at the Action header of the part H. If that header is present, and the interception took place in + phase 3 or 4 then the E part contains the intended response + body. Otherwise, it contains the actual response body. + + Once the G (actual response body) part is implemented, + part E will be present only in audit logs that contain a + transaction that was intercepted, and there will be no need for further + analsys. + +
+
+ Response Headers (<literal>F</literal>) + This part contains the actual response headers sent to the client. Since + ModSecurity 2.x for Apache does not access the raw connection data, it + constructs part F out of the internal Apache data structures + that hold the response headers. + Some headers (the Date and Server + response headers) are generated just before they are sent and ModSecurity is not + able to record those. You should note than ModSecurity is working as part of a + reverse proxy, the backend web server will have generated these two servers, and + in that case they will be recorded. +
+
+ Response Body (G) + When implemented, this part will contain the actual response body before + compression and chunking. + + This part is reserved for future use. It is not implemented in ModSecurity + 2.x. + +
+
+ Audit Log Trailer (H) + Part H contains additional transaction meta-data that was + obtained from the web server or from ModSecurity itself. The part contains a + number of trailer headers, which are similar to HTTP headers (without support + for header folding): + + Action + + + Apache-Error + + + Message + + + Producer + + + Response-Body-Transformed + + + Sanitised-Args + + + Sanitised-Request-Headers + + + Sanitised-Response-Headers + + + Server + + + Stopwatch + + + WebApp-Info + + +
+ Action + The Action header is present only for the transactions + that were intercepted: + Action: Intercepted (phase 2) + The phase information documents the phase in which the decision to + intercept took place. +
+
+ Apache-Error + The Apache-Error header contains Apache error log messages observed by + ModSecurity, excluding those sent by ModSecurity itself. For example: + Apache-Error: [file "/tmp/buildd/apache2-2.0.54/build-tree/apache2/server/ + core.c"] [line 3505] [level 3] File does not exist: /var/www/www. + modsecurity.org/fst/documentation/modsecurity-apache/2.5.0-dev2 +
+
+ Message + Zero or more Message headers can be present in any + trailer, and each such header will represent a single ModSecurity warning or + error, displayed in the order they were raised. + The example below was broken into multiple lines to make it fit this + page: + Message: Access denied with code 400 (phase 2). Pattern match "^\w+:/" at + REQUEST_URI_RAW. [file "/etc/apache2/rules-1.6.1/modsecurity_crs_20_ + protocol_violations.conf"] [line "74"] [id "960014"] [msg "Proxy access + attempt"] [severity "CRITICAL"] [tag "PROTOCOL_VIOLATION/PROXY_ACCESS"] +
+
+ Producer + The Producer header identifies the product that + generated the audit log. For example: + Producer: ModSecurity for Apache/2.5.5 (http://www.modsecurity.org/). + ModSecurity allows rule sets to add their own signatures to the Producer information (this is done using the SecComponentSignature directive). Below is an example of the + Producer header with the signature of one component + (all one line): + Producer: ModSecurity for Apache/2.5.5 (http://www.modsecurity.org/); + MyComponent/1.0.0 (Beta). +
+
+ Response-Body-Transformed + This header will appear in every audit log that contains a response + body: + Response-Body-Transformed: Dechunked + The contents of the header is constant at present, so the header is only + useful as a reminder that the recorded response body is not identical to the + one sent to the client. The actual content is the same, except that Apache + may further compress the body and deliver it in chunks. +
+
+ Sanitised-Args + The Sanitised-Args header contains a list of arguments + that were sanitised (each byte of their content replaced with an asterisk) + before logging. For example: + Sanitised-Args: "old_password", "new_password", "new_password_repeat". +
+
+ Sanitised-Request-Headers + The Sanitised-Request-Headers header contains a list of + request headers that were sanitised before logging. For example: + Sanitised-Request-Headers: "Authentication". +
+
+ Sanitised-Response-Headers + The Sanitised-Response-Headers header contains a list + of response headers that were sanitised before logging. For example: + Sanitised-Response-Headers: "My-Custom-Header". +
+
+ Server + The Server header identifies the web server. For + example: + Server: Apache/2.0.54 (Debian GNU/Linux) mod_ssl/2.0.54 OpenSSL/0.9.7e + This information may sometimes be present in any of the parts that contain + response headers, but there are a few cases when it isn't: + + None of the response headers were recoreded. + + + The information in the response headers is not accurate + because server signature masking was used. + + +
+
+ Stopwatch + The Stopwatch header provides certain diagnostic + information that allows you to determine the performance of the web server + and of ModSecurity itself. It will typically look like this: + Stopwatch: 1222945098201902 2118976 (770* 4400 -) + Each line can contain up to 5 different values. Some values can be absent; + each absent value will be replaced with a dash. + The meanings of the values are as follows (all values are in + microseconds): + + Transaction timestamp in microseconds since January 1st, + 1970. + + + Transaction duration. + + + The time between the moment Apache started processing the + request and until phase 2 of ModSecurity began. If an asterisk + is present that means the time includes the time it took + ModSecurity to read the request body from the client (typically + slow). This value can be used to provide a rough estimate of the + client speed, but only with larger request bodies (the smaller + request bodies may arrive in a single TCP/IP packet). + + + The time between the start of processing and until phase 2 was + completed. If you substract the previous value from this value + you will get the exact duration of phase 2 (which is the main + rule processing phase). + + + The time between the start of request processing and util we + began sending a fully-buffered response body to the client. If + you substract this value from the total transaction duration and + divide with the response body size you may get a rough estimate + of the client speed, but only for larger response bodies. + + +
+
+ WebApp-Info + The WebApp-Info header contains information on the + application to which the recorded transaction belongs. This information will + appear only if it is known, which will happen if SecWebAppId was set, or setsid or setuid executed in the transaction. + The header uses the following format: + WebApp-Info: "WEBAPPID" "SESSIONID" "USERID" + Each unknown value is replaced with a dash. +
+
+
+ Reduced Multipart Request Body (<literal>I</literal>) + Transactions that deal with file uploads tend to be large, yet the file + contents is not always relevant from the security point of view. The I part was designed to avoid recording raw multipart/form-data request bodies, replacing them with a + simulated application/x-www-form-urlencoded body that + contains the same key-value parameters. + The reduced multipart request body will not contain any file information. The + J part (currently not implemented) is intended to carry + the file metadata. +
+
+ Multipart Files Information (<literal>J</literal>) + The purpose of part J is to record the information on the + files contained in a multipart/form-data request body. This + is handy in the cases when the original request body was not recorded, or when + only a reduced version was recorded (e.g. when part I was + used instead of part C). + + This part is reserved for future use. It is not implemented in ModSecurity + 2.x. + +
+
+ Matched Rules (<literal>K</literal>) + The matched rules part contains a record of all ModSecurity rules that matched + during transaction processing. You should note that if a rule that belongs to a + chain matches then the entire chain will be recorded. This is because, even + though the disruptive action may not have executed, other per-rule actions have, + and you will need to see the entire chain in order to understand the + rules. + This part is available starting with ModSecurity 2.5.x. +
+
+ Audit Log Footer (<literal>Z</literal>) + Part Z is a special part that only has a boundary but no + content. Its only purpose is to signal the end of an audit log. +
+
+
+ Storage Formats + ModSecurity supports two audit log storage formats: + + Serial audit log format - multiple audit log + files stored in the same file. + + + Concurrent audit log format - one file is used + for every audit log. + + +
+ Serial Audit Log Format + The serial audit log format stores multiple audit log entries within the same + file (one after another). This is often very convinent (audit log entries are + easy to find) but this format is only suitable for light logging in the current + ModSecurity implementation because writing to the file is serialised: only one + audit log entry can be written at any one time. +
+
+ Concurrent Audit Log Format + The concurrent audit log format uses one file per audit log entry, and allows + many transactions to be recorded at once. A hierarchical directory structure is + used to ensure that the number of files created in any one directory remains + relatively small. For example: + $LOGGING-HOME/20081128/20081128-1414/20081128-141417- + egDKy38AAAEAAAyMHXsAAAAA + The current time is used to work out the directory structure. The file name is + constructed using the current time and the transaction ID. + The creation of every audit log in concurrent format is recorded with an entry + in the concurrent audit log index file. The format of each + line resembles the common web server access log format. For example: + 192.168.0.111 192.168.0.1 - - [28/Nov/2008:15:06:32 +0000] + "GET /?p=\\ HTTP/1.1" 200 69 "-" "-" NOfRx38AAAEAAAzcCU4AAAAA + "-" /20081128/20081128-1506/20081128-150632-NOfRx38AAAEAAAzcCU4AAAAA + 0 1183 md5:ffee2d414cd43c2f8ae151652910ed96 + The tokens on the line are as follows: + + + Hostname (or IP address, if the hostname is not known) + + + Source IP address + + + Remote user (from HTTP Authentication) + + + Local user (from identd) + + + Timestamp + + + Request line + + + Response status + + + Bytes sent (in the response body) + + + Referrer information + + + User-Agent information + + + Transaction ID + + + Session ID + + + Audit log file name (relative to the audit logging home, as configured + using the SecAuditLogStorageDir directive) + + + Audit log offset + + + Audit log size + + + Audit log hash (the has begins with the name of the algorithm used, + followed by a colon, followed by the hexadecimal representation of the + hash itself); this hash can be used to verify that the transaction was + correctly recorded and that it hasn't been modified since. + + + + Lines in the index file will be up to 3980 bytes long, and the information + logged will be reduced to fit where necessary. Reduction will occur within + the individual fields, but the overall format will remain the same. The + character L will appear as the last character on a + reduced line. A space will be the last character on a line that was not + reduced to stay within the limit. + +
+
+
+ Transport Protocol + Audit logs generated in multi-sensor deployments are of little use if left on the + sensors. More commonly, they will be transported to a central logging server using + the transport protocol described in this section: + + + The transport protocol is based on the HTTP protocol. + + + The server end is an SSL-enabled web server with HTTP Basic Authentication + configured. + + + Clients will open a connection to the centralisation web server and + authenticate (given the end-point URI, the username and the + password). + + + Clients will submit every audit log in a single PUT + transaction, placing the file in the body of the request and additional + information in the request headers (see below for details). + + + Server will process each submission and respond with an appropriate status + code: + + + 200 (OK) - the submission was processed; the client can delete the + corresponding audit log entry if it so desires. The same audit log + entry must not be submitted again. + + + 409 (Conflict) - if the submission is in invalid format and cannot + be processed. The client should attempt to fix the problem with the + submission and attempt delivery again at a later time. This error is + generally going to occur due to a programming error in the protocol + implementation, and not because of the content of the audit log + entry that is being transported. + + + 500 (Internal Server Error) - if the server was unable to + correctly process the submission, due to its own fault. The client + should re-attempt delivery at a later time. A client that starts + receiving 500 reponses to all its submission should suspend its + operations for a period of time before continuing. + + + + + + Server implementations are advised to accept all submissions that correctly + implement the protocol. Clients are unlikely to be able to overcome problems + within audit log entries, so such problems are best resolved on the server + side. + + + When en error occurs, the server may place an explanation of the problem in + the text part of the response line. + +
+ Request Headers Information + Each audit log entry submission must contain additional information in the + request headers: + + + Header X-Content-Hash must contain the audit log + entry hash. Clients should expect the audit log entries to be validated + against the hash by the server. + + + Header X-ForensicLog-Summary must contain the + entire concurrent format index line. + + + The Content-Lenght header must be present and + contain the length of the audit log entry. + + +
+
+
+
diff --git a/modsecurity.conf-minimal b/modsecurity.conf-minimal new file mode 100644 index 0000000..bc78d2f --- /dev/null +++ b/modsecurity.conf-minimal @@ -0,0 +1,60 @@ + +# Basic configuration options +SecRuleEngine On +SecRequestBodyAccess On +SecResponseBodyAccess Off + +# Handling of file uploads +# TODO Choose a folder private to Apache. +# SecUploadDir /opt/apache-frontend/tmp/ +SecUploadKeepFiles Off + +# Debug log +SecDebugLog logs/modsec_debug.log +SecDebugLogLevel 0 + +# Serial audit log +SecAuditEngine RelevantOnly +SecAuditLogRelevantStatus ^5 +SecAuditLogParts ABIFHZ +SecAuditLogType Serial +SecAuditLog logs/modsec_audit.log + +# Maximum request body size we will +# accept for buffering +SecRequestBodyLimit 131072 + +# Store up to 128 KB in memory +SecRequestBodyInMemoryLimit 131072 + +# Buffer response bodies of up to +# 512 KB in length +SecResponseBodyLimit 524288 + +# Verify that we've correctly processed the request body. +# As a rule of thumb, when failing to process a request body +# you should reject the request (when deployed in blocking mode) +# or log a high-severity alert (when deployed in detection-only mode). +SecRule REQBODY_PROCESSOR_ERROR "!@eq 0" \ +"phase:2,t:none,log,deny,msg:'Failed to parse request body.',severity:2" + +# By default be strict with what we accept in the multipart/form-data +# request body. If the rule below proves to be too strict for your +# environment consider changing it to detection-only. You are encouraged +# _not_ to remove it altogether. +SecRule MULTIPART_STRICT_ERROR "!@eq 0" \ +"phase:2,t:none,log,deny,msg:'Multipart request body \ +failed strict validation: \ +PE %{REQBODY_PROCESSOR_ERROR}, \ +BQ %{MULTIPART_BOUNDARY_QUOTED}, \ +BW %{MULTIPART_BOUNDARY_WHITESPACE}, \ +DB %{MULTIPART_DATA_BEFORE}, \ +DA %{MULTIPART_DATA_AFTER}, \ +HF %{MULTIPART_HEADER_FOLDING}, \ +LF %{MULTIPART_LF_LINE}, \ +SM %{MULTIPART_SEMICOLON_MISSING}, \ +IQ %{MULTIPART_INVALID_QUOTING}'" + +# Did we see anything that might be a boundary? +SecRule MULTIPART_UNMATCHED_BOUNDARY "!@eq 0" \ +"phase:2,t:none,log,deny,msg:'Multipart parser detected a possible unmatched boundary.'" diff --git a/rules/CHANGELOG b/rules/CHANGELOG new file mode 100644 index 0000000..aabe69b --- /dev/null +++ b/rules/CHANGELOG @@ -0,0 +1,419 @@ +-------------------------- +ModSecurity JIRA CHANGELOG +-------------------------- +https://www.modsecurity.org/tracker/browse/CORERULES?report=com.atlassian.jira.plugin.system.project:changelog-panel + +-------------------------- +Version 2.0.3 - 11/05/2009 +-------------------------- + +Improvements: +- Updated converted PHPIDS signatures (https://svn.php-ids.org/svn/trunk/lib/IDS/default_filter.xml) +- Create a new PHPIDS Converter rules file (https://svn.php-ids.org/svn/trunk/lib/IDS/Converter.php) +- Added new rules to identify multipart/form-data bypass attempts +- Increased anomaly scoring (+100) for REQBODY_PROCESSOR_ERROR alerts + +Bug Fixes: +- Added t:urlDecodeUni transformation function to phpids rules to fix both false positives/negatives + https://www.modsecurity.org/tracker/browse/CORERULES-17 +- Added new variable locations to the phpids filters + https://www.modsecurity.org/tracker/browse/CORERULES-19 +- Use of transformation functions can cause false negatives - added multiMatch action to phpids rules + https://www.modsecurity.org/tracker/browse/CORERULES-20 +- Fixed multipart parsing evasion issues by adding strict parsing rules + https://www.modsecurity.org/tracker/browse/CORERULES-21 +- Fixed typo in xss rules (missing |) + https://www.modsecurity.org/tracker/browse/CORERULES-22 +- Fixed regex text in IE8 XSS filters (changed to lowercase) + https://www.modsecurity.org/tracker/browse/CORERULES-23 + +-------------------------- +Version 2.0.2 - 09/11/2009 +-------------------------- + +Improvements: +- Added converted PHPIDS signatures (https://svn.php-ids.org/svn/trunk/lib/IDS/default_filter.xml) + https://www.modsecurity.org/tracker/browse/CORERULES-13 + +Bug Fixes: +- Rule 958297 - Fixed Comment SPAM UA false positive that triggered only on mozilla. + https://www.modsecurity.org/tracker/browse/CORERULES-15 + +-------------------------- +Version 2.0.1 - 08/07/2009 +-------------------------- + +Improvements: +- Updated the transformation functions used in the XSS/SQLi rules to improve performance + https://www.modsecurity.org/tracker/browse/CORERULES-10 + +- Updated the variable/target list in the XSS rules + https://www.modsecurity.org/tracker/browse/CORERULES-11 + +- Added XSS Filters from IE8 + https://www.modsecurity.org/tracker/browse/CORERULES-12 + +Bug Fixes: +- Rule 958297 - Fixed unescaped double-quote issue in Comment SPAM UA rule. + https://www.modsecurity.org/tracker/browse/CORERULES-9 + +-------------------------- +Version 2.0.0 - 07/29/2009 +-------------------------- + +New Rules & Features: +- Fine Grained Policy + The rules have been split to having one signature per rule instead of having + all signatures combined into one optimized regular expression. + This should allow you to modify/disable events based on specific patterns + instead of having to deal with the whole rule. +- Converted Snort Rules + Emerging Threat web attack rules have been converted. + http://www.emergingthreats.net/ +- Anomaly Scoring Mode Option + The rules have been updated to include anomaly scoring variables which allow + you to evaluate the score at the end of phase:2 and phase:5 and decide on what + logging and disruptive actions to take based on the score. +- Correlated Events + There are rules in phase:5 that will provide some correlation between inbound + events and outbound events and will provide a result of successful atttack or + attempted attack. +- Updated Severity Ratings + The severity ratings in the rules have been updated to the following: + - 0: Emergency - is generated from correlation where there is an inbound attack and + an outbound leakage. + - 1: Alert - is generated from correlation where there is an inbound attack and an + outbound application level error. + - 2: Critical - is the highest severity level possible without correlation. It is + normally generated by the web attack rules (40 level files). + - 3: Error - is generated mostly from outbound leakabe rules (50 level files). + - 4: Warning - is generated by malicious client rules (35 level files). + - 5: Notice - is generated by the Protocol policy and anomaly files. + - 6: Info - is generated by the search engine clients (55 marketing file). +- Updated Comment SPAM Protections + Updated rules to include RBL lookups and client fingerprinting concepts from + Bad Behavior (www.bad-behavior.ioerror.us) +- Creation of Global Collection + Automatically create a Global collection in the *10* config file. Other rules + can then access it. +- Use of Block Action + Updated the rules to use the "block" action. This allows the Admin to globally + set the desired block action once with SecDefaultAction in the *10* config file + rather than having to edit the disruptive actions in all of the rules or for + the need to have multiple versions of the rules (blocking vs. non-blocking). +- "Possible HTTP Parameter Pollution Attack: Multiple Parameters with the same Name." + http://tacticalwebappsec.blogspot.com/2009/05/http-parameter-pollution.html +- Added new generic RFI detection rules. + http://tacticalwebappsec.blogspot.com/2009/06/generic-remote-file-inclusion-attack.html +- "Possibly malicious iframe tag in output" (Rules 981001,981002) + Planting invisible iframes in a site can be used by attackers to point users + from the victim site to their malicious site. This is actually as if the + user was visiting the attacker's site himself, causing the user's browser to + process the content in the attacker's site. + +New Events: +- Rule 960019 - Expect Header Not Allowed. +- Rule 960020 - Pragma Header Requires Cache-Control Header +- Rule 958290 - Invalid Character in Request - Browsers should not send the (#) character + as it is reserved for use as a fragment identifier within the html page. +- Rule 958291 - Range: field exists and begins with 0. +- Rule 958292 - Invalid Request Header Found. +- Rule 958293 - Lowercase Via Request Header Found. +- Rule 958294 - Common SPAM Proxies found in Via Request Header. +- Rule 958295 - Multiple/Conflicting Connection Header Data Found. +- Rule 958296 - Request Indicates a SPAM client accessed the Site. +- Rule 958297 - Common SPAM/Email Harvester crawler. +- Rule 958298 - Common SPAM/Email Harvester crawler + +Bug Fixes: +- Rule 950107 - Split the rule into 2 separate rules to factor in the + Content-Type when inspecting the REQUEST_BODY variable. +- Rule 960017 - Bug fix for when having port in the host header. +- Rule 960014 - Bug fix to correlate the SERVER_NAME variable. +- Rule 950801 - Increased the logic so that the rule will only run if the web site + uses UTF-8 Encoding. +- Rules 999210,999211 - Bug fix to move ctl actions to last rule, add OPTIONS and + allow the IPv6 loopback address +- Rule 950117 - Updated the RFI logic to factor in both a trailing "?" in the ARG + and to identify offsite hosts by comparing the ARG URI to the Host + header. Due to this rule now being stronger, moved it from optional + tight security rule to *40* generic attacks file. + +Other Fixes: +- Added more HTTP Protocol violations to *20* file. +- Set the SecDefaultAction in the *10* config file to log/pass (This was the + default setting, however this sets it explicitly. +- Added SecResponseBodyLimitAction ProcessPartial to the *10* config file. This + was added so that when running the SecRuleEngine in DetectionOnly mode, it will + not deny response bodies that go over the size restrictions. +- Changed SecServerSignature to "Apache/1.3.28" +- Fixed the use of SkipAfter and SecMarkers to make it consistent. Now have + BEGIN and END SecMarkers for rule groups to more accurately allow moving to + proper locations. +- Fixed the @pm/@pmFromFile pre-qualifier logic to allow for operator inversion. + This removes the need for some SecAction/SkipAfter rules. +- Updated rule formatting to easily show rule containers (SecMarkers, pre-qualifier + rules and chained rules). + +-------------------------- +Version 1.6.1 - 2008/04/22 +-------------------------- + +- Fixed a bug where phases and transformations where not specified explicitly + in rules. The issue affected a significant number of rules, and we strongly + recommend to upgrade. + +-------------------------- +Version 1.6.0 - 2008/02/19 +-------------------------- + +New Rulesets & Features: +- 42 - Tight Security + This ruleset contains currently 2 rules which are considered highly prone + to FPs. They take care of Path Traversal attacks, and RFI attacks. This + ruleset is included in the optional_rulesets dir +- 42 - Comment Spam + Comment Spam is used by the spammers to increase their rating in search + engines by posting links to their site in other sites that allow posting + of comments and messages. The rules in this ruleset will work against that. + (Requires ModSecurity 2.5) +- Tags + A single type of attack is often detected by multiple rules. The new alert + classification tags solve this issue by providing an alternative alert type + indication and can serve for filtering and analysis of audit logs. + The classification tags are hierarchical with slashes separating levels. + Usually there are two levels with the top level describing the alert group + and the lower level denoting the alert type itself, for example: + WEB_ATTACK/SQL_INJECTION. + +False Positives Fixes: +- Rule 960903 - Moved to phase 4 instead of 5 to avoid FPs +- Rule 950107 - Will look for invalid url decoding in variables that are not + automatically url decoded + +Additional rules logic: +- Using the new "logdata" action for logging the matched signature in rules +- When logging an event once, init the collection only if the alert needs to log +- Using the new operator @pm as a qualifier before large rules to enhance + performance (Requires ModSecurity 2.5) +- SQL injection - A smarter regexp is used to detect 1=1,2=2,etc.. and not + only 1=1. (Thanks to Marc Stern for the idea) +- New XSS signatures - iframe & flash XSS + + +------------------------- +Version 1.5.1 - 2007/12/6 +------------------------- + +False Positives Fixes: +- Protocol Anomalies (file 21) - exception for Apache SSL pinger (Request: GET /) + +New Events: +- 960019 - Detect HTTP/0.9 Requests + HTTP/0.9 request are not common these days. This rule will log by default, + and block in the blocking version of file 21 + +Other Fixes: +- File 40, Rules 950004,950005 - Repaired the correction for the double + url decoding problem +- File 55 contained empty regular expressions. Fixed. + +------------------------ +Version 1.5 - 2007/11/23 +------------------------ + +New Rulesets: +- 23 - Request Limits + "Judging by appearances". This rulesets contains rules blocking based on + the size of the request, for example, a request with too many arguments + will be denied. + +Default policy changes: +- XML protection off by default +- BLOCKING dir renamed to optional_rules +- Ruleset 55 (marketing) is now optional (added to the optional_rules dir) +- Ruleset 21 - The exception for apache internal monitor will not log anymore + +New Events: +- 960912 - Invalid request body + Malformed content will not be parsed by modsecurity, but still there might + be applications that will parse it, ignoring the errors. +- 960913 - Invalid Request + Will trigger a security event when request was rejected by apache with + code 400, without going through ModSecurity rules. + +Additional rules logic: +- 950001 - New signature: delete from +- 950007 - New signature: waitfor delay + +False Positives Fixes: +- 950006 - Will not be looking for /cc pattern in User-Agent header +- 950002 - "Internet Explorer" signature removed +- Double decoding bug used to cause FPs. Some of the parameters are already + url-decoded by apache. This caused FPs when the rule performed another + url-decoding transformation. The rules have been split so that parameters + already decoded by apache will not be decoded by the rules anymore. +- 960911 - Expression is much more permissive now +- 950801 - Commented out entirely. NOTE: If your system uses UTF8 encoding, + then you should uncomment this rule (in file 20) + +-------------------------- +version 1.4.3 - 2007/07/21 +-------------------------- + +New Events: +- 950012 - HTTP Request Smuggling + For more info on this attack: + http://www.cgisecurity.com/lib/HTTP-Request-Smuggling.pdf +- 960912 - Invalid request body + Malformed content will not be parsed by modsecurity, but still there might + be applications that will parse it, ignoring the errors. +- 960913 - Invalid Request + Will trigger a security event when request was rejected by apache with + code 400, without going through ModSecurity rules. + +False Positives Fixes: +- 950107 - Will allow a % sign in the middle of a string as well +- 960911 - A more accurate expression based on the rfc: + http://www.ietf.org/rfc/rfc2396.txt +- 950015 - Will not look for http/ pattern in the request headers + +Additional rules logic: +- Since Apache applies scope directives only after ModSecurity phase 1 + this directives cannot be used to exclude phase 1 rules. Therefore + we moved all inspection rules to phase 2. + + +-------------------------------- +version 1.4 build 2 - 2007/05/17 +-------------------------------- + +New Feature: +- Search for signatures in XML content + XML Content will be parsed and ispected for signatures + +New Events: +- 950116 - Unicode Full/Half Width Abuse Attack Attempt + Full-width unicode can by used to bypass content inspection. Such encoding will be forbidden + http://www.kb.cert.org/vuls/id/739224 +- 960911 - Invalid HTTP request line + Enforce request line to be valid, i.e.: +- 960904 - Request Missing Content-Type (when there is content) + When a request contains content, the content-type must be specified. If not, the content will not be inspected +- 970018 - IIS installed in default location (any drive) + Log once if IIS in installed in the /Inetpub directory (on any drive, not only C) +- 950019 - Email Injection + Web forms used for sending mail (such as "tell a friend") are often manipulated by spammers for sending anonymous emails + +Regular expressions fixes: +- Further optimization of some regular expressions (using the non-greediness operator) + The non-greediness operator, , prevents excessive backtracking + +FP fixes: +- Rule 950107 - Will allow a parameter to end in a % sign from now on + +------------------------ +version 1.4 - 2007/05/02 +------------------------ + +New Events: +- 970021 - WebLogic information disclosure + Matching of "JSP compile error" in the response body, will trigger this rule, with severity 4 (Warning) +- 950015,950910,950911 - HTTP Response Splitting + Looking for HTTP Response Splitting patterns as described in Amit Klein's excellent white paper: + http://www.packetstormsecurity.org/papers/general/whitepaper_httpresponse.pdf +ModSecurity does not support compressed content at the moment. Thus, the following rules have been added: +- 960902 - Content-Encoding in request not supported + Any incoming compressed request will be denied +- 960903 - Content-Encoding in response not suppoted + An outgoing compressed response will be logged to alert, but ONLY ONCE. + +False Positives Fixes: +- Removed <.exe>,<.shtml> from restricted extensions +- Will not be looking for SQL Injection signatures , in the Via request header +- Excluded Referer header from SQL injection, XSS and command injection rules +- Excluded X-OS-Prefs header from command injection rule +- Will be looking for command injection signatures in + REQUEST_COOKIES|REQUEST_COOKIES_NAMES instead of REQUEST_HEADERS:Cookie. +- Allowing charset specification in the Content-Type + +Additional rules logic: +- Corrected match of OPTIONS method in event 960015 +- Changed location for event 960014 (proxy access) to REQUEST_URI_RAW +- Moved all rules apart from method inspection from phase 1 to phase 2 - + This will enable viewing content if such a rule triggers as well as setting + exceptions using Apache scope tags. +- Added match for double quote in addition to single quote for signature (SQL Injection) +- Added 1=1 signature (SQL Injection) + +-------------------------------- +version 1.3.2 build 4 2007/01/17 +-------------------------------- + +Fixed apache 2.4 dummy requests exclusion +Added persistent PDF UXSS detection rule + +-------------------------------- +Version 1.3.2 build 3 2007/01/10 +-------------------------------- + +Fixed regular expression in rule 960010 (file #30) to allow multipart form data +content + +-------------------------- +Version 1.3.2 - 2006/12/27 +-------------------------- + +New events: +- 960037 Directory is restricted by policy +- 960038 HTTP header is restricted by policy + +Regular expressions fixes: +- Regular expressions with @ at end of beginning (for example "@import) +- Regular expressions with un-escaped "." +- Command Injections now always require certain characters both before and after the command. Important since many are common English words (finger, mail) +- The command injection wget is not searched in the UA header as it has different meaning there. +- LDAP Fixed to reduce FPs: + + More accurate regular expressions + + high bit characters not accpeted between signature tokens. +- Do not detect + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/rules/README b/rules/README new file mode 100644 index 0000000..a774441 --- /dev/null +++ b/rules/README @@ -0,0 +1,229 @@ + +============================== +ModSecurity Core Rule Set +============================== + +(c) 2006-2009 Breach Secuiry Inc. + +The ModSecurity Core Rule Set is provided to you under the terms and +conditions of GPL version 2 + +This directory contains the files for Core ModSecurity Rule Set +The rules are compatible with ModSecurity 2.5 (as of version 1.4.3) + + +Overview +======== + +Using ModSecurity requires rules. In order to enable users to take full +advantage of ModSecurity immediately, Breach Security Inc. is providing a free +Core rule set. Unlike intrusion detection and prevention systems which +rely on signature specific to known vulnerabilities, the Core Rule Set +provides generic protection from unknown vulnerabilities often found in web +application that are in most cases custom coded. + +Keep in mind that a predefined rule set is only part of the work required to +protect your web site. We strongly urge you to consult Ivan Ristic's book, +"Apache Security" in order to harden your Apache web server. You may also +consider writing custom rules for providing a positive security envelope to +your application or critical parts of it. Breach Security can provide you with +training and professional services to assist you in doing that. The Core +Rule Set is heavily commented to allow it to be used as a step-by-step +deployment guide for ModSecurity. + +For more information refer to the Core Rule Set page at +http://www.owasp.org/index.php/Category:OWASP_ModSecurity_Core_Rule_Set_Project + +Core Rules Mail-list - +Suscribe here: https://lists.owasp.org/mailman/listinfo/owasp-modsecurity-core-rule-set +Archive: https://lists.owasp.org/pipermail/owasp-modsecurity-core-rule-set/ + +Core Rule Set Structure & Usage +==================================== + +To activate the rules for your web server installation: + + 1) The modsecurity_crs_10_global_config.conf file includes directives that + can only be initiated once by Apache and thus this should be included + within the main httpd.conf file context. + + The modsecurity_crs_10_config.conf, on the other hand, includes directives + that can be included within virtual host containers. Pay attention to + the SecRuleEngine setting (On by default) and that the SecDefaultAction + directive is set to "pass". All of the rules use the "block" action which + inherits this setting. The effectively means that you can toggle the + SecDefaultAction setting to decide if you would like to deny on a rule + match or if you want to run in anomaly scoring/correlation mode (which is + the new default). + + Should also update the appropriate anomaly scoring level in the + modsecurity_crs_49_enforcement.conf and modsecurity_crs_60_correlation.conf + files. This will determine when you log and block events. + + Additionally you may want to edit modsecurity_crs_30_http_policy.conf + which enforces an application specific HTTP protocol usage. + + 2) Add the following line to your httpd.conf (assuming + you've placed the rule files into conf/modsecurity/): + + Include conf/modsecurity/*.conf + Include conf/modsecurity/base_rules/*conf + + 3) Restart web server. + + 4) Make sure your web sites are still running fine. + + 5) Simulate an attack against the web server. Then check + the attack was correctly logged in the Apache error log, + ModSecurity debug log (if you enabled it) and ModSecurity + audit log (if you enabled it). + + 6) If you configured your audit log entries to be transported + to ModSecurity Console in real time, check the alert was + correctly recorded there too. + + +Known Issues +=============== + +Apache requests rejection and phase 2 rules +------------------------------------------- + +Since now all inspection rules are executed in phase 2, several protocol +validation is done by Apache prior to ModSecurity. This is by no means a +security issue as Apache would block the requests, but the alert would appear +in the ModSecurity audit log as a generic event "Invalid Request (960913)" + +Here's a list of the events that modsecurity might not log due to this issue: +- Validate encoding - 950107 + When invalid encoding is found in the URI +- Validate utf-8 encoding - 950801 + When invalid encoding is found in the URI +- Method not allowed by policy - 960032 + When the request uses a method that Apache doesn't know such as: CONNECT, SUBSCRIBE, etc. + + +Google Analytics +---------------- + +For Google Analytics account activation, you will need to disable +the Core Rules temporarily, then enable them after your Google account is +activated. More info can be found in the mod-security-mailing-list: +http://sourceforge.net/mailarchive/message.php?msg_name=1179692394.26994.10.camel%40localhost + + +About Regular Expressions +============================ + +One of the advantages of the Core Rule Set, being a set of text files is your +ability to modify it. However you will find that the regular expressions used +are very complex. + +Since regular expressions are much more efficient if assembled into a single +expression and optimized, a generation script takes a list of patterns that +are required for a rule and optimize them into a most efficient regular +expression. + +We plan to release the optimization script shortly to allow much easier editing +of regular expressions. + + +Core Rule Set Content +========================= + +In order to provide generic web applications protection, the Core Rule Set +uses the following techniques: + +1. HTTP protection - detecting violations of the HTTP protocol and a locally +defined usage policy. + +2. Common Web Attacks Protection - detecting common web application security +attack. + +3. Automation detection - Detecting bots, crawlers, scanners and other surface +malicious activity. + +4. Trojan Protection - Detecting access to Trojans horses. + +5. Errors Hiding - Disguising error messages sent by the server + +In addition the rule set also hints at the power of ModSecurity beyond +providing security by reporting access from the major search engines to your +site. + + +HTTP Protection - This first line of protection ensures that all abnormal HTTP +requests are detected. This line of defense eliminates a large number of +automated and non targeted attacks as well as protects the web server itself. +Common Web Attacks Protection Rules on the second level address the common web +application security attack methods. These are the issues that can appear in +any web application. Some of the issues addressed are: + +- SQL Injection +- Cross-Site Scripting (XSS) +- OS Command execution +- Remote code inclusion +- LDAP Injection +- SSI Injection +- Information leak +- Buffer overflows +- File disclosure + +Automation Detection - Automated clients are both a security risk and a +commercial risk. Automated crawlers collect information from your site, consume +bandwidth and might also search for vulnerabilities on the web site. Automation +detection is especially useful for generic detection of comments spam. + + +Trojan Protection - ModSecurity Core Rule Set detects access to back doors +installed on a web server. This feature is very important in a hosting +environment when some of this backdoors may be uploaded in a legitimate way and +used maliciously. In addition the Core Rule Set includes a hook for adding +an Anti-Virus program such as ClamAV for checking file uploads. + +Errors Hiding - If all fails, the Core Rule Set will detect errors sent by +the web server. Detecting and blocking errors prevents attackers from +collecting reconnaissance information about the web application and also server +as a last line of defense in case an attack was not detected eariler. + + +Few Word of Caution +------------------- + +As with every new technology, using the ModSecurity Core Rule Set requires some caution: + +- Every Rule Set can have false positive in new environments and any new +installation should initially use the log only Rule Set version or if no such +version is available, set ModSecurity to Detection only using the SecRuleEngine +DetectionOnly command. + +After running ModSecurity in a detection only mode for a while review the evens +generated and decide if any modification to the rule set should be made before +moving to protection mode. + +- Freely available wide spread signatures have their down side as attackers may +examine them and find ways to bypass them. Especially note that the automation +detection signatures are relatively easy to evade and should not be viewed as a +security mechanism but only as a "nuisance reduction" mechanism. + + +Road Map +-------- + +This rule set is both young and old. Breach Security has a long experience with +rules and signatures for application security protection and the Core Rule +Set is based on this experience. On the other hand, this is a first cut of a +ModSecurity rule set so your feedback and remarks, either directly or through +the ModSecurity mailing list would be greatly appreciated. + +Going forward we plan to: + +- Utilize ModSecurity 2.0 support for events correlation to detect denial of +service attacks, brute force attacks and attack reconnaissance + +- Add a framework for validating SOAP requests. + +- Add signatures for key known vulnerabilities. + +Anything else you would want? + diff --git a/rules/base_rules/modsecurity_40_generic_attacks.data b/rules/base_rules/modsecurity_40_generic_attacks.data new file mode 100644 index 0000000..a9fe981 --- /dev/null +++ b/rules/base_rules/modsecurity_40_generic_attacks.data @@ -0,0 +1,277 @@ +set-cookie +.cookie +expiressys.user_objects +sys.user_triggers +@@spid +msysaces +instr +sys.user_views +sys.tab +charindex +locate +sys.user_catalog +constraint_type +msysobjects +attnotnull +select +sys.user_tables +sys.user_constraints +sys.user_tab_columns +waitfor +mysql.user +sys.all_tables +msysrelationships +msyscolumns +msysqueriessubstr +xtype +textpos +all_objects +rownum +sysfilegroups +sysprocesses +user_group +sysobjects +systables +user_tables +pg_attribute +column_id +user_password +user_users +attrelid +user_tab_columns +table_name +pg_class +user_constraints +user_objects +object_type +sysconstraints +mb_users +column_name +atttypid +substring +object_id +syscat +sysibm +user_ind_columns +syscolumns +sysdba +object_namexp_enumdsn +insert +infile +autonomous_transaction +nvarchar +openrowset +print +data_type +outfile +castb +shutdown +inner +tbcreator +xp_filelist +@@version +sql_longvarchar +sp_prepare +xp_regenumkeys +xp_dirtree +xp_loginconfig +ifnull +sp_addextendedproc +xp_regaddmultistring +delete +sp_sqlexec +sp_oacreate +sp_execute +xp_ntsec +xp_regdeletekey +drop +xp_execresultset +varchar +dba_users +to_number +having +xp_regenumvalues +utl_file +xp_terminate +xp_availablemedia +xp_regdeletevalue +sql_variant +dumpfile +isnull +'sa' +select +xp_regremovemultistring +xp_makecab +xp_cmdshell +'msdasql' +sp_executesql +openquery +'sqloledb' +'dbo' +sp_makewebtask +utl_http +dbms_java +benchmark +xp_regread +xp_regwritejscript +onsubmit +copyparentfolder +javascript +meta +onchange +onmove +onkeydown +onkeyup +activexobject +onerror +onmouseup +ecmascript +bexpression +onmouseover +vbscript: +Index of +>
+Index ofMicrosoft VBScript runtime (0x8 +error '800 +Application uses a value of the wrong type for the current operation +Microsoft VBScript compilation (0x8 +Microsoft VBScript compilation error +Microsoft .NET Framework Version: +A trappable error occurred in an external object. The script cannot continue running +rror +Microsoft VBScript runtime Error +>error 'ASP +ADODB.Command +Object required: ' +<b>Version Information:</b> does not match with a table name or alias name used in the query +Either BOF or EOF is True, or the current record has been deleted; the operation +PostgreSQL query failed: +You have an error in your SQL syntax near ' +ORA- +select list because it is not contained in either an aggregate function or the GROUP BY clause +Syntax error converting the +supplied argument is not a valid MS SQL +supplied argument is not a valid Oracle +Unclosed quotation mark before the character string +Warning: mysql_connect(): +Unable to connect to PostgreSQL server: +SQL Server does not exist or access denied +microsoft jet database engine error '8 +supplied argument is not a valid PostgreSQL result +Microsoft OLE DB Provider for +You have an error in your SQL syntax; +Either BOF or EOF is True, or the current record has been deleted +supplied argument is not a valid ODBC +supplied argument is not a valid MySQL +[Microsoft][ODBC +error '800a01b8' + data type as an argument. +select list because it is not contained in an aggregate function and there is no GROUP BY clause +' in sysservers. execute sp_addlinkedserver +incorrect syntax near These statistics were produced by PeLAB +This analysis was produced by +These statistics were produced by getstats +This report was generated by WebLog +ebalizer +This summary was generated byfgets +move_uploaded_file +$_session +ftp_fget +ftp_put +readfile +ftp_nb_put +gzencode +bzopen +fopen +readdir +$_post +gzread +ftp_nb_fput +ftp_nb_fget +ftp_get +$_get +scandir +fscanf +readgzfile +fread +fgetc +proc_open +ftp_fput +fgetss +ftp_nb_get +fwrite +session_start +gzopen +gzcompress +gzwriteserver.urlencode +server.createobject +scripting.filesystemobject +server.execute +wscript.shell +<jsp: +.createtextfile +.addheader +wscript.network +javax.servlet +.loadfromfile +server.mappath +vbscript.encode +server.htmlencode +response.write +response.binarywrite +.getfile diff --git a/rules/base_rules/modsecurity_crs_20_protocol_violations.conf b/rules/base_rules/modsecurity_crs_20_protocol_violations.conf new file mode 100644 index 0000000..4554706 --- /dev/null +++ b/rules/base_rules/modsecurity_crs_20_protocol_violations.conf @@ -0,0 +1,146 @@ +# --------------------------------------------------------------- +# Core ModSecurity Rule Set ver.2.0.3 +# Copyright (C) 2006-2009 Breach Security Inc. All rights reserved. +# +# The ModSecuirty Core Rule Set is distributed under GPL version 2 +# Please see the enclosed LICENCE file for full details. +# --------------------------------------------------------------- + + +# +# TODO in some cases a valid client (usually automated) generates requests that +# violates the HTTP protocol. Create exceptions for those clients, but try +# to limit the exception to a source IP or other additional properties of +# the request such as URL and not allow the violation generally. +# +# + +# Validate request line +# +SecRule REQUEST_LINE "!^(?:(?:[a-z]{3,10}\s+(?:\w{3,7}?://[\w\-\./]*(?::\d+)?)?/[^?#]*(?:\?[^#\s]*)?(?:#[\S]*)?|connect (?:\d{1,3}\.){3}\d{1,3}\.?(?::\d+)?|options \*)\s+[\w\./]+|get /[^?#]*(?:\?[^#\s]*)?(?:#[\S]*)?)$" \ + "t:none,t:lowercase,phase:2,block,nolog,auditlog,status:400,msg:'Invalid HTTP Request Line',id:'960911',severity:'4',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+5,setvar:tx.protocol_violation_score=+1,setvar:'tx.%{rule.id}-PROTOCOL_VIOLATION/INVALID_REQ-%{matched_var_name}=%{matched_var}'" + + +# Block request with malformed content. +# ModSecurity will not inspect these, but the server application might do so +# +SecRule REQBODY_PROCESSOR_ERROR "!@eq 0" "t:none,phase:2,block,nolog,auditlog,status:400,msg:'Request Body Parsing Failed. %{REQBODY_PROCESSOR_ERROR_MSG}',id:'960912',severity:'4',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+100,setvar:tx.protocol_violation_score=+1,setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/INVALID_REQ-%{matched_var_name}=%{matched_var}" + +# By default be strict with what we accept in the multipart/form-data +# request body. If the rule below proves to be too strict for your +# environment consider changing it to detection-only. You are encouraged +# _not_ to remove it altogether. +SecRule MULTIPART_STRICT_ERROR "!@eq 0" \ +"phase:2,t:none,block,nolog,auditlog,msg:'Multipart request body \ +failed strict validation: \ +PE %{REQBODY_PROCESSOR_ERROR}, \ +BQ %{MULTIPART_BOUNDARY_QUOTED}, \ +BW %{MULTIPART_BOUNDARY_WHITESPACE}, \ +DB %{MULTIPART_DATA_BEFORE}, \ +DA %{MULTIPART_DATA_AFTER}, \ +HF %{MULTIPART_HEADER_FOLDING}, \ +LF %{MULTIPART_LF_LINE}, \ +SM %{MULTIPART_SEMICOLON_MISSING}, \ +IQ %{MULTIPART_INVALID_QUOTING}',id:960914,severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+90,setvar:tx.protocol_violation_score=+1,setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/INVALID_REQ-%{matched_var_name}=%{matched_var}" + +# Did we see anything that might be a boundary? +SecRule MULTIPART_UNMATCHED_BOUNDARY "!@eq 0" \ +"phase:2,block,t:none,nolog,auditlog,msg:'Multipart parser detected a possible unmatched boundary.',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.protocol_violation_score=+1,setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/INVALID_REQ-%{matched_var_name}=%{matched_var}" + +# Identify multipart/form-data name evasion attempts +SecRule FILES "['\";=]" "phase:2,block,t:none,nolog,auditlog,msg:'Attempted multipart/form-data bypass',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.protocol_violation_score=+1,setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/INVALID_REQ-%{matched_var_name}=%{matched_var}" +SecRule FILES_NAMES "['\";=]" "phase:2,block,t:none,nolog,auditlog,msg:'Attempted multipart/form-data bypass',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.protocol_violation_score=+1,setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/INVALID_REQ-%{matched_var_name}=%{matched_var}" + +# Accept only digits in content length +# +SecRule REQUEST_HEADERS:Content-Length "!^\d+$" "phase:2,t:none,block,nolog,auditlog,status:400,msg:'Content-Length HTTP header is not numeric', severity:'2',id:'960016',tag:'PROTOCOL_VIOLATION/INVALID_HREQ',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+5,setvar:tx.policy_score=+1,setvar:tx.%{rule.id}-POLICY/IP_HOST-%{matched_var_name}=%{matched_var}" + +# Do not accept GET or HEAD requests with bodies +# HTTP standard allows GET requests to have a body but this +# feature is not used in real life. Attackers could try to force +# a request body on an unsuspecting web applications. +# +SecRule REQUEST_METHOD "^(?:GET|HEAD)$" "chain,phase:2,t:none,block,nolog,auditlog,status:400,msg:'GET or HEAD requests with bodies', severity:'2',id:'960011',tag:'PROTOCOL_VIOLATION/EVASION'" + SecRule REQUEST_HEADERS:Content-Length "!^0?$" "t:none,setvar:'tx.msg=%{rule.msg}',setvar:tx.protocol_violation_score=+1,setvar:tx.anomaly_score=+5,setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/INVALID_HREQ-%{matched_var_name}=%{matched_var}" + +# Require Content-Length to be provided with every POST request. +# +SecRule REQUEST_METHOD "^POST$" "chain,phase:2,t:none,block,nolog,auditlog,status:400,msg:'POST request must have a Content-Length header',id:'960012',tag:'PROTOCOL_VIOLATION/EVASION',severity:'4'" + SecRule &REQUEST_HEADERS:Content-Length "@eq 0" "t:none,setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+5,setvar:tx.protocol_violation_score=+1,setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/INVALID_HREQ-%{matched_var_name}=%{matched_var}" + +# Don't accept transfer encodings we know we don't know how to handle +# +# NOTE ModSecurity does not support chunked transfer encodings at +# this time. You MUST reject all such requests. +# +SecRule REQUEST_HEADERS:Transfer-Encoding "!^$" "phase:2,t:none,block,nolog,auditlog,status:501,msg:'ModSecurity does not support transfer encodings',id:'960013',tag:'PROTOCOL_VIOLATION/EVASION',severity:'4',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+5,setvar:tx.protocol_violation_score=+1,setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/INVALID_HREQ-%{matched_var_name}=%{matched_var}" + +# Expect header is an HTTP/1.1 protocol feature +# +SecRule REQUEST_HEADERS:Expect "100-continue" "chain,phase:2,t:none,nolog,block,auditlog,msg:'Expect Header Not Allowed.',severity:'5',id:'960021',tag:'PROTOCOL_VIOLATION/INVALID_HREQ'" + SecRule REQUEST_PROTOCOL "@streq HTTP/1.0" "setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+5,setvar:tx.protocol_violation_score=+1,setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/INVALID_HREQ-%{matched_var_name}=%{matched_var}" + +# Pragma Header requires a Cache-Control Header +# +SecRule &REQUEST_HEADERS:Pragma "@eq 1" "chain,phase:2,t:none,block,nolog,auditlog,msg:'Pragma Header requires Cache-Control Header for HTTP/1.1 requests.',severity:'5',id:'960020',tag:'PROTOCOL_VIOLATION/INVALID_HREQ'" + SecRule &REQUEST_HEADERS:Cache-Control "@eq 0" "chain" + SecRule REQUEST_PROTOCOL "@streq HTTP/1.1" "setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+5,setvar:tx.protocol_violation_score=+1,setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/INVALID_HREQ-%{matched_var_name}=%{matched_var}" + +# Range Header exists and begins with 0 - normal browsers don't do this. +# +SecRule REQUEST_HEADERS:Range "@contains =0-" "phase:2,t:none,block,nolog,auditlog,msg:'Range: field exists and begins with 0.',severity:'5',id:'958291',tag:'PROTOCOL_VIOLATION/INVALID_HREQ',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+5,setvar:tx.protocol_violation_score=+1,setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/INVALID_HREQ-%{matched_var_name}=%{matched_var}" + +# Broken/Malicous clients often have duplicate or conflicting headers +# +SecRule REQUEST_HEADERS:Connection "\b(keep-alive|close),\s?(keep-alive|close)\b" "phase:2,t:none,block,nolog,auditlog,status:400,msg:'Multiple/Conflicting Connection Header Data Found.',id:'958295',tag:'PROTOCOL_VIOLATION/INVALID_HREQ',severity:'5',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+5,setvar:tx.protocol_violation_score=+1,setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/INVALID_HREQ-%{matched_var_name}=%{matched_var}" + +# Check encodings +SecRule REQUEST_URI "\%(?!$|\W|[0-9a-fA-F]{2}|u[0-9a-fA-F]{4})" \ + "chain,phase:2,t:none,block,nolog,auditlog,status:400,msg:'URL Encoding Abuse Attack Attempt',id:'950107',tag:'PROTOCOL_VIOLATION/EVASION',severity:'5'" + SecRule REQUEST_URI "@validateUrlEncoding" "setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+5,setvar:tx.protocol_violation_score=+1,setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/EVASION-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_HEADERS:Content-Type "^application\/x-www-form-urlencoded(?:;(?:\s?charset\s?=\s?[\w\d\-]{1,18})?)??$" \ + "chain,phase:2,t:none,block,nolog,auditlog,status:400,msg:'URL Encoding Abuse Attack Attempt',id:'950108',tag:'PROTOCOL_VIOLATION/EVASION',severity:'5'" + SecRule REQUEST_BODY "\%(?!$|\W|[0-9a-fA-F]{2}|u[0-9a-fA-F]{4})" "chain" + SecRule REQUEST_BODY "@validateUrlEncoding" "setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+5,setvar:tx.protocol_violation_score=+1,setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/EVASION-%{matched_var_name}=%{matched_var}" + +# Check UTF enconding +# This rule checks to see if your system uses UTF encoding. +SecRule RESPONSE_HEADERS:Content-Type "charset=utf-8" \ + "phase:3,t:none,pass,nolog,setvar:global.utf8_encoding_used=1" + +# If UTF-8 encoding was detected in the server's respone headers, run this rule on inbound data. +SecRule GLOBAL:UTF8_ENCODING_USED "@eq 1" "chain,phase:2,t:none,block,nolog,auditlog,status:400,msg:'UTF8 Encoding Abuse Attack Attempt',id:'950801',tag:'PROTOCOL_VIOLATION/EVASION',severity:'5'" + SecRule REQUEST_URI|REQUEST_BODY|REQUEST_HEADERS|XML:/*|!REQUEST_HEADERS:Referer "@validateUtf8Encoding" "setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+5,setvar:tx.protocol_violation_score=+1,setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/EVASION-%{matched_var_name}=%{matched_var}" + + +# Disallow use of full-width unicode +SecRule REQUEST_URI|REQUEST_BODY|REQUEST_HEADERS|XML:/*|!REQUEST_HEADERS:Referer "\%u[fF]{2}[0-9a-fA-F]{2}" \ + "t:none,phase:2,block,nolog,auditlog,status:400,msg:'Unicode Full/Half Width Abuse Attack Attempt',id:'950116',severity:'5',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+5,setvar:tx.protocol_violation_score=+1,setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/EVASION-%{matched_var_name}=%{matched_var}" + +# Proxy access attempt +# NOTE Apache blocks such access by default if not set as a proxy. The rule is +# included in case Apache proxy is misconfigured. +# NOTE There are some clients (mobile devices) that will send a full URI even when connecting to +# your local application and this rule allows it. +# NOTE Need to have UseCononicalName On in Apache config to properly set the SERVER_NAME variable. +SecRule REQUEST_URI_RAW ^\w+:/ "chain,phase:2,t:none,block,nolog,auditlog,status:400,msg:'Proxy access attempt', severity:'2',id:'960014',tag:'PROTOCOL_VIOLATION/PROXY_ACCESS'" + SecRule MATCHED_VAR "!@beginsWith http://%{SERVER_NAME}" "setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+5,setvar:tx.protocol_violation_score=+1,setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/PROXY_ACCESS-%{matched_var_name}=%{matched_var}" + +# +# Restrict type of characters sent +# +# NOTE In order to be broad and support localized applications this rule +# only validates that NULL Is not used. +# +# The strict policy version also validates that protocol and application +# generated fields are limited to printable ASCII. +# +# TODO If your application use the range 32-126 for parameters. +# +#SecRule REQUEST_FILENAME|REQUEST_HEADERS_NAMES|REQUEST_HEADERS|!REQUEST_HEADERS:Referer \ +# "@validateByteRange 32-126" \ +# "phase:2,block,nolog,auditlog,status:400,msg:'Invalid character in request',id:'960018',tag:'PROTOCOL_VIOLATION/EVASION',severity:'4',t:none,t:urlDecodeUni,setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+5,setvar:tx.protocol_violation_score=+1,setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/EVASION-%{matched_var_name}=%{matchedvar}" + +SecRule ARGS|ARGS_NAMES|REQUEST_HEADERS:Referer "@validateByteRange 1-255" \ + "phase:2,block,nolog,auditlog,status:400,msg:'Invalid character in request',id:'960901',tag:'PROTOCOL_VIOLATION/EVASION',severity:'4',t:none,t:urlDecodeUni,setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+5,setvar:tx.protocol_violation_score=+1,setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/EVASION-%{matched_var_name}=%{matched_var}" diff --git a/rules/base_rules/modsecurity_crs_21_protocol_anomalies.conf b/rules/base_rules/modsecurity_crs_21_protocol_anomalies.conf new file mode 100644 index 0000000..ee12f64 --- /dev/null +++ b/rules/base_rules/modsecurity_crs_21_protocol_anomalies.conf @@ -0,0 +1,73 @@ +# --------------------------------------------------------------- +# Core ModSecurity Rule Set ver.2.0.3 +# Copyright (C) 2006-2009 Breach Security Inc. All rights reserved. +# +# The ModSecuirty Core Rule Set is distributed under GPL version 2 +# Please see the enclosed LICENCE file for full details. +# --------------------------------------------------------------- + + +# +# TODO in some cases a valid client (usually automated) generates requests that +# violates the HTTP protocol. Create exceptions for those clients, but try +# to limit the exception to a source IP or other additional properties of +# the request such as URL and not allow the violation generally. +# + +# Do not accept requests without common headers. +# Implies either an attacker or a legitimate automation client. +# + +# Detect HTTP/0.9 Requests +SecRule REQUEST_PROTOCOL ^HTTP/0.9$ "t:none,phase:2,nolog,auditlog,msg:'HTTP/0.9 Request Detected',id:'960019',severity:'4',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+5,setvar:tx.protocol_violation_score=+1,setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/INVALID_REQ-%{matched_var_name}=%{matched_var}" + +SecMarker BEGIN_HOST_CHECK + + SecRule &REQUEST_HEADERS:Host "@eq 0" \ + "skipAfter:END_HOST_CHECK,phase:2,t:none,nolog,auditlog,msg:'Request Missing a Host Header',id:'960008',tag:'PROTOCOL_VIOLATION/MISSING_HEADER',severity:'5',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+5,setvar:tx.protocol_violation_score=+1,setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/MISSING_HEADER-%{matched_var_name}=%{matched_var}" + SecRule REQUEST_HEADERS:Host "^$" \ + "phase:2,t:none,nolog,auditlog,msg:'Request Missing a Host Header',id:'960008',tag:'PROTOCOL_VIOLATION/MISSING_HEADER',severity:'5',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+5,setvar:tx.protocol_violation_score=+1,setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/MISSING_HEADER-%{matched_var_name}=%{matched_var}" + +SecMarker END_HOST_CHECK + + +SecMarker BEGIN_ACCEPT_CHECK + + SecRule &REQUEST_HEADERS:Accept "@eq 0" \ + "chain,phase:2,t:none,nolog,auditlog,msg:'Request Missing an Accept Header', severity:'2',id:'960015',tag:'PROTOCOL_VIOLATION/MISSING_HEADER'" + SecRule REQUEST_METHOD "!^OPTIONS$" "skipAfter:END_ACCEPT_CHECK,t:none,setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+5,setvar:tx.protocol_violation_score=+1,setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/MISSING_HEADER-%{matched_var_name}=%{matched_var}" + SecRule REQUEST_HEADERS:Accept "^$" \ + "chain,phase:2,t:none,nolog,auditlog,msg:'Request Has an Empty Accept Header', severity:'2',id:'960021',tag:'PROTOCOL_VIOLATION/MISSING_HEADER'" + SecRule REQUEST_METHOD "!^OPTIONS$" "t:none,setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+5,setvar:tx.protocol_violation_score=+1,setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/MISSING_HEADER-%{matched_var_name}=%{matched_var}" + +SecMarker END_ACCEPT_CHECK + +SecMarker BEGIN_UA_CHECK + + SecRule &REQUEST_HEADERS:User-Agent "@eq 0" \ + "skipAfter:END_UA_CHECK,phase:2,t:none,nolog,auditlog,msg:'Request Missing a User Agent Header',id:'960009',tag:'PROTOCOL_VIOLATION/MISSING_HEADER',severity:'5',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+5,setvar:tx.protocol_violation_score=+1,setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/MISSING_HEADER-%{matched_var_name}=%{matched_var}" + SecRule REQUEST_HEADERS:User-Agent "^$" \ + "t:none,nolog,auditlog,msg:'Request Missing a User Agent Header',id:'960009',tag:'PROTOCOL_VIOLATION/MISSING_HEADER',severity:'5',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+5,setvar:tx.protocol_violation_score=+1,setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/MISSING_HEADER-%{matched_var_name}=%{matched_var}" + +SecMarker END_UA_CHECK + + +SecRule &REQUEST_HEADERS:Content-Type "@eq 0" \ + "chain,phase:2,t:none,nolog,auditlog,msg:'Request Containing Content, but Missing Content-Type header',id:'960904',severity:'5'" + SecRule REQUEST_HEADERS:Content-Length "!^0$" "t:none,setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+5,setvar:tx.protocol_violation_score=+1,setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/MISSING_HEADER-%{matched_var_name}=%{matched_var}" + + +# Check that the host header is not an IP address +# +SecRule REQUEST_HEADERS:Host "^[\d.:]+$" "phase:2,t:none,block,nolog,auditlog,status:400,msg:'Host header is a numeric IP address', severity:'2',id:'960017',tag:'PROTOCOL_VIOLATION/IP_HOST',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+5,setvar:tx.policy_score=+1,setvar:tx.%{rule.id}-POLICY/IP_HOST-%{matched_var_name}=%{matched_var}'" + + +# Log a security event when the request is rejected by apache +# +# You must patch mod_unique_id for this to work correctly. See the following +# mod-security-users mail-list post for the patch details - +# http://article.gmane.org/gmane.comp.apache.mod-security.user/5808 +# +SecRule RESPONSE_STATUS ^400$ "t:none,phase:5,chain,nolog,auditlog,pass,msg:'Invalid request',id:'960913',severity:'4'" + SecRule WEBSERVER_ERROR_LOG !ModSecurity "t:none,setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+5,setvar:tx.leakage_score=+1,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" + diff --git a/rules/base_rules/modsecurity_crs_23_request_limits.conf b/rules/base_rules/modsecurity_crs_23_request_limits.conf new file mode 100644 index 0000000..843a303 --- /dev/null +++ b/rules/base_rules/modsecurity_crs_23_request_limits.conf @@ -0,0 +1,69 @@ +# --------------------------------------------------------------- +# Core ModSecurity Rule Set ver.2.0.3 +# Copyright (C) 2006-2009 Breach Security Inc. All rights reserved. +# +# The ModSecuirty Core Rule Set is distributed under GPL version 2 +# Please see the enclosed LICENCE file for full details. +# --------------------------------------------------------------- + + + +# In most cases, you should expect a certain volume of each a request on your +# website. For example, a request with 400 arguments, can be suspicious. +# This file creates limitations on the request. +# TODO Look at the rules in this file, and define the sizes you'd like to enforce. +# Note that most of the rules are commented out by default. +# Uncomment the rules you need +# + +## -- Arguments limits -- + +# Limit argument name length +#SecRule ARGS_NAMES "@gt 100" "phase:2,t:none,t:length,block,nolog,auditlog,status:403,msg:'Argument name too long',id:'960209',severity:'4',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+5,setvar:tx.policy_score=+1,setvar:tx.%{rule.id}-POLICY/SIZE_LIMIT-%{matched_var_name}=%{matched_var}" + +# Limit value name length +#SecRule ARGS "@gt 400" "phase:2,t:none,t:length,block,nolog,auditlog,status:403,msg:'Argument value too long',id:'960208',severity:'4',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+5,setvar:tx.policy_score=+1,setvar:tx.%{rule.id}-POLICY/SIZE_LIMIT-%{matched_var_name}=%{matched_var}" + +# Maximum number of arguments in request limited +SecRule &ARGS "@gt 255" "phase:2,t:none,block,nolog,auditlog,status:403,msg:'Too many arguments in request',id:'960335',severity:'4',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+5,setvar:tx.policy_score=+1,setvar:tx.%{rule.id}-POLICY/SIZE_LIMIT-%{matched_var_name}=%{matched_var}" + +# Limit arguments total length +#SecRule ARGS_COMBINED_SIZE "@gt 64000" "phase:2,t:none,block,nolog,auditlog,status:403,msg:'Total arguments size exceeded',id:'960341',severity:'4',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+5,setvar:tx.policy_score=+1,setvar:tx.%{rule.id}-POLICY/SIZE_LIMIT-%{matched_var_name}=%{matched_var}" + + +## -- File upload limits -- + +# Individual file size is limited +#SecRule FILES_SIZES "@gt 1048576" "phase:2,t:none,block,nolog,auditlog,status:403,msg:'Uploaded file size too large',id:'960342',severity:'4',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+5,setvar:tx.policy_score=+1,setvar:tx.%{rule.id}-POLICY/SIZE_LIMIT-%{matched_var_name}=%{matched_var}" + +# Combined file size is limited +#SecRule FILES_COMBINED_SIZE "@gt 1048576" "phase:2,t:none,block,nolog,auditlog,status:403,msg:'Total uploaded files size too large',id:'960343',severity:'4',setvar:tx.%{rule.id}-POLICY/SIZE_LIMIT-%{matched_var_name}=%{matched_var}" + + + +## -- Apache Limits -- + +# These are Apache limit directives, but we are including them here because +# they are often forgotten. If you already have these configured leave this +# section entirely commented-out. Otherwise review the limits and uncomment +# the directives. + +# Maximum size of the request body. +# +# NOTE If your application allows file uploads the value below will +# most likely be way to low. +# +#LimitRequestBody 64000 + +# Maximum number of request headers in a request. +# +#LimitRequestFields 32 + +# Maximum size of request header lines. +# +#LimitRequestFieldSize 8000 + +# Maximum size of the request line. +# +#LimitRequestLine 4000 + diff --git a/rules/base_rules/modsecurity_crs_30_http_policy.conf b/rules/base_rules/modsecurity_crs_30_http_policy.conf new file mode 100644 index 0000000..c4cbbfd --- /dev/null +++ b/rules/base_rules/modsecurity_crs_30_http_policy.conf @@ -0,0 +1,111 @@ +# --------------------------------------------------------------- +# Core ModSecurity Rule Set ver.2.0.3 +# Copyright (C) 2006-2009 Breach Security Inc. All rights reserved. +# +# The ModSecuirty Core Rule Set is distributed under GPL version 2 +# Please see the enclosed LICENCE file for full details. +# --------------------------------------------------------------- + + +# HTTP policy enforcement +# The HTTP policy enforcement rule set sets limitations on the use of HTTP by clients. + +# Few applications require the breadth and depth of the HTTP protocol. On the +# other hand many attacks abuse valid but rare HTTP use patterns. Restricting +# HTTP protocol usage is effective in therefore effective in blocking many +# application layer attacks. +# +# TODO Many automation programs use non standard HTTP requests. While you may +# want to allow some of those, try not to create exceptions only for the +# automated program based on properties such as their source IP address or +# the URL they access. +# + +# allow request methods +# +# TODO Most applications only use GET, HEAD, and POST request +# methods. If that is not the case with your environment, you are advised +# to edit the line or uncomment it. +# +SecRule REQUEST_METHOD "!^((?:(?:POS|GE)T|OPTIONS|HEAD))$" "phase:2,t:none,block,nolog,auditlog,status:501,msg:'Method is not allowed by policy', severity:'2',id:'960032',tag:'POLICY/METHOD_NOT_ALLOWED',setvar:tx.anomaly_score=+5,setvar:tx.policy_score=+1,setvar:tx.%{rule.id}-POLICY/METHOD_NOT_ALLOWED-%{matched_var_name}=%{matched_var}" + + +# Restrict which content-types we accept. +# +# TODO Most applications support only two types for request bodies +# because that is all browsers know how to produce. If you are using +# automated tools to talk to the application you may be using other +# content types and would want to change the list of supported types. +# +# Note though that ModSecurity parses only three content types: +# application/x-www-form-urlencoded, multipart/form-data request and +# text/xml. The protection provided for any other type is inferior. +# +# TODO There are many applications that are not using multipart/form-data +# types (typically only used for file uploads). This content type +# can be disabled if not used. +# +# NOTE We allow any content type to be specified with GET or HEAD +# because some tools incorrectly supply content type information +# even when the body is not present. There is a rule further in +# the file to prevent GET and HEAD requests to have bodies to we're +# safe in that respect. +# +# NOTE Use of WebDAV requires "text/xml" content type. +# +# NOTE Philippe Bourcier (pbourcier AT citali DOT com) reports +# applications running on the PocketPC and AvantGo platforms use +# non-standard content types: +# +# M-Business iAnywhere application/x-mal-client-data +# UltraLite iAnywhere application/octet-stream +# +SecRule REQUEST_METHOD "!^(?:GET|HEAD|PROPFIND|OPTIONS)$" "phase:2,chain,t:none,block,nolog,auditlog,status:501,msg:'Request content type is not allowed by policy',id:'960010',tag:'POLICY/ENCODING_NOT_ALLOWED',severity:'4'" + SecRule REQUEST_HEADERS:Content-Type "!(?:^(?:application\/x-www-form-urlencoded(?:;(?:\s?charset\s?=\s?[\w\d\-]{1,18})?)??$|multipart/form-data;)|text/xml)" "t:none,setvar:tx.anomaly_score=+5,setvar:tx.policy_score=+1,setvar:tx.%{rule.id}-POLICY/CONTENT_TYPE_NOT_ALLOWED-%{matched_var_name}=%{matched_var}" + +# Restrict protocol versions. +# +# TODO All modern browsers use HTTP version 1.1. For tight security, allow only +# this version. +# +# NOTE Automation programs, both malicious and non malicious many times use +# other HTTP versions. If you want to allow a specific automated program +# to use your site, try to create a narrower expection and not allow any +# client to send HTTP requests in a version lower than 1.1 +# +SecRule REQUEST_PROTOCOL "!^HTTP/(0\.9|1\.[01])$" "phase:2,t:none,block,nolog,auditlog,status:505,msg:'HTTP protocol version is not allowed by policy', severity:'2',id:'960034',tag:'POLICY/PROTOCOL_NOT_ALLOWED',setvar:tx.anomaly_score=+5,setvar:tx.policy_score=+1,setvar:tx.%{rule.id}-POLICY/PROTOCOL_NOT_ALLOWED-%{matched_var_name}=%{matched_var}" + +# Restrict file extension +# +# TODO the list of file extensions below are virtually always considered unsafe +# and not in use in any valid program. If your application uses one of +# these extensions, please remove it from the list of blocked extensions. +# You may need to use ModSecurity Core Rule Set Templates to do so, otherwise +# comment the whole rule. +# +SecRule REQUEST_BASENAME "\.(?:c(?:o(?:nf(?:ig)?|m)|s(?:proj|r)?|dx|er|fg|md)|p(?:rinter|ass|db|ol|wd)|v(?:b(?:proj|s)?|sdisco)|a(?:s(?:ax?|cx)|xd)|d(?:bf?|at|ll|os)|i(?:d[acq]|n[ci])|ba(?:[kt]|ckup)|res(?:ources|x)|s(?:h?tm|ql|ys)|l(?:icx|nk|og)|\w{0,5}~|webinfo|ht[rw]|xs[dx]|key|mdb|old)$" "phase:2,t:none,t:urlDecodeUni,t:lowercase,block,nolog,auditlog,status:500,msg:'URL file extension is restricted by policy', severity:'2',id:'960035',tag:'POLICY/EXT_RESTRICTED',setvar:tx.anomaly_score=+5,setvar:tx.policy_score=+1,setvar:tx.%{rule.id}-POLICY/EXT_RESTRICTED-%{matched_var_name}=%{matched_var}" + + + +# Restricted HTTP headers +# +# TODO the list of HTTP headers below are considered unsafe for your environment. +# If your application uses one of these directories, please remove it from +# the list of blocked extensions. You may need to use ModSecurity Core Rule +# Set Templates to do so, otherwise comment the whole rule. +# +SecRule REQUEST_HEADERS_NAMES "(?:(?:Proxy-Connectio|Lock-Toke)n|(?:Content-Rang|Translat)e|via|if)$" "phase:2,t:none,block,nolog,auditlog,status:500,msg:'HTTP header is restricted by policy',id:'960038',tag:'POLICY/HEADER_RESTRICTED',tag:'POLICY/FILES_NOT_ALLOWED',severity:'4',setvar:tx.anomaly_score=+5,setvar:tx.policy_score=+1,setvar:tx.%{rule.id}-POLICY/HEADERS_RESTRICTED-%{matched_var_name}=%{matched_var}" + + +# Restricted Content Encodings +# +# ModSecurity does not support compressed content. Therefore, the following +# action will be taken: +# - Inbound compressed content will be denied +# - Outbound compressed content will be logged once, to alert the user +# Deny inbound compressed content +SecRule REQUEST_HEADERS:Content-Encoding "!^Identity$" "phase:2,t:none,block,nolog,auditlog,status:501,msg:'ModSecurity does not support content encodings',id:'960902',severity:'4',setvar:tx.anomaly_score=+5,setvar:tx.policy_score=+1,setvar:tx.%{rule.id}-POLICY/ENCODING_RESTRICTED-%{matched_var_name}=%{matched_var}" +# Log outbound compressed content (log once) +SecRule RESPONSE_HEADERS:Content-Encoding "!^Identity$" "phase:4,t:none,pass,nolog,auditlog,msg:'ModSecurity does not support content encodings',id:'960903',severity:'4',chain,initcol:global=global" + SecRule &GLOBAL:alerted_960903_compression "@eq 0" "setvar:global.alerted_960903_compression,setvar:tx.anomaly_score=+5,setvar:tx.policy_score=+1,setvar:tx.%{rule.id}-POLICY/ENCODING_RESTRICTED-%{matched_var_name}=%{matched_var}" + diff --git a/rules/base_rules/modsecurity_crs_35_bad_robots.conf b/rules/base_rules/modsecurity_crs_35_bad_robots.conf new file mode 100644 index 0000000..ff51d22 --- /dev/null +++ b/rules/base_rules/modsecurity_crs_35_bad_robots.conf @@ -0,0 +1,31 @@ +# --------------------------------------------------------------- +# Core ModSecurity Rule Set ver.2.0.3 +# Copyright (C) 2006-2009 Breach Security Inc. All rights reserved. +# +# The ModSecuirty Core Rule Set is distributed under GPL version 2 +# Please see the enclosed LICENCE file for full details. +# --------------------------------------------------------------- + + +# +# NOTE Bad robots detection is based on checking elements easily +# controlled by the client. As such a determined attacked can bypass +# those checks. Therefore bad robots detection should not be viewed as +# a security mechanism against targeted attacks but rather as a nuisance +# reduction, eliminating most of the random attacks against your web +# site. + +SecRule REQUEST_HEADERS:User-Agent "(?:\b(?:m(?:ozilla\/4\.0 \(compatible\)|etis)|webtrends security analyzer|pmafind)\b|n(?:-stealth|sauditor|essus|ikto)|b(?:lack ?widow|rutus|ilbo)|(?:jaascoi|paro)s|webinspect|\.nasl)" \ + "phase:2,t:none,t:lowercase,block,nolog,auditlog,status:404,msg:'Request Indicates a Security Scanner Scanned the Site',id:'990002',tag:'AUTOMATION/SECURITY_SCANNER',severity:'4',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+10,setvar:tx.automation_score=+1,setvar:tx.%{rule.id}-AUTOMATION/SECURITY_SCANNER-%{matched_var_name}=%{matched_var}" +SecRule REQUEST_HEADERS_NAMES "\bacunetix-product\b" \ + "phase:2,t:none,t:lowercase,block,nolog,auditlog,status:404,msg:'Request Indicates a Security Scanner Scanned the Site',id:'990901',tag:'AUTOMATION/SECURITY_SCANNER',severity:'4',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+10,setvar:tx.automation_score=+1,setvar:tx.%{rule.id}-AUTOMATION/SECURITY_SCANNER-%{matched_var_name}=%{matched_var}" +SecRule REQUEST_FILENAME "^/nessustest" \ + "phase:2,t:none,t:lowercase,block,nolog,auditlog,status:404,msg:'Request Indicates a Security Scanner Scanned the Site',id:'990902',tag:'AUTOMATION/SECURITY_SCANNER',severity:'4',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+10,setvar:tx.automation_score=+1,setvar:tx.%{rule.id}-AUTOMATION/SECURITY_SCANNER-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_HEADERS:User-Agent "(?:e(?:mail(?:(?:collec|harves|magne)t|(?: extracto|reape)r|siphon|wolf)|(?:collecto|irgrabbe)r|xtractorpro|o browse)|w(?:eb(?:emailextrac| by mail|altbot)|i(?:se(?:nut)?bot|ndows xp 5)|ordpress\/4\.01|3mir)|a(?:t(?:tache|hens)|utoemailspider|dsarobot| href=)|m(?:ailto:craftbot\@yahoo\.com|urzillo compatible)|p(?:(?:oe-component-clien|ackra)t|cbrowser|surf)|c(?:ompatible(?: ; msie|-)|hinaclaw)|f(?:astlwspider|loodgate)|t(?:uring machine|akeout)|g(?:rub-client|ecko\/25)|h(?:hjhj@yahoo|anzoweb)|d(?:igout4u|ts )agent|larbin@unspecified|(?:; widow|zeu)s|\bdatacha0s\b|user-agent:|rsync|shai|\\r)" \ + "phase:2,t:none,t:lowercase,block,nolog,auditlog,status:404,msg:'Rogue web site crawler',id:'990012',tag:'AUTOMATION/MALICIOUS',severity:'4',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+10,setvar:tx.automation_score=+1,setvar:tx.%{rule.id}-AUTOMATION/MALICIOUS-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_HEADERS:User-Agent "(?:\b(?:(?:indy librar|snoop)y|microsoft url control|lynx)\b|mozilla\/2\.0 \(compatible; newt activex; win32\)|w(?:3mirror|get)|download demon|l(?:ibwww|wp)|p(?:avuk|erl)|big brother|autohttp|netants|eCatch|curl)" \ + "chain,phase:2,t:none,t:lowercase,nolog,auditlog,msg:'Request Indicates an automated program explored the site',id:'990011',tag:'AUTOMATION/MISC',severity:'5'" +SecRule REQUEST_HEADERS:User-Agent "!^apache.*perl" "t:none,t:lowercase,setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+5,setvar:tx.automation_score=+1,setvar:tx.%{rule.id}-AUTOMATION/MISC-%{matched_var_name}=%{matched_var}" + diff --git a/rules/base_rules/modsecurity_crs_40_generic_attacks.conf b/rules/base_rules/modsecurity_crs_40_generic_attacks.conf new file mode 100644 index 0000000..b3f7b07 --- /dev/null +++ b/rules/base_rules/modsecurity_crs_40_generic_attacks.conf @@ -0,0 +1,389 @@ +# --------------------------------------------------------------- +# Core ModSecurity Rule Set ver.2.0.3 +# Copyright (C) 2006-2009 Breach Security Inc. All rights reserved. +# +# The ModSecuirty Core Rule Set is distributed under GPL version 2 +# Please see the enclosed LICENCE file for full details. +# --------------------------------------------------------------- + + +# +# TODO While some of the pattern groups such as command injection are usually +# safe of false positives, other pattern groups such as SQL injection and +# XSS may require setting exceptions and therefore are set to log only by +# default. +# +# Start ModSecurity in monitoring only mode and check whether your +# application requires exceptions for a specific URL, Pattern or source IP +# before moving to blocking mode. + +# +# Begin RegEx Checks for rules that could not use @pm prequalifications +# + +# +# HTTP Parameter Pollution +# +SecRule ARGS_NAMES ".*" \ + "chain,phase:2,t:none,nolog,auditlog,pass,capture,setvar:'tx.arg_name_%{tx.0}=+1',msg:'Possible HTTP Parameter Pollution Attack: Multiple Parameters with the same Name.'" + SecRule TX:/ARG_NAME_*/ "@gt 1" "t:none,setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + +SecRule ARGS "(?:(?:[\;\|\`]\W*?\bcc|\bwget)\b|\/cc(?:[\'\"\|\;\`\-\s]|$))" \ + "phase:2,capture,t:none,t:htmlEntityDecode,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'950907',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" +SecRule "REQUEST_HEADERS|XML:/*|!REQUEST_HEADERS:'/^(Cookie|Referer|X-OS-Prefs|User-Agent)$/'|REQUEST_COOKIES|REQUEST_COOKIES_NAMES" \ + "(?:(?:[\;\|\`]\W*?\bcc|\bwget)\b|\/cc(?:[\'\"\|\;\`\-\s]|$))" \ + "phase:2,capture,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'959907',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + +# +# Coldfusion injection +# +SecRule REQUEST_HEADERS|XML:/* "\bcf(?:usion_(?:d(?:bconnections_flush|ecrypt)|set(?:tings_refresh|odbcini)|getodbc(?:dsn|ini)|verifymail|encrypt)|_(?:(?:iscoldfusiondatasourc|getdatasourceusernam)e|setdatasource(?:password|username))|newinternal(?:adminsecurit|registr)y|admin_registry_(?:delete|set)|internaldebug)\b" \ + "phase:2,capture,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'Injection of Undocumented ColdFusion Tags',id:'950008',tag:'WEB_ATTACK/CF_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/CF_INJECTION-%{matched_var_name}=%{matched_var}" + + +# +# LDAP injection +# +SecRule REQUEST_HEADERS|XML:/*|!REQUEST_HEADERS:Referer "(?:\((?:\W*?(?:objectc(?:ategory|lass)|homedirectory|[gu]idnumber|cn)\b\W*?=|[^\w\x80-\xFF]*?[\!\&\|][^\w\x80-\xFF]*?\()|\)[^\w\x80-\xFF]*?\([^\w\x80-\xFF]*?[\!\&\|])" \ + "phase:2,capture,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'LDAP Injection Attack',id:'950010',tag:'WEB_ATTACK/LDAP_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/LDAP_INJECTION-%{matched_var_name}=%{matched_var}" + + +# +# SSI injection +# +SecRule REQUEST_HEADERS|XML:/* "<!--\W*?#\W*?(?:e(?:cho|xec)|printenv|include|cmd)" \ + "phase:2,capture,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'SSI injection Attack',id:'950011',tag:'WEB_ATTACK/SSI_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/SSI_INJECTION-%{matched_var_name}=%{matched_var}" + + + +# +# UPDF XSS +# +SecRule REQUEST_HEADERS|XML:/* "http:\/\/[\w\.]+?\/.*?\.pdf\b[^\x0d\x0a]*#" \ + "phase:2,capture,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'Persistent Universal PDF XSS attack',id:'950018',tag:'WEB_ATTACK/UPDF_XSS',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/UPDF_XSS-%{matched_var_name}=%{matched_var}" + + +# +# Email Injection +# +SecRule REQUEST_HEADERS|XML:/* "[\n\r]\s*\b(?:to|b?cc)\b\s*:.*?\@" \ + "phase:2,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:lowercase,capture,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Email Injection Attack',id:'950019',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/EMAIL_INJECTION-%{matched_var_name}=%{matched_var}" + + +# HTTP Request Smuggling +# +SecRule REQUEST_HEADERS:'/(Content-Length|Transfer-Encoding)/' "," "phase:2,t:none,block,nolog,auditlog,status:400,msg:'HTTP Request Smuggling Attack.',id:'950012',tag:'WEB_ATTACK/REQUEST_SMUGGLING',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/REQUEST_SMUGGLING-%{matched_var_name}=%{matched_var}" + +# +# HTTP Response Splitting +# +SecRule REQUEST_URI|REQUEST_HEADERS|REQUEST_HEADERS_NAMES "%0[ad]" \ + "phase:2,t:none,t:lowercase,capture,ctl:auditLogParts=+E,block,nolog,auditlog,status:400,msg:'HTTP Response Splitting Attack',id:'950910',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/RESPONSE_SPLITTING-%{matched_var_name}=%{matched_var}" +SecRule REQUEST_URI|REQUEST_BODY|XML:/* "(?:\bhttp\/(?:0\.9|1\.[01])|<(?:html|meta)\b)" \ + "phase:2,capture,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,status:400,msg:'HTTP Response Splitting Attack',id:'950911',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/RESPONSE_SPLITTING-%{matched_var_name}=%{matched_var}" + + +# +# RFI Attack +# +# See - http://tacticalwebappsec.blogspot.com/2009/06/generic-remote-file-inclusion-attack.html +# +SecRule ARGS "^(?:ht|f)tps?:\/\/([\d\.]+)" \ + "phase:2,t:none,t:htmlEntityDecode,t:lowercase,capture,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'Remote File Inclusion Attack',id:'950117',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/RFI-%{matched_var_name}=%{matched_var}" + +SecRule ARGS "(?:\binclude\s*\([^)]*(ht|f)tps?:\/\/)" \ + "phase:2,t:none,t:htmlEntityDecode,t:lowercase,capture,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'Remote File Inclusion Attack',id:'950118',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/RFI-%{matched_var_name}=%{matched_var}" + +SecRule ARGS "(?:ft|htt)ps?.*\?+$" \ + "phase:2,t:none,t:htmlEntityDecode,t:lowercase,capture,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'Remote File Inclusion Attack',id:'950119',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/RFI-%{matched_var_name}=%{matched_var}" + +SecRule ARGS "^(?:ht|f)tps?://(.*)\?$" \ + "chain,phase:2,t:none,t:htmlEntityDecode,t:lowercase,capture,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'Remote File Inclusion Attack',id:'950120',severity:'2'" + SecRule TX:1 "!@beginsWith %{request_headers.host}" "setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/RFI-%{matched_var_name}=%{matched_var}" + +# +# Prequalify Request Matches +# +SecRule REQUEST_URI|REQUEST_BODY|REQUEST_HEADERS|XML:/*|!REQUEST_HEADERS:Referer "@pmFromFile modsecurity_40_generic_attacks.data" \ + "phase:2,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,nolog,pass,setvar:tx.pm_score=+1,setvar:tx.pm_data_%{matched_var_name}=%{matched_var}" + +SecRule TX:PM_SCORE "@eq 0" "phase:2,t:none,pass,skipAfter:END_PM_CHECK,nolog" + +# +# Begin RegEx Checks for target locations that matched the prequalifier checks +# + # + # Session fixation + # + SecRule TX:/PM_DATA_*/ "\.cookie\b.*?\;\W*?expires\W*?\=" \ + "phase:2,t:none,capture,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Session Fixation',id:'950301',tag:'WEB_ATTACK/SESSION_FIXATION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/SSI_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\.cookie\b.*?\;\W*?domain\W*?\=" \ + "phase:2,t:none,capture,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Session Fixation',id:'950300',tag:'WEB_ATTACK/SESSION_FIXATION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/SSI_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\bhttp-equiv\W+set-cookie\b" \ + "phase:2,t:none,capture,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Session Fixation',id:'950302',tag:'WEB_ATTACK/SESSION_FIXATION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/SSI_INJECTION-%{matched_var_name}=%{matched_var}" + + + + # + # File Injection + # + SecRule TX:/PM_DATA_*/ "\bboot\.ini\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'Remote File Access Attempt',id:'958711',tag:'WEB_ATTACK/FILE_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/FILE_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\/etc\/" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'Remote File Access Attempt',id:'958700',tag:'WEB_ATTACK/FILE_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/FILE_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\b\.htaccess\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'Remote File Access Attempt',id:'958706',tag:'WEB_ATTACK/FILE_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/FILE_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\b\.htpasswd\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'Remote File Access Attempt',id:'958708',tag:'WEB_ATTACK/FILE_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/FILE_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\bhttpd\.conf\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'Remote File Access Attempt',id:'958705',tag:'WEB_ATTACK/FILE_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/FILE_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\bglobal\.asa\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'Remote File Access Attempt',id:'958712',tag:'WEB_ATTACK/FILE_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/FILE_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\b\.wwwacl\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'Remote File Access Attempt',id:'958710',tag:'WEB_ATTACK/FILE_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/FILE_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\b\.www_acl\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'Remote File Access Attempt',id:'958709',tag:'WEB_ATTACK/FILE_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/FILE_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\b\.htgroup\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'Remote File Access Attempt',id:'958707',tag:'WEB_ATTACK/FILE_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/FILE_INJECTION-%{matched_var_name}=%{matched_var}" + + + # + # Command access + # + SecRule TX:/PM_DATA_*/ "\bnc\.exe\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Access',id:'958503',tag:'WEB_ATTACK/FILE_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/FILE_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "\bcmd\.exe\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Access',id:'958500',tag:'WEB_ATTACK/FILE_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/FILE_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "\bnet\.exe\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Access',id:'958504',tag:'WEB_ATTACK/FILE_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/FILE_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "\btelnet\.exe\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Access',id:'972022',tag:'WEB_ATTACK/FILE_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/FILE_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "\bwsh\.exe\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Access',id:'972032',tag:'WEB_ATTACK/FILE_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/FILE_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "\bftp\.exe\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Access',id:'958502',tag:'WEB_ATTACK/FILE_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/FILE_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "\bcmd\b\W*?\/c" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Access',id:'972030',tag:'WEB_ATTACK/FILE_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/FILE_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "\bnmap\.exe\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Access',id:'972029',tag:'WEB_ATTACK/FILE_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/FILE_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "\bwguest\.exe\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Access',id:'972031',tag:'WEB_ATTACK/FILE_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/FILE_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "\bcmd32\.exe\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Access',id:'958501',tag:'WEB_ATTACK/FILE_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/FILE_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "\brcmd\.exe\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Access',id:'958505',tag:'WEB_ATTACK/FILE_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/FILE_INJECTION-%{matched_var_name}=%{matched_var}" + + # + # Command injection + # + SecRule TX:/PM_DATA_*/ "\btclsh8\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958929',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "\bnmap\.exe\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958870',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "[\;\|\`]\W*?\bperl\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958873',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "[\;\|\`]\W*?\bcpp\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958928',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "[\;\|\`]\W*?\bpython\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958887',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "\bnc\.exe\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958828',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "[\;\|\`]\W*?\buname\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958898',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "[\;\|\`]\W*?\bpasswd\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958888',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "\bnet\b\W+?\blocalgroup\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958830',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "[\;\|\`]\W*?\bls\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958883',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "[\;\|\`]\W*?\bchown\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958877',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "\brcmd\.exe\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958832',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "[\;\|\`]\W*?\bnc\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958891',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "[\;\|\`]\W*?\brm\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958894',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "\bwsh\.exe\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958839',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "[\;\|\`]\W*?\bfinger\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958881',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "[\;\|\`]\W*?\bftp\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958890',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "[\;\|\`]\W*?\becho\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958872',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "[\;\|\`]\W*?\bxterm\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958879',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "[\;\|\`]\W*?\bkill\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958884',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "[\;\|\`]\W*?\bchsh\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958927',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "[\;\|\`]\W*?\bping\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958893',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "\bcd\b\W*?[\\/]" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958821',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "[\;\|\`]\W*?\btelnet\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958889',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "[\;\|\`]\W*?\bchmod\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958876',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "\bwguest\.exe\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958838',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "\bcmd\b\W*?\/c" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958871',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "\bnet\.exe\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958829',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "[\;\|\`]\W*?\bg\+\+" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958875',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "[\;\|\`]\W*?\bnasm\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958882',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "\bcmd32\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958824',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "[\;\|\`]\W*?\blsof\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958897',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "[\;\|\`]\W*?\bid\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958885',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "\btelnet\.exe\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958834',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "\btracert\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958926',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "[\;\|\`]\W*?\bnmap\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958896',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "\becho\b\W*?\by+\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958826',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "\btraceroute\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958837',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "\btftp\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958836',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "[\;\|\`]\W*?\bgcc\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958874',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "\bchmod.{0,40}?\+.{0,3}x" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958822',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "[\;\|\`]\W*?\bps\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958886',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "\bftp\.exe\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958827',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "[\;\|\`]\W*?\bcmd\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958892',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "\btclsh\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958833',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "[\;\|\`]\W*?\bmail\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958895',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "[\;\|\`]\W*?\bchgrp\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958878',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "\bcd\W*?\.\." \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958925',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + SecRule TX:/PM_DATA_*/ "\bcmd\.exe\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'System Command Injection',id:'958823',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{matched_var}" + + # + # PHP injection + # + + SecRule TX:/PM_DATA_*/ "<\?(?!xml)" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'PHP Injection Attack',id:'959151',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/PHP_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\bproc_open\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'PHP Injection Attack',id:'958976',tag:'WEB_ATTACK/PHP_INJECTION',tag:'WEB_ATTACK/HTTP_RESPONSSE_SPLITTING',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/PHP_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\bgzread\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'PHP Injection Attack',id:'958972',tag:'WEB_ATTACK/PHP_INJECTION',tag:'WEB_ATTACK/HTTP_RESPONSSE_SPLITTING',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/PHP_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\bftp_nb_fget\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'PHP Injection Attack',id:'958963',tag:'WEB_ATTACK/PHP_INJECTION',tag:'WEB_ATTACK/HTTP_RESPONSSE_SPLITTING',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/PHP_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\bftp_nb_get\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'PHP Injection Attack',id:'958965',tag:'WEB_ATTACK/PHP_INJECTION',tag:'WEB_ATTACK/HTTP_RESPONSSE_SPLITTING',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/PHP_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\bfscanf\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'PHP Injection Attack',id:'958959',tag:'WEB_ATTACK/PHP_INJECTION',tag:'WEB_ATTACK/HTTP_RESPONSSE_SPLITTING',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/PHP_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\breadfile\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'PHP Injection Attack',id:'958978',tag:'WEB_ATTACK/PHP_INJECTION',tag:'WEB_ATTACK/HTTP_RESPONSSE_SPLITTING',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/PHP_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\bfgetss\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'PHP Injection Attack',id:'958955',tag:'WEB_ATTACK/PHP_INJECTION',tag:'WEB_ATTACK/HTTP_RESPONSSE_SPLITTING',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/PHP_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\$_post\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'PHP Injection Attack',id:'958941',tag:'WEB_ATTACK/PHP_INJECTION',tag:'WEB_ATTACK/HTTP_RESPONSSE_SPLITTING',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/PHP_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\bsession_start\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'PHP Injection Attack',id:'958982',tag:'WEB_ATTACK/PHP_INJECTION',tag:'WEB_ATTACK/HTTP_RESPONSSE_SPLITTING',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/PHP_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\breaddir\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'PHP Injection Attack',id:'958977',tag:'WEB_ATTACK/PHP_INJECTION',tag:'WEB_ATTACK/HTTP_RESPONSSE_SPLITTING',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/PHP_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\bgzwrite\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'PHP Injection Attack',id:'958973',tag:'WEB_ATTACK/PHP_INJECTION',tag:'WEB_ATTACK/HTTP_RESPONSSE_SPLITTING',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/PHP_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\bscandir\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'PHP Injection Attack',id:'958981',tag:'WEB_ATTACK/PHP_INJECTION',tag:'WEB_ATTACK/HTTP_RESPONSSE_SPLITTING',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/PHP_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\bftp_get\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'PHP Injection Attack',id:'958962',tag:'WEB_ATTACK/PHP_INJECTION',tag:'WEB_ATTACK/HTTP_RESPONSSE_SPLITTING',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/PHP_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\bfread\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'PHP Injection Attack',id:'958958',tag:'WEB_ATTACK/PHP_INJECTION',tag:'WEB_ATTACK/HTTP_RESPONSSE_SPLITTING',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/PHP_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\breadgzfile\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'PHP Injection Attack',id:'958979',tag:'WEB_ATTACK/PHP_INJECTION',tag:'WEB_ATTACK/HTTP_RESPONSSE_SPLITTING',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/PHP_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\bftp_put\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'PHP Injection Attack',id:'958967',tag:'WEB_ATTACK/PHP_INJECTION',tag:'WEB_ATTACK/HTTP_RESPONSSE_SPLITTING',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/PHP_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\bfwrite\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'PHP Injection Attack',id:'958968',tag:'WEB_ATTACK/PHP_INJECTION',tag:'WEB_ATTACK/HTTP_RESPONSSE_SPLITTING',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/PHP_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\bgzencode\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'PHP Injection Attack',id:'958970',tag:'WEB_ATTACK/PHP_INJECTION',tag:'WEB_ATTACK/HTTP_RESPONSSE_SPLITTING',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/PHP_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\bfopen\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'PHP Injection Attack',id:'958957',tag:'WEB_ATTACK/PHP_INJECTION',tag:'WEB_ATTACK/HTTP_RESPONSSE_SPLITTING',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/PHP_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\$_session\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'PHP Injection Attack',id:'958942',tag:'WEB_ATTACK/PHP_INJECTION',tag:'WEB_ATTACK/HTTP_RESPONSSE_SPLITTING',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/PHP_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\bftp_nb_fput\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'PHP Injection Attack',id:'958964',tag:'WEB_ATTACK/PHP_INJECTION',tag:'WEB_ATTACK/HTTP_RESPONSSE_SPLITTING',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/PHP_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\bftp_fput\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'PHP Injection Attack',id:'958961',tag:'WEB_ATTACK/PHP_INJECTION',tag:'WEB_ATTACK/HTTP_RESPONSSE_SPLITTING',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/PHP_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\bgzcompress\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'PHP Injection Attack',id:'958969',tag:'WEB_ATTACK/PHP_INJECTION',tag:'WEB_ATTACK/HTTP_RESPONSSE_SPLITTING',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/PHP_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\bbzopen\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'PHP Injection Attack',id:'958946',tag:'WEB_ATTACK/PHP_INJECTION',tag:'WEB_ATTACK/HTTP_RESPONSSE_SPLITTING',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/PHP_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\bgzopen\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'PHP Injection Attack',id:'958971',tag:'WEB_ATTACK/PHP_INJECTION',tag:'WEB_ATTACK/HTTP_RESPONSSE_SPLITTING',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/PHP_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\bfgetc\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'PHP Injection Attack',id:'958953',tag:'WEB_ATTACK/PHP_INJECTION',tag:'WEB_ATTACK/HTTP_RESPONSSE_SPLITTING',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/PHP_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\bmove_uploaded_file\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'PHP Injection Attack',id:'958975',tag:'WEB_ATTACK/PHP_INJECTION',tag:'WEB_ATTACK/HTTP_RESPONSSE_SPLITTING',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/PHP_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\bftp_nb_put\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'PHP Injection Attack',id:'958966',tag:'WEB_ATTACK/PHP_INJECTION',tag:'WEB_ATTACK/HTTP_RESPONSSE_SPLITTING',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/PHP_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\$_get\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'PHP Injection Attack',id:'958940',tag:'WEB_ATTACK/PHP_INJECTION',tag:'WEB_ATTACK/HTTP_RESPONSSE_SPLITTING',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/PHP_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\bfgets\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'PHP Injection Attack',id:'958954',tag:'WEB_ATTACK/PHP_INJECTION',tag:'WEB_ATTACK/HTTP_RESPONSSE_SPLITTING',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/PHP_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/PM_DATA_*/ "\bftp_fget\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'PHP Injection Attack',id:'958960',tag:'WEB_ATTACK/PHP_INJECTION',tag:'WEB_ATTACK/HTTP_RESPONSSE_SPLITTING',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.web_attack_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/PHP_INJECTION-%{matched_var_name}=%{matched_var}" + + +SecMarker END_PM_CHECK diff --git a/rules/base_rules/modsecurity_crs_41_phpids_converter.conf b/rules/base_rules/modsecurity_crs_41_phpids_converter.conf new file mode 100644 index 0000000..ecbd7a3 --- /dev/null +++ b/rules/base_rules/modsecurity_crs_41_phpids_converter.conf @@ -0,0 +1,54 @@ +# --------------------------------------------------------------- +# Core ModSecurity Rule Set ver.2.0.3 +# Copyright (C) 2006-2009 Breach Security Inc. All rights reserved. +# +# The ModSecuirty Core Rule Set is distributed under GPL version 2 +# Please see the enclosed LICENCE file for full details. +# --------------------------------------------------------------- + + +# +# PHP-IDS rules (www.php-ids.org) +# Converter.php Section +# https://svn.php-ids.org/svn/trunk/lib/IDS/Converter.php +# + +# +# Make sure the value to normalize and monitor doesn't contain +# possibilities for a regex DoS. +# http://www.checkmarx.com/Upload/Documents/PDF/Checkmarx_OWASP_IL_2009_ReDoS.pdf +# +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:(.{2,})\1{32,})|(?:[+=|\-@\s]{128,})" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Possible RegEx DoS Payload',tag:'WEB_ATTACK/EVASION',logdata:'%{TX.0}',severity:'4',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+10,setvar:tx.%{rule.id}-WEB_ATTACK/EVASION-%{matched_var_name}=%{matched_var}" + +# +# Identify Comment Evasion Attempts +# +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:\<!-|-->|\/\*|\*\/|\/\/\W*\w+\s*$)" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Comment Evasion Attempt',tag:'WEB_ATTACK/EVASION',logdata:'%{TX.0}',severity:'4',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+10,setvar:tx.%{rule.id}-WEB_ATTACK/EVASION-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:--[^-]*-)" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Comment Evasion Attempt',tag:'WEB_ATTACK/EVASION',logdata:'%{TX.0}',severity:'4',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+10,setvar:tx.%{rule.id}-WEB_ATTACK/EVASION-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:(?:<!)(?:(?:--(?:[^-]*(?:-[^-]+)*)--\s*)*)(?:>))" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Comment Evasion Attempt',tag:'WEB_ATTACK/EVASION',logdata:'%{TX.0}',severity:'4',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+10,setvar:tx.%{rule.id}-WEB_ATTACK/EVASION-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:(?:\/\*\/*[^\/\*]*)+\*\/)" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Comment Evasion Attempt',tag:'WEB_ATTACK/EVASION',logdata:'%{TX.0}',severity:'4',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+10,setvar:tx.%{rule.id}-WEB_ATTACK/EVASION-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:--[^-]*-)" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Comment Evasion Attempt',tag:'WEB_ATTACK/EVASION',logdata:'%{TX.0}',severity:'4',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+10,setvar:tx.%{rule.id}-WEB_ATTACK/EVASION-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(<\w+)\/+(\w+=?)" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Comment Evasion Attempt',tag:'WEB_ATTACK/EVASION',logdata:'%{TX.0}',severity:'4',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+10,setvar:tx.%{rule.id}-WEB_ATTACK/EVASION-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "[^\\\:]\/\/(.*)$" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Comment Evasion Attempt',tag:'WEB_ATTACK/EVASION',logdata:'%{TX.0}',severity:'4',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+10,setvar:tx.%{rule.id}-WEB_ATTACK/EVASION-%{matched_var_name}=%{matched_var}" + +# +# Checks for common charcode patterns +# +# check if value matches typical charCode pattern +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:[\d+-=\/\* ]+(?:\s?,\s?[\d+-=\/\* ]+)){4,}" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Basic Charcode Pattern Found',tag:'WEB_ATTACK/EVASION',logdata:'%{TX.0}',severity:'4',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+10,setvar:tx.%{rule.id}-WEB_ATTACK/EVASION-%{matched_var_name}=%{matched_var}" + +# +# check for octal charcode pattern +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:(?:[\\\]+\d+[ \t]*){8,})" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Octal Charcode Pattern Found',tag:'WEB_ATTACK/EVASION',logdata:'%{TX.0}',severity:'4',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+10,setvar:tx.%{rule.id}-WEB_ATTACK/EVASION-%{matched_var_name}=%{matched_var}" + +# +# check for hexadecimal charcode pattern +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:(?:[\\\]+\w+\s*){8,})" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Hexadecimal Charcode Pattern Found',tag:'WEB_ATTACK/EVASION',logdata:'%{TX.0}',severity:'4',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+10,setvar:tx.%{rule.id}-WEB_ATTACK/EVASION-%{matched_var_name}=%{matched_var}" + + diff --git a/rules/base_rules/modsecurity_crs_41_phpids_filters.conf b/rules/base_rules/modsecurity_crs_41_phpids_filters.conf new file mode 100644 index 0000000..0fc820d --- /dev/null +++ b/rules/base_rules/modsecurity_crs_41_phpids_filters.conf @@ -0,0 +1,150 @@ +# --------------------------------------------------------------- +# Core ModSecurity Rule Set ver.2.0.3 +# Copyright (C) 2006-2009 Breach Security Inc. All rights reserved. +# +# The ModSecuirty Core Rule Set is distributed under GPL version 2 +# Please see the enclosed LICENCE file for full details. +# --------------------------------------------------------------- + + + +# PHP-IDS rules (www.php-ids.org) +# https://svn.php-ids.org/svn/trunk/lib/IDS/default_filter.xml +# +# Attack Signatures +# + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:\<\w*:?\s(?:[^\>]*)t(?!rong))|(?:\<scri)|(<\w+:\w+)" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects obfuscated script tags and XML wrapped HTML',id:'phpids-33',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:[^\w\s=]on(?!g\>)\w+[^=_+-]*=[^$]+(?:\W|\>)?)" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects possible event handlers',id:'phpids-32',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:[\w.-]+@[\w.-]+%(?:[01][\db-ce-f])+\w+:)" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects common mail header injections',id:'phpids-63',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:,\s*(?:alert|showmodaldialog|eval)\s*,)|(?::\s*eval\s*[^\s])|([^:\s\w,.\/?+-]\s*)?(?<![a-z\/_@])(\s*return\s*)?(?:(?:document\s*\.)?(?:.+\/)?(?:alert|eval|msgbox|showmodaldialog|prompt|write(?:ln)?|confirm|dialog|open))\s*(?(1)[^\w]|(?:\s*[^\s\w,.@\/+-]))|(?:java[\s\/]*\.[\s\/]*lang)|(?:\w\s*=\s*new\s+\w+)|(?:&\s*\w+\s*\)[^,])|(?:\+[\W\d]*new\s+\w+[\W\d]*\+)|(?:document\.\w)" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects very basic XSS probings',id:'phpids-21',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:\d\s*[|&]{2}\s*\w)|(?:[=(].+\?.+:)|(?:with\([^)]*\)\))|(?:\.\s*source\W)|(?:\?[^:=]+:[^;]+(;|$))" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects JavaScript with(), ternary operators and XML predicate attacks',id:'phpids-7',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:[^:\s\w]+\s*[^\w\/](href|protocol|host|hostname|pathname|hash|port|cookie)[^\w])" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects JavaScript cookie stealing and redirection attempts',id:'phpids-26',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "([^*:\s\w,.\/?+-]\s*)?(?<![a-z]\s)(?<![a-z\/_@>\-\|])(\s*return\s*)?(?:join|pop|push|reverse|reduce|concat|map|shift|sp?lice|sort|unshift)(?(1)[^\w%\"]|(?:\s*[^@\s\w%,.+\-]))" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects JavaScript array properties and methods',id:'phpids-18',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "([^*\s\w,.\/?+-]\s*)?(?<![a-mo-z]\s)(?<![a-z\/_@>\-\|])(\s*return\s*)?(?:alert|inputbox|showmodaldialog|infinity|isnan|isnull|msgbox|expression|prompt|write(?:ln)?|confirm|dialog|urn|(?:un)?eval|exec|execscript|tostring|status|execute|window|unescape|navigate|jquery|getscript|extend|prototype)(?(1)[^\w%\"]|(?:\s*[^@\s\w%\",.:\/+\-]))" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects possible includes and typical script methods',id:'phpids-16',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:\d\"\s+\"\s+\d)|(?:^admin\s*\"|(\/\*)+\"+\s?(?:--|#|\/\*|{)?)|(?:\"\s*or[\w\s-]+\s*[+<>=(),-]\s*[\d\"])|(?:\"\s*[^\w\s]?=\s*\")|(?:\"\W*[+=]+\W*\")|(?:\"\s*[!=|][\d\s!=+-]+.*[\"(].*$)|(?:\"\s*[!=|][\d\s!=]+.*\d+$)|(?:\"\s*like\W+[\w\"(])|(?:\sis\s*0\W)|(?:where\s[\s\w\.,-]+\s=)|(?:\"[<>~]+\")" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects basic SQL authentication bypass attempts 1/3',id:'phpids-44',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:from\s+information_schema\W)|(?:(?:(?:current_)?user|database|schema|connection_id)\s*\([^\)]*)|(?:\";?\s*(?:select|union|having)\s*[\"(\d])|(?:\wiif\s*\()|(?:exec\s+master\.)|(?:union select @)|(?:union[\w(\s]*select)|(?:select.*\w?user\()|(?:into[\s+]+(?:dump|out)file\s*\")" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects MSSQL code execution and information gathering attempts',id:'phpids-55',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:data:.*,)|(?:\w+\s*=\W*(?!https?)\w+:)|(jar:\w+:)|(=\s*\"?\s*vbs(?:ript)?:)|(language\s*=\s?\"?\s*vbs(?:ript)?)|on\w+\s*=\*\w+\-\"?" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects data: URL injections, VBS injections and common URI schemes',id:'phpids-27',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:select\s*\*\s*from)|((?:select|create|rename|truncate|load|alter|delete|update|insert|desc)\s*\(\s*space\s*\()" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects MySQL comment-/space-obfuscated injections',id:'phpids-57',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:\w+]?(?<!href)(?<!src)(?<!longdesc)(?<!returnurl)=(?:https?|ftp):)|(?:\{\s*\$\s*\{)" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects url injections and RFE attempts',id:'phpids-61',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "([^*:\s\w,.\/?+-]\s*)?(?<![a-z]\s)(?<![a-z_@>\|])(\s*return\s*)?(?:globalstorage|sessionstorage|postmessage|callee|constructor|content|domain|prototype|try|catch|top|call|apply|url|function|object|array|string|math|if|elseif|case|switch|regex|boolean|location|settimeout|setinterval|void|setexpression|namespace|while)(?(1)[^\w%\"]|(?:\s*[^@\s\w%\",.+\-]))" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects JavaScript language constructs',id:'phpids-20',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:(?:\/|\\\\)?\.+(\/|\\\\)(?:\.+)?)|(?:\w+\.exe\??\s)|(?:;\s*\w+\s*\/[\w*-]+\/)|(?:\d\.\dx\|)|(?:%(?:c0\.|af\.|5c\.))|(?:\/(?:%2e){2})" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects basic directory traversal',id:'phpids-10',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:=\s*\d*\.\d*\?\d*\.\d*)|(?:[|&]{2,}\s*\")|(?:!\d+\.\d*\?\")|(?:\/:[\w.]+,)|(?:=[\d\W\s]*\[[^]]+\])|(?:\?\w+:\w+)" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects common XSS concatenation patterns 2/2',id:'phpids-31',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:--[^\n]*$)|(?:\<!-|-->)|(?:[^*]\/\*|\*\/[^*])|(?:(?:[\W\d]#|--|{)$)|(?:\/{3,}.*$)|(?:<!\[\W)|(?:\]!>)" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects common comment types',id:'phpids-35',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:%c0%ae\/)|(?:(?:\/|\\\\)(home|conf|usr|etc|proc|opt|s?bin|local|dev|tmp|kern|[br]oot|sys|system|windows|winnt|program|%[a-z_-]{3,}%)(?:\/|\\\\))|(?:(?:\/|\\\\)inetpub|localstart\.asp|boot\.ini)" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects specific directory and path traversal',id:'phpids-11',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:\/\w+;?\s+(?:having|and|or|select))|(?:\d\s+group\s+by.+\()|(?:(?:;|#|--)\s*(?:drop|alter))|(?:(?:;|#|--)\s*(?:update|insert)\s*\w{2,})|(?:[^\w]SET\s*@\w+)|(?:(?:n?and|x?or|not |\|\||\&\&)\s+\w+[!=+]+[\s\d]*[\"=(])" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects chained SQL injection attempts 1/2',id:'phpids-48',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:(^|\W)const\s+[\w\-]+\s*=)|(?:(?:do|for|while)\s*\([^;]+;+\))|(?:(?:^|\W)on\w+\s*=[\w\W]*(?:on\w+|alert|eval|print|confirm|prompt))|(?:groups=\d+\(\w+\))|(?:(.)\1{128,})" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects basic XSS DoS attempts',id:'phpids-65',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:binding\s?=|moz-binding|behavior\s?=)|(?:[\s\/]style\s*=\s*[-\\\\])" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects bindings and behavior injections',id:'phpids-29',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:(select|;)\s+(?:benchmark|if|sleep)\s?\(\s?\(?\s?\w+)" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects SQL benchmark and sleep injection attempts including conditional queries',id:'phpids-50',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:\\\\x[01fe][\db-ce-f])|(?:%[01fe][\db-ce-f])|(?:&#[01fe][\db-ce-f])|(?:\\\\[01fe][\db-ce-f])|(?:&#x[01fe][\db-ce-f])" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects nullbytes and other dangerous characters',id:'phpids-39',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:\.pl\?\w+=\w?\|\w+;)|(?:\|\(\w+=\*)|(?:\*\s*\)+\s*;)" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects perl echo shellcode injection and LDAP vectors',id:'phpids-64',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:@[\w-]+\s*\()|(?:]\s*\(\s*[\"!]\s*\w)|(?:<[?%](?:php)?.*(?:[?%]>)?)|(?:;[\s\w|]*\$\w+\s*=)|(?:\$\w+\s*=(?:(?:\s*\$?\w+\s*[(;])|\s*\".*\"))|(?:;\s*\{\W*\w+\s*\()" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects code injection attempts 1/3',id:'phpids-58',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:\)\s*like\s*\()|(?:having\s+[\d\w\-\"]+\s*[(=<>~])|(?:if\s?\([\d\w]\s*[=<>~])" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects conditional SQL injection attempts',id:'phpids-41',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:etc\/\W*passwd)" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects etc/passwd inclusion attempts',id:'phpids-12',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "([^*:\s\w,.\/?+-]\s*)?(?<![a-z]\s)(?<![a-z\/_@>\-\|])(\s*return\s*)?(?:create(?:element|attribute|textnode)|[a-z]+events?|setattribute|getelement\w+|appendchild|createrange|createcontextualfragment|removenode|parentnode|decodeuricomponent|\wettimeout|option|useragent)(?(1)[^\w%\"]|(?:\s*[^@\s\w%\",.+\-]))" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects JavaScript DOM/miscellaneous properties and methods',id:'phpids-15',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:alter\s*\w+.*character\s+set\s+\w+)|(\";\s*waitfor\s+time\s+\")|(?:\";.*:\s*goto)" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects MySQL charset switch and MSSQL DoS attempts',id:'phpids-52',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:(?:[;]+|(<[?%](?:php)?)).*[^\w](?:echo|print|print_r|var_dump|[fp]open))|(?:;\s*rm\s+-\w+\s+)|(?:;.*{.*\$\w+\s*=)|(?:\$\w+\s*\[\]\s*=\s*)" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects code injection attempts 3/3',id:'phpids-60',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:merge.*using\s*\()|(execute\s*immediate\s*\")|(?:\W+\d*\s+having\s+\d)|(?:match\s*[\w(),+-]+\s*against\s*\()" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects MATCH AGAINST, MERGE, EXECUTE IMMEDIATE and HAVING injections',id:'phpids-56',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:union\s*(?:all|distinct|[(!@]*)?\s*[([]\s*select)|(?:\w+\s+like\s+\")|(?:like\s*\"\%)|(?:\"\s*like\W*[\"\d])|(?:\"\s*(?:n?and|x?or|not |\|\||\&\&)\s+[\s\w]+=\s*\w+\s*having)|(?:\"\s*\*\s*\w+\W+\")|(?:\"\s*[^?\w\s=.,;)(]+\s*[(@\"]*\s*\w+\W+\w)|(?:select\s*[\[\]()\s\w\.,-]+from)" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects basic SQL authentication bypass attempts 2/3',id:'phpids-45',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "([^*:\s\w,.\/?+-]\s*)?(?<![a-z]\s)(?<![a-z\/_@>\-\|])(\s*return\s*)?(?:set|atob|btoa|charat|charcodeat|charset|concat|crypto|frames|fromcharcode|indexof|lastindexof|match|navigator|toolbar|menubar|replace|regexp|slice|split|substr|substring|escape|\w+codeuri\w*)(?(1)[^\w%\"]|(?:\s*[^@\s\w%,.+\-]))" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects JavaScript string properties and methods',id:'phpids-19',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:function[^(]*\([^)]*\))|(?:(?:delete|void|throw|instanceof|new|typeof)\W+\w+\s*[([])|([)\]]\s*\.\s*\w+\s*=)|(?:\(\s*new\s+\w+\s*\)\.)" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects common function declarations and special JS operators',id:'phpids-62',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:select\s*pg_sleep)|(?:waitfor\s*delay\s?\"+\s?\d)|(?:;\s*shutdown\s*(?:;|--|#|\/\*|{))" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects Postgres pg_sleep injection, waitfor delay attacks and database shutdown attempts',id:'phpids-54',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:\({2,}\+{2,}:{2,})|(?:\({2,}\+{2,}:+)|(?:\({3,}\++:{2,})|(?:\$\[!!!\])" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects unknown attack vectors based on PHPIDS Centrifuge detection',id:'phpids-67',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:[\s\/\"]+[-\w\/\\\\\*]+\s*=.+(?:\/\s*>))" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'finds attribute breaking injections including obfuscated attributes',id:'phpids-68',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:\"+.*[<=]\s*\"[^\"]+\")|(?:\"\w+\s*=)|(?:>\w=\/)|(?:#.+\)[\"\s]*>)|(?:\"\s*(?:src|style|on\w+)\s*=\s*\")|(?:[^\"]?\"[,;\s]+\w*[\[\(])" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'finds attribute breaking injections including whitespace attacks',id:'phpids-2',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "([^*:\s\w,.\/?+-]\s*)?(?<![a-z]\s)(?<![a-z\/_@>\|])(\s*return\s*)?(?:hash|name|href|navigateandfind|source|pathname|close|constructor|port|protocol|assign|replace|back|forward|document|ownerdocument|window|self|parent|frames|_?content|date|cookie|innerhtml|innertext|csstext+?|outerhtml|print|moveby|resizeto|createstylesheet|stylesheets)(?(1)[^\w%\"]|(?:\s*[^@\/\s\w%,.+\-]))" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects JavaScript object properties and methods',id:'phpids-17',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:\"[^\"]*[^-]?>)|(?:[^\w\s]\s*\/>)|(?:>\")" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'finds html breaking injections including whitespace attacks',id:'phpids-1',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:\+=\s*\(\s\")|(?:!+\s*[\d.,]+\w?\d*\s*\?)|(?:=\s*\[s*\])|(?:\"\s*\+\s*\")|(?:[^\s]\[\s*\d+\s*\]\s*[;+])|(?:\"\s*[&|]+\s*\")|(?:\/\s*\?\s*\")|(?:\/\s*\)\s*\[)|(?:\d\?.+:\d)|(?:]\s*\[\W*\w)|(?:[^\s]\s*=\s*\/)" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects common XSS concatenation patterns 1/2',id:'phpids-30',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:=\s*[$\w]\s*[\(\[])|(?:\(\s*(?:this|top|window|self|parent|_?content)\s*\))|(?:src\s*=s*(?:\w+:|\/\/))|(?:\w+\[(\"\w+\"|\w+\|\|))|(?:[\d\W]\|\|[\d\W]|\W=\w+,)|(?:\/\s*\+\s*[a-z\"])|(?:=\s*\$[^([]*\()|(?:=\s*\(\s*\")" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects obfuscated JavaScript script injections',id:'phpids-25',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:firefoxurl:\w+\|)|(?:(?:file|res|telnet|nntp|news|mailto|chrome)\s*:\s*[\%&#xu\/]+)|(wyciwyg|firefoxurl\s*:\s*\/\s*\/)" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects IE firefoxurl injections, cache poisoning attempts and local file inclusion/execution',id:'phpids-28',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:\"\s*(?:#|--|{))|(?:\/\*!\s?\d+)|(?:ch(?:a)?r\s*\(\s*\d)|(?:(?:(n?and|x?or|not)\s+|\|\||\&\&)\s*\w+\()" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects MySQL comments, conditions and ch(a)r injections',id:'phpids-40',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:\w+script:|@import[^\w]|;base64|base64,)|(?:\w+\s*\([\w\s]+,[\w\s]+,[\w\s]+,[\w\s]+,[\w\s]+,[\w\s]+\))" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects possible includes and packed functions',id:'phpids-14',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:(?:msgbox|eval)\s*\+|(?:language\s*=\*vbscript))" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'finds basic VBScript injection attempts',id:'phpids-69',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:(?:[;]+|(<[?%](?:php)?)).*(?:define|eval|file_get_contents|include|require|require_once|set|shell_exec|phpinfo|system|passthru|preg_\w+|execute)\s*[\"(@])" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects code injection attempts 2/3',id:'phpids-59',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:\*\/from)|(?:\+\s*\d+\s*\+\s*@)|(?:\w\"\s*(?:[-+=|@]+\s*)+[\d(])|(?:coalesce\s*\(|@@\w+\s*[^\w\s])|(?:\W!+\"\w)|(?:\";\s*(?:if|while|begin))|(?:\"[\s\d]+=\s*\d)|(?:order\s+by\s+if\w*\s*\()" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects chained SQL injection attempts 2/2',id:'phpids-49',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:[\".]script\s*\()|(?:\$\$?\s*\(\s*[\w\"])|(?:\/[\w\s]+\/\.)|(?:=\s*\/\w+\/\s*\.)|(?:(?:this|window|top|parent|frames|self|content)\[\s*[(,\"]*\s*[\w\$])|(?:,\s*new\s+\w+\s*[,;)])" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects basic obfuscated JavaScript script injections',id:'phpids-24',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:procedure\s+analyse\s*\()|(?:;\s*(declare|open)\s+[\w-]+)|(?:create\s+(procedure|function)\s*\w+\s*\(\s*\)\s*-)|(?:declare[^\w]+[@#]\s*\w+)|(exec\s*\(\s*@)" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects MySQL and PostgreSQL stored procedure/function injections',id:'phpids-53',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:[^\s]\s*=\s*script)|(?:\.\s*constructor)|(?:default\s+xml\s+namespace\s*=)|(?:\/\s*\+[^+]+\s*\+\s*\/)" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects advanced XSS probings via Script(), RexExp, constructors and XML namespaces',id:'phpids-22',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:\\\\x(?:23|27|3d))|(?:^.?\"$)|(?:^.*\\\\\".+(?<!\\\\)\")|(?:(?:^[\"\\\\]*(?:[\d\"]+|[^\"]+\"))+\s*(?:n?and|x?or|not|\|\||\&\&)\s*[\w\"[+&!@(),.-])|(?:[^\w\s]\w+\s*[|-]\s*\"\s*\w)|(?:@\w+\s+(and|or)\s*[\"\d]+)|(?:@[\w-]+\s(and|or)\s*[^\w\s])|(?:[^\w\s:]\s*\d\W+[^\w\s]\s*\".)" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects classic SQL injection probings 1/2',id:'phpids-42',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:(?:n?and|x?or|not |\|\||\&\&)\s+[\s\w+]+(?:regexp\s*\(|sounds\s+like\s*\"|[=\d]+x))|(\"\s*\d\s*(?:--|#))|(?:\"[\%&<>^=]+\d\s*(=|or))|(?:\"\W+[\w+-]+\s*=\s*\d\W+\")|(?:\"\s*is\s*\d.+\"?\w)|(?:\"\|?[\w-]{3,}[^\w\s.,]+\")|(?:\"\s*is\s*[\d.]+\s*\W.*\")" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects basic SQL authentication bypass attempts 3/3',id:'phpids-46',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:\.\s*\w+\W*=)|(?:\W\s*(?:location|document)\s*\W[^({[;]+[({[;])|(?:\(\w+\?[:\w]+\))|(?:\w{2,}\s*=\s*\d+[^&\w]\w+)|(?:\]\s*\(\s*\w+)" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects JavaScript location/document property access and window access obfuscation',id:'phpids-23',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:%u(?:ff|00|e\d)\w\w)|(?:(?:%(?:e\w|c[^3\W]|))(?:%\w\w)(?:%\w\w)?)" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects halfwidth/fullwidth encoded unicode HTML breaking attempts',id:'phpids-13',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:with\s*\(\s*.+\s*\)\s*\w+\s*\()|(?:(?:do|while|for)\s*\([^)]*\)\s*\{)|(?:\/[\w\s]*\[\W*\w)" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects self contained xss via with(), common loops and regex to string conversion',id:'phpids-6',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:^>[\w\s]*<\/?\w{2,}>)" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'finds unquoted attribute breaking injections',id:'phpids-3',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:\\\\u00[a-f0-9]{2})|(?:\\\\x0*[a-f0-9]{2})|(?:\\\\\d{2,3})" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects the IE octal, hex and unicode entities',id:'phpids-9',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:create\s+function\s+\w+\s+returns)|(?:;\s*(?:select|create|rename|truncate|load|alter|delete|update|insert|desc)\s*[\[(]?\w{2,})" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects MySQL UDF injection and other data/structure manipulation attempts',id:'phpids-51',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:^\s*[;>\"]\s*(?:union|select|create|rename|truncate|load|alter|delete|update|insert|desc))|(?:(?:select|create|rename|truncate|load|alter|delete|update|insert|desc)\s+(?:concat|char|load_file)\s?\(?)|(?:end\s*\);)|(\"\s+regexp\W)" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects concatenated basic SQL injection and SQLLFI attempts',id:'phpids-47',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:\([\w\s]+\([\w\s]+\)[\w\s]+\))|(?:(?<!(?:mozilla\/\d\.\d\s))\([^)[]+\[[^\]]+\][^)]*\))|(?:[^\s!][{([][^({[]+[{([][^}\])]+[}\])][\s+\",\d]*[}\])])|(?:\"\)?\]\W*\[)|(?:=\s*[^\s:;]+\s*[{([][^}\])]+[}\])];)" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects self-executing JavaScript functions',id:'phpids-8',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:\<[\/]?(?:[i]?frame|applet|isindex|marquee|keygen|script|audio|video|input|button|textarea|style|base|body|meta|link|object|embed|param|plaintext|xm\w+|image|im(?:g|port)))" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects possibly malicious html elements including some attributes',id:'phpids-38',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:[+\/]\s*name[\W\d]*[)+])|(?:;\W*url\s*=)|(?:[^\w\s\/?:>]\s*(?:location|referrer|name)\s*[^\/\w\s-])" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects url-, name-, JSON, and referrer-contained payload attacks',id:'phpids-4',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:\<\/\w+\s\w+)|(?:@(?:cc_on|set)[\s@,\"=])" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects attributes in closing tags and conditional compilation tokens',id:'phpids-34',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:\<base\s+)|(?:<!(?:element|entity|\[CDATA))" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects base href injections and XML entity injections',id:'phpids-37',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:\"\s*\*.+(?:or|id)\W*\"\d)|(?:\^\")|(?:^[\w\s\"-]+(?<=and\s)(?<=or\s)(?<=xor\s)(?<=nand\s)(?<=not\s)(?<=\|\|)(?<=\&\&)\w+\()|(?:\"[\s\d]*[^\w\s]+\W*\d\W*.*[\"\d])|(?:\"\s*[^\w\s?]+\s*[^\w\s]+\s*\")|(?:\"\s*[^\w\s]+\s*[\W\d].*(?:#|--))|(?:\".*\*\s*\d)|(?:\"\s*or\s[\w-]+.*\d)|(?:[()*<>%+-][\w-]+[^\w\s]+\"[^,])" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects classic SQL injection probings 2/2',id:'phpids-43',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_BODY|REQUEST_URI_RAW|ARGS|ARGS_NAMES|FILES|FILES_NAMES|XML:/* "(?:\W\s*hash\s*[^\w\s-])|(?:\w+=\W*[^,]*,[^\s(]\s*\()|(?:\?\"[^\s\"]\":)|(?:(?<!\/)__[a-z]+__)|(?:(?:^|[\s)\]\}])(?:s|g)etter\s*=)" "phase:2,capture,multiMatch,t:none,t:urlDecodeUni,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Detects hash-contained xss payload attacks, setter usage and property overloading',id:'phpids-5',tag:'WEB_ATTACK',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}" + diff --git a/rules/base_rules/modsecurity_crs_41_sql_injection_attacks.conf b/rules/base_rules/modsecurity_crs_41_sql_injection_attacks.conf new file mode 100644 index 0000000..2976e29 --- /dev/null +++ b/rules/base_rules/modsecurity_crs_41_sql_injection_attacks.conf @@ -0,0 +1,438 @@ +# --------------------------------------------------------------- +# Core ModSecurity Rule Set ver.2.0.3 +# Copyright (C) 2006-2009 Breach Security Inc. All rights reserved. +# +# The ModSecuirty Core Rule Set is distributed under GPL version 2 +# Please see the enclosed LICENCE file for full details. +# --------------------------------------------------------------- + + +# +# TODO While some of the pattern groups such as command injection are usually +# safe of false positives, other pattern groups such as SQL injection and +# XSS may require setting exceptions and therefore are set to log only by +# default. +# +# Start ModSecurity in monitoring only mode and check whether your +# application requires exceptions for a specific URL, Pattern or source IP +# before moving to blocking mode. + +# +# Prequalify Request Matches +# +SecRule REQUEST_URI|REQUEST_BODY|REQUEST_HEADERS|XML:/*|!REQUEST_HEADERS:Referer "@pmFromFile modsecurity_41_sql_injection_attacks.data" \ + "phase:2,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:lowercase,t:replaceComments,t:compressWhiteSpace,nolog,pass,setvar:tx.pm_sqli_score=+1,setvar:tx.pm_sqli_data_%{matched_var_name}=%{matched_var}" + +SecRule TX:PM_SQLI_SCORE "@eq 0" "phase:2,t:none,pass,skipAfter:END_SQL_INJECTION_PM,nolog" + +# +# Begin RegEx Checks for target locations that matched the prequalifier checks +# + + # + # Blind SQL injection + # + SecRule TX:/^PM_SQLI_DATA_*/ "\bsys\.user_catalog\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959517',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bconstraint_type\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959503',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bsys\.user_tables\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959521',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bmsysqueries\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959509',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bmsysaces\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959506',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\@\@spid\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959500',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bcharindex\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959502',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bsys\.all_tables\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959515',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bsys\.user_constraints\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959518',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bselect\b.{0,40}buser\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959514',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bwaitfor\b\W*?\bdelay\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959538',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bmsyscolumns\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959507',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bselect\b.{0,40}\bsubstring\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959513',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bsys\.user_triggers\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959522',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\blocate\W+\(" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959505',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bmsysrelationships\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959510',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bsys\.user_tab_columns\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959520',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\battnotnull\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959501',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bmsysobjects\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959508',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bsys\.tab\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959516',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bselect\b.{0,40}\bascii\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959512',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bsys\.user_views\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959523',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\binstr\W+\(" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959504',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bsys\.user_objects\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959519',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bmysql\.user\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959511',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + + SecRule TX:/^PM_SQLI_DATA_*/ "\buser_tables\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959918',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\buser_tab_columns\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959536',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\ball_objects\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959900',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bpg_class\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959910',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bsyscat\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959524',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bsubstr\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959912',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bsysdba\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959527',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\btextpos\W+\(" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959533',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\battrelid\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959901',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bpg_attribute\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959909',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\buser_password\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959917',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\buser_users\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959919',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\buser_constraints\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959534',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bxtype\W+\bchar\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959537',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\buser_objects\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959916',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bcolumn_name\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959904',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bsysfilegroups\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959528',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bsyscolumns\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959525',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bsubstring\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959913',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bsysobjects\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959530',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bobject_type\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959908',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bobject_id\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959906',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bsysibm\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959529',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\buser_ind_columns\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959535',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bcolumn_id\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959903',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bsysprocesses\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959531',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bmb_users\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959905',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\btable_name\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959914',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bsystables\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959532',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bobject_name\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959907',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\brownum\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959911',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bsysconstraints\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959526',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\batttypid\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959902',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\buser_group\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'959915',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + + + # + # SQL injection + # + + SecRule TX:/^PM_SQLI_DATA_*/ "\'msdasql\'" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959020',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bxp_makecab\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959058',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\butl_http\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959049',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bselect\b.*?\bto_number\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959035',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\btbcreator\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959046',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bsp_execute\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959038',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bgroup\b.*\bbyb.{1,100}?\bhaving\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959011',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bselect\b.*?\bdata_type\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959027',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bxp_cmdshell\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959052',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bisnull\b\W*?\(" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959018',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bopenrowset\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959023',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bunion\b.{1,100}?\bselect\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959047',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\binsert\b\W*?\binto\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959015',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bselect\b.{1,100}?\bcount\b.{1,100}?\bfrom\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959032',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\;\W*?\bdrop\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959001',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bxp_execresultset\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959055',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bxp_regaddmultistring\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959060',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\@\@version\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959004',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bxp_regread\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959065',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bloadb\W*?\bdata\b.*\binfile\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959019',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bselect\b.*?\bto_char\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959034',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bdbms_java\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959009',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bxp_enumdsn\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959054',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bxp_availablemedia\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959051',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bsp_prepare\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959042',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bnvarchar\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959021',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\butl_file\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959048',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\binner\b\W*?\bjoin\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959014',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bxp_regdeletekey\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959061',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bxp_loginconfig\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959057',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bsp_sqlexec\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959043',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bprint\b\W*?\@\@" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959024',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bselect\b.{1,100}?\bfrom\b.{1,100}?\bwhere\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959031',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bxp_regremovemultistring\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959066',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bxp_regwrite\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959067',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bvarchar\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959050',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bintob\W*?\bdumpfile\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959016',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bifb\W*?\(\W*?\bbenchmark\W*?\(" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959012',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bopenquery\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959022',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bselect\b.{1,100}?\blength\b.{1,100}?\bfrom\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959033',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bcastb\W*?\(" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959006',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bdelete\b\W*?\bfrom\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959075',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bxp_regdeletevalue\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959062',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\'sqloledb\'" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959003',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bsp_addextendedproc\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959037',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bsql_longvarchar\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959044',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bxp_dirtree\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959053',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bxp_regenumkeys\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959063',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bselect\b.*?\bdump\b.*\bfrom\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959028',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bxp_filelist\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959056',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\'sa\'" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959026',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bxp_terminate\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959068',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bsp_executesql\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959039',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bifnull\b\W*?\(" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959013',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bintob\W*?\boutfile\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959017',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bsp_makewebtask\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959040',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\'dbo\'" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959010',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bsql_variant\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959045',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bxp_ntsec\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959059',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\;\W*?\bshutdown\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959002',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bselect\b.*?\binstr\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959029',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bautonomous_transaction\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959005',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bdba_users\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959007',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bsp_oacreate\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959041',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bselect\b.{1,100}?\btop\b.{1,100}?\bfrom\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959036',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/^PM_SQLI_DATA_*/ "\bxp_regenumvalues\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'959064',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + +SecMarker END_SQL_INJECTION_PM + +SecRule REQUEST_HEADERS|XML:/*|!REQUEST_HEADERS:Referer "\b(\d+) ?= ?\1\b|[\'\"](\w+)[\'\"] ?= ?[\'\"]\2\b" \ + "phase:2,capture,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'950001',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_HEADERS|XML:/*|!REQUEST_HEADERS:Referer|!REQUEST_HEADERS:via "\b(?:coalesce\b|root\@)" \ + "phase:2,capture,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,id:'950908',tag:'WEB_ATTACK/SQL_INJECTION',setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +SecMarker BEGIN_SQL_INJECTION_WEAK +SecRule &TX:/SQL_INJECTION/ "@eq 0" "phase:2,t:none,nolog,pass,skipAfter:END_SQL_INJECTION_WEAK" + + SecRule TX:/SQL_INJECTION/ "\b(?:rel(?:(?:nam|typ)e|kind)|a(?:ttn(?:ame|um)|scii)|c(?:o(?:nver|un)t|ha?r)|s(?:hutdown|elect)|to_(?:numbe|cha)r|u(?:pdate|nion)|d(?:elete|rop)|group\b\W*\bby|having|insert|length|where)\b" \ + "phase:2,chain,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'SQL Injection Attack',id:'950001',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2'" + SecRule MATCHED_VAR "(?:[\\\(\)\%#]|--)" \ + "t:none,setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + + SecRule TX:/SQL_INJECTION/ "\b(?:benchmark|encode)\b" \ + "phase:2,chain,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Blind SQL Injection Attack',id:'950007',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2'" + SecRule MATCHED_VAR "(?:[\\\(\)\%#]|--)" "t:none,setvar:'tx.msg=%{rule.msg}',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +SecMarker END_SQL_INJECTION_WEAK diff --git a/rules/base_rules/modsecurity_crs_41_xss_attacks.conf b/rules/base_rules/modsecurity_crs_41_xss_attacks.conf new file mode 100644 index 0000000..a3b9fd1 --- /dev/null +++ b/rules/base_rules/modsecurity_crs_41_xss_attacks.conf @@ -0,0 +1,493 @@ +# --------------------------------------------------------------- +# Core ModSecurity Rule Set ver.2.0.3 +# Copyright (C) 2006-2009 Breach Security Inc. All rights reserved. +# +# The ModSecuirty Core Rule Set is distributed under GPL version 2 +# Please see the enclosed LICENCE file for full details. +# --------------------------------------------------------------- + + +# +# XSS +# +SecRule REQUEST_URI|REQUEST_BODY|REQUEST_HEADERS|XML:/*|!REQUEST_HEADERS:Referer "@pm jscript onsubmit copyparentfolder javascript meta onchange onmove onkeydown onkeyup activexobject onerror onmouseup ecmascript bexpression onmouseover vbscript: <![cdata[ http: .innerhtml settimeout shell: onabort asfunction: onkeypress onmousedown onclick .fromcharcode background-image: .cookie x-javascript ondragdrop onblur mocha: javascript: onfocus lowsrc getparentfolder onresize @import alert script onselect onmouseout application onmousemove background .execscript livescript: vbscript getspecialfolder .addimport iframe onunload createtextrange <input onload" \ + "phase:2,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,pass,nolog,skip:1,setvar:tx.pm_xss_data_%{matched_var_name}=%{matched_var}" +SecAction phase:2,pass,nolog,skipAfter:END_XSS_REGEX + + +SecRule TX:/^PM_XSS_DATA_*/ "\bgetparentfolder\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958016',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\bonmousedown\b\W*?\=" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958414',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\bsrc\b\W*?\bshell:" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958032',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\bmocha:" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958026',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\bonabort\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958027',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\blowsrc\b\W*?\bhttp:" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958054',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\bonmouseup\b\W*?\=" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958418',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\bstyle\b\W*\=.*bexpression\b\W*\(" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958034',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\bhref\b\W*?\bshell:" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958019',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\bcreatetextrange\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958013',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\bondragdrop\b\W*?\=" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958408',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\bcopyparentfolder\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958012',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\bonunload\b\W*?\=" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958423',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\.execscript\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958002',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\bgetspecialfolder\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958017',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "<body\b.*?\bonload\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958007',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\burl\b\W*?\bvbscript:" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958047',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\bonkeydown\b\W*?\=" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958410',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\bonmousemove\b\W*?\=" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958415',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\blivescript:" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958022',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\bonblur\b\W*?\=" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958405',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\bonmove\b\W*?\=" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958419',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\bsettimeout\b\W*?\(" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958028',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\< ?iframe" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958057',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\bsrc\b\W*?\bjavascript:" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958031',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "<body\b.*?\bbackground\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958006',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\bsrc\b\W*?\bvbscript:" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958033',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\btype\b\W*?\btext\b\W*?\becmascript\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958038',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\bonfocus\b\W*?\=" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958409',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\.cookie\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958001',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\<\!\[cdata\[" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958005',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\bonerror\b\W*?\=" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958404',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\blowsrc\b\W*?\bjavascript:" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958023',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\bactivexobject\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958010',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\bonkeypress\b\W*?\=" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958411',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\bonsubmit\b\W*?\=" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958422',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\btype\b\W*?\bapplication\b\W*?\bx-javascript\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958036',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\.addimport\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958000',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\bhref\b\W*?\bjavascript:" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958018',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\bonchange\b\W*?\=" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958406',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\btype\b\W*?\btext\b\W*?\bjscript\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958040',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\balert\b\W*?\(" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958052',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\btype\b\W*?\bapplication\b\W*?\bx-vbscript\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958037',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\< ?meta\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958049',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\bsrc\b\W*?\bhttp:" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958030',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\btype\b\W*?\btext\b\W*?\bvbscript\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958041',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\bonmouseout\b\W*?\=" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958416',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\blowsrc\b\W*?\bshell:" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958024',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\basfunction:" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958059',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\bonmouseover\b\W*?\=" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958417',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\bhref\b\W*?\bvbscript:" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958020',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\burl\b\W*?\bjavascript:" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958045',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\.innerhtml\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958004',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\bonselect\b\W*?\=" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958421',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\@import\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958009',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\blowsrc\b\W*?\bvbscript:" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958025',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\bonload\b\W*?\=" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958413',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\< ?script\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958051',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\bonresize\b\W*?\=" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958420',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\bonclick\b\W*?\=" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958407',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\biframe\b.{0,100}?\bsrc\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958056',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\bbackground-image:" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958011',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\bonkeyup\b\W*?\=" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958412',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "<input\b.*?\btype\b\W*?\bimage\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958008',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\burl\b\W*?\bshell:" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958046',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\btype\b\W*?\btext\b\W*?\bjavascript\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958039',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule TX:/^PM_XSS_DATA_*/ "\.fromcharcode\b" \ + "phase:2,capture,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,msg:'Cross-site Scripting (XSS) Attack',id:'958003',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + + +SecMarker END_XSS_REGEX + +# Detect tags that are the most common direct HTML injection points. +# +# <a href=javascript:... +# <applet src="..." type=text/html> +# <applet src="data:text/html;base64,PHNjcmlwdD5hbGVydCgvWFNTLyk8L3NjcmlwdD4" type=text/html> +# <base href=javascript:... +# <base href=... // change base URL to something else to exploit relative filename inclusion +# <bgsound src=javascript:... +# <body background=javascript:... +# <body onload=... +# <embed src=http://www.example.com/flash.swf allowScriptAccess=always +# <embed src="data:image/svg+xml; +# <frameset><frame src="javascript:..."></frameset> +# <iframe src=javascript:... +# <img src=x onerror=... +# <input type=image src=javascript:... +# <layer src=... +# <link href="javascript:..." rel="stylesheet" type="text/css" +# <link href="http://www.example.com/xss.css" rel="stylesheet" type="text/css" +# <meta http-equiv="refresh" content="0;url=javascript:..." +# <meta http-equiv="refresh" content="0;url=http://;javascript:..." // evasion +# <meta http-equiv="link" rel=stylesheet content="http://www.example.com/xss.css"> +# <meta http-equiv="Set-Cookie" content="NEW_COOKIE_VALUE"> +# <object data=http://www.example.com +# <object type=text/x-scriptlet data=... +# <object type=application/x-shockwave-flash data=xss.swf> +# <object classid=clsid:ae24fdae-03c6-11d1-8b76-0080c744f389><param name=url value=javascript:...></object> // not verified +# <script>...</script> +# <script src=http://www.example.com/xss.js></script> - TODO add another rule for this +# <script src="data:text/javascript,alert(1)"></script> +# <script src="data:text/javascript;base64,PHNjcmlwdD5hbGVydChkb2N1bWVudC5jb29raWUpOzwvc2NyaXB0Pg=="></script> +# <style>STYLE</style> +# <style type=text/css>STYLE</style> +# <style type=text/javascript>alert('xss')</style> +# <table background=javascript:... +# <td background=javascript: +# +# +# NOTES +# +# - Reference the WASC Script Mapping Project - http://projects.webappsec.org/Script-Mapping +# +# - Not using closing brackets because they are not needed for the +# attacks to succeed. The following seems to work in FF: <body/s/onload=... +# +# - Also, browsers sometimes tend to translate < into >, in order to "repair" +# what they think was a mistake made by the programmer/template designer. +# +# - Browsers are flexible when it comes to what they accept as separator between +# tag names and attributes. The following is commonly used in payloads: <img/src=... +# A better example: <BODY onload!#$%&()*~+-_.,:;?@[/|\]^=alert("XSS")> +# +# - Grave accents are sometimes used as an evasion technique (as a replacement for quotes), +# but I don't believe we need to look for quotes anywhere. +# +# - Links do not have to be fully qualified. For example, the following works: +# <script src="//ha.ckers.org/.j"> +# +SecRule REQUEST_URI_RAW|REQUEST_BODY "<(a|abbr|acronym|address|applet|area|audioscope|b|base|basefront|bdo|bgsound|big|blackface|blink|blockquote|body|bq|br|button|caption|center|cite|code|col|colgroup|comment|dd|del|dfn|dir|div|dl|dt|em|embed|fieldset|fn|font|form|frame|frameset|h1|head|hr|html|i|iframe|ilayer|img|input|ins|isindex|kdb|keygen|label|layer|legend|li|limittext|link|listing|map|marquee|menu|meta|multicol|nobr|noembed|noframes|noscript|nosmartquotes|object|ol|optgroup|option|p|param|plaintext|pre|q|rt|ruby|s|samp|script|select|server|shadow|sidebar|small|spacer|span|strike|strong|style|sub|sup|table|tbody|td|textarea|tfoot|th|thead|title|tr|tt|u|ul|var|wbr|xml|xmp)\W" \ + "phase:2,t:none,t:jsDecode,t:lowercase,block,nolog,auditlog,msg:'XSS Attack Detected',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_URI_RAW|REQUEST_BODY "\ballowscriptaccess\b|\brel\b\W*?=" \ + "phase:2,t:none,t:lowercase,block,nolog,auditlog,msg:'XSS Attack Detected',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+20,setvar:tx.anomaly_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +# TODO Would evasion such as null and whitespace work here? +# +SecRule REQUEST_URI_RAW|REQUEST_BODY "application/x-shockwave-flash|image/svg\+xml|text/(css|html|ecmascript|javascript|vbscript|x-(javascript|scriptlet|vbscript))" \ + "phase:2,t:none,t:htmlEntityDecode,t:lowercase,block,nolog,auditlog,msg:'XSS Attack Detected',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+20,setvar:tx.anomaly_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +# Detect event handler names +# +# <body onload=...> +# <img src=x onerror=...> +# +SecRule REQUEST_URI_RAW|REQUEST_BODY "\bon(abort|blur|change|click|dblclick|dragdrop|error|\ +focus|keydown|keypress|keyup|load|mousedown|mousemove|mouseout\ +|mouseover|mouseup|move|readystatechange|reset|resize|select|submit|unload)\b\W*?=" \ + "phase:2,t:none,t:lowercase,block,nolog,auditlog,msg:'XSS Attack Detected',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +# Detect usage of common URI attributes (e.g. src) +# +# <a href="javascript:...">Link</a> +# <base href="javascript:..."> +# <bgsound src="javascript:..."> +# <body background="javascript:..."> +# <frameset><frame src="javascript:..."></frameset> +# <iframe src=javascript:...> +# <img dynsrc=javascript:...> +# <img lowsrc=javascript:...> +# <img src=javascript:...> +# <input type=image src=javascript:...> +# +SecRule REQUEST_URI_RAW|REQUEST_BODY "\b(background|dynsrc|href|lowsrc|src)\b\W*?=" \ + "phase:2,t:none,t:lowercase,block,nolog,auditlog,msg:'XSS Attack Detected',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +# As above, but try to catch the other bit that is necessary to execute the attack. +# +# <meta http-equiv="refresh" content="0;url=data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K"> +# <img src=jaVaScrIpt:...> +# <img src=a;avascript:...> (not evasion) +# <img src="jav ascript:..."> (embedded tab; null byte, other whitespace characters work too) +# <img src="jaa ascript:..."> (the combination of the above two) +# +# NOTES +# +# - htmlEntityDecode needs to be applied because this content appears in HTML +# attributes, so it's not evasion. +# +# TODO I think asfunction only work in HTML files handled by Flash. Needs verifying. +# +SecRule REQUEST_URI_RAW|REQUEST_BODY "(asfunction|javascript|vbscript|data|mocha|livescript):" \ + "phase:2,t:none,t:htmlEntityDecode,t:lowercase,t:removeNulls,t:removeWhitespace,block,nolog,auditlog,msg:'XSS Attack Detected',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +# Detect attempts to use the style attribute, which works with any tag in at +# least one major browser. +# +# <div style="background-image: url(javascript:...)"> +# +SecRule REQUEST_URI_RAW|REQUEST_BODY "\bstyle\b\W*?=" \ + "phase:2,t:none,t:lowercase,block,nolog,auditlog,msg:'XSS Attack Detected',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +# -- JavaScript fragments -- +# +# TODO Need more fragments. +# +# TODO What about JavaScript code hidden behind CSS? +# +# TODO There is a bunch of DOM-manipulation stuff that we want to cover here. +# +# alert(String.fromCharCode(88,83,83) +# - window.name +# - document.cookie +# - document.location +# - document.write +# - document.styleSheets[0].addImport('yourstylesheet.css', 2); +# - window.execScript("alert('test');", "JavaScript"); +# - document.body.innerHTML = '' +# - newObj = new ActiveXObject(servername.typename[, location]) +# - A list of keywords here: http://technet.microsoft.com/en-gb/library/bb794749.aspx +# - setTimeout("alert('xss')", 1000) +# - xmlHttp.onreadystatechange=function() {} +# - eval(location.hash.substr(1)) // used to execute JavaScript in fragment identifier +# +# NOTES: +# +# - JavaScript evasion: +# +# http://www.thespanner.co.uk/2007/09/19/javascript-for-hackers/ +# http://www.thespanner.co.uk/2007/12/12/javascript-for-hackers-part-2/ +# +SecRule REQUEST_URI_RAW|REQUEST_BODY "(fromcharcode|alert|eval)\s*\(" \ + "phase:2,t:none,t:htmlEntityDecode,t:jsDecode,t:lowercase,block,nolog,auditlog,msg:'XSS Attack Detected',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+20,setvar:tx.anomaly_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + + +# -- CSS attack fragments -- + +# <div style="background-image: url(javascript:...)"> +# <div style="background-image: url(javascript:alert('XSS'))"> // not used +# <div style="width: expression(...);"> +# <img style="x:expression(document.write(1))"> +# <xss style="behavior: url(http://ha.ckers.org/xss.htc);"> +# - <style>li {list-style-image: url("javascript:alert('XSS')");}</style><ul><li>xss +# <style>@import url(...);</style> +# -moz-binding:url(...) +# background:url("javascript:...") +# </xss/*-*/style=xss:e/**/xpression(alert(1337))> (comment evasion) // TODO Verify +# <style type="text/css">@i\m\p\o\rt url(...);</style> (css escaping evasion) +# <li style="behavior:url(hilite.htc)">xss +# +# Interesting CSS injection: http://www.thespanner.co.uk/2007/11/26/ultimate-xss-css-injection/ +# +# Ref: http://crawlmsdn.microsoft.com/en-us/library/ms531078(vs.85).aspx (DHTML Behaviors) +# +# Note: A lot of these seem to need to use the "javascript:" prefix to execute anything. Requiring +# a match of that before we do anything might help us reduce the FP rate. +# +SecRule REQUEST_URI_RAW|REQUEST_BODY "background\b\W*?:\W*?url|background-image\b\W*?:|behavior\b\W*?:\W*?url|-moz-binding\b|@import\b|expression\b\W*?\(" \ + "phase:2,t:none,t:htmlEntityDecode,t:cssDecode,t:replaceComments,t:removeWhitespace,t:lowercase,block,nolog,auditlog,msg:'XSS Attack Detected',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +# <C><![CDATA[<IMG SRC="javas]]><![CDATA[cript:alert('XSS');">]]></C> // evasion +SecRule REQUEST_URI_RAW|REQUEST_BODY "<!\[cdata\[|\]\]>" \ + "phase:2,t:none,t:lowercase,block,nolog,auditlog,msg:'XSS Attack Detected',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + + +# -- Misc -- + +# alert('xss') +# alert("xss") +# alert(/xss/) +# <xss> +# +SecRule REQUEST_URI_RAW|REQUEST_BODY "[/'\"<]xss[/'\">]" \ + "phase:2,t:none,t:lowercase,block,nolog,auditlog,msg:'XSS Attack Detected',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +# String.fromCharCode(88,83,83) +# +SecRule REQUEST_URI_RAW|REQUEST_BODY "(88,83,83)" \ + "phase:2,t:none,t:lowercase,block,nolog,auditlog,msg:'XSS Attack Detected',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +# '';!--"<XSS>=&{()} +# +SecRule REQUEST_URI_RAW|REQUEST_BODY "'';!--\"<xss>=&{()}" \ + "phase:2,t:none,t:lowercase,block,nolog,auditlog,msg:'XSS Attack Detected',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +# Handle &{alert('xss')} which is supposed to work in Netscape 4. +# +SecRule REQUEST_URI_RAW|REQUEST_BODY "&{" \ + "phase:2,t:none,block,nolog,auditlog,msg:'XSS Attack Detected',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + + +# <!DOCTYPE html [ +# <!ENTITY inject "<script>alert(1)</script>"> +# ]> +# <html xmlns="http://www.w3.org/1999/xhtml"> +# <head> +# <title>Test +# +# +# +# &inject; +# +# +# +SecRule REQUEST_URI_RAW|REQUEST_BODY ".*?((@[i\\\\])|(([:=]|(&[#\(\)=]x?0*((58)|(3A)|(61)|(3D));?)).*?([(\\\\]|(&[#()=]x?0*((40)|(28)|(92)|(5C));?)))))" "phase:2,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,block,nolog,auditlog,msg:'IE XSS Filters - Attack Detected',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+20,setvar:tx.anomaly_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_URI_RAW|REQUEST_BODY "(?i:[ /+\t\"\'`]style[ /+\t]*?=.*?([:=]|(&[#()=]x?0*((58)|(3A)|(61)|(3D));?)).*?([(\\\\]|(&[#()=]x?0*((40)|(28)|(92)|(5C));?)))" "phase:2,t:none,t:lowercase,block,nolog,auditlog,msg:'IE XSS Filters - Attack Detected',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+20,setvar:tx.anomaly_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_URI_RAW|REQUEST_BODY "(?i:])" "phase:2,t:none,t:lowercase,block,nolog,auditlog,msg:'IE XSS Filters - Attack Detected',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+20,setvar:tx.anomaly_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_URI_RAW|REQUEST_BODY "(?i:)" "phase:2,t:none,t:lowercase,block,nolog,auditlog,msg:'IE XSS Filters - Attack Detected',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+20,setvar:tx.anomaly_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_URI_RAW|REQUEST_BODY "(?i:)" "phase:2,t:none,t:lowercase,block,nolog,auditlog,msg:'IE XSS Filters - Attack Detected',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+20,setvar:tx.anomaly_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_URI_RAW|REQUEST_BODY "(?i:[\"\'][ ]*(([^a-z0-9~_:\'\" ])|(in)).*?(((l|(\\\\u006C))(o|(\\\\u006F))(c|(\\\\u0063))(a|(\\\\u0061))(t|(\\\\u0074))(i|(\\\\u0069))(o|(\\\\u006F))(n|(\\\\u006E)))|((n|(\\\\u006E))(a|(\\\\u0061))(m|(\\\\u006D))(e|(\\\\u0065)))).*?=)" "phase:2,t:none,t:lowercase,block,nolog,auditlog,msg:'IE XSS Filters - Attack Detected',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+20,setvar:tx.anomaly_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_URI_RAW|REQUEST_BODY "(?i:[\"\'][ ]*(([^a-z0-9~_:\'\" ])|(in)).+?(([.].+?)|([\[].*?[\]].*?))=)" "phase:2,t:none,t:lowercase,block,nolog,auditlog,msg:'IE XSS Filters - Attack Detected',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+20,setvar:tx.anomaly_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_URI_RAW|REQUEST_BODY "(?i:[\"\'].*?\[ ]*(([^a-z0-9~_:\'\" ])|(in)).+?\()" "phase:2,t:none,t:lowercase,block,nolog,auditlog,msg:'IE XSS Filters - Attack Detected',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+20,setvar:tx.anomaly_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + +SecRule REQUEST_URI_RAW|REQUEST_BODY "(?i:[\"\'][ ]*(([^a-z0-9~_:\'\" ])|(in)).+?\(.*?\))" "phase:2,t:none,t:lowercase,block,nolog,auditlog,msg:'IE XSS Filters - Attack Detected',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+20,setvar:tx.anomaly_score=+1,setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{matched_var}" + diff --git a/rules/base_rules/modsecurity_crs_45_trojans.conf b/rules/base_rules/modsecurity_crs_45_trojans.conf new file mode 100644 index 0000000..5cd41a4 --- /dev/null +++ b/rules/base_rules/modsecurity_crs_45_trojans.conf @@ -0,0 +1,34 @@ +# --------------------------------------------------------------- +# Core ModSecurity Rule Set ver.2.0.3 +# Copyright (C) 2006-2009 Breach Security Inc. All rights reserved. +# +# The ModSecuirty Core Rule Set is distributed under GPL version 2 +# Please see the enclosed LICENCE file for full details. +# --------------------------------------------------------------- + + +# The trojan access detection rules detects access to known Trojans already +# installed on a server. Uploading of Trojans is part of the Anti-Virus rules +# and uses external Anti Virus program when uploading files. +# +# Detection of Trojans access is especially important in a hosting environment +# where the actual Trojan upload may be done through valid methods and not +# through hacking. +# -- +# +# NOTE Trojans detection is based on checking elements controlled by the client. +# A determined attacked can bypass those checks. We are working on +# enchaining the checks so it would require a major change in the Trojan +# to overcome. +# +# NOTE We found out that Trojan horses are not detected easily by Anti-Virus +# software when uploading as the signature set of AV software is not tuned +# for this purpose. We are working on adding signature tuned to detect +# Trojans upload to file uploading inspection. +# + +SecRule REQUEST_HEADERS_NAMES "x_(?:key|file)\b" "phase:2,t:none,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,status:404,msg:'Backdoor access',id:'950110',tag:'MALICIOUS_SOFTWARE/TROJAN',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.trojan_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-MALICIOUS_SOFTWARE/TROJAN-%{matched_var_name}=%{matched_var}" +SecRule REQUEST_FILENAME "root\.exe" \ + "phase:2,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,status:404,msg:'Backdoor access',id:'950921',tag:'MALICIOUS_SOFTWARE/TROJAN',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.trojan_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-MALICIOUS_SOFTWARE/TROJAN-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "(?:[^<]*?(?:\b(?:(?:c(?:ehennemden|gi-telnet)|gamma web shell)\b|imhabirligi phpftp)|(?:r(?:emote explorer|57shell)|aventis klasvayv|zehir)\b|\.::(?:news remote php shell injection::\.| rhtools\b)|ph(?:p(?:(?: commander|-terminal)\b|remoteview)|vayv)|myshell)|\b(?:(?:(?:microsoft windows\b.{0,10}?\bversion\b.{0,20}?\(c\) copyright 1985-.{0,10}?\bmicrosoft corp|ntdaddy v1\.9 - obzerve \| fux0r inc)\.|(?:www\.sanalteror\.org - indexer and read|haxplor)er|php(?:konsole| shell)|c99shell)\b|aventgrup\.<br>|drwxr))" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:404,msg:'Backdoor access',id:'950922',tag:'MALICIOUS_SOFTWARE/TROJAN',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.trojan_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-MALICIOUS_SOFTWARE/TROJAN-%{matched_var_name}=%{matched_var}" diff --git a/rules/base_rules/modsecurity_crs_46_et_sql_injection.conf b/rules/base_rules/modsecurity_crs_46_et_sql_injection.conf new file mode 100644 index 0000000..d5dc540 --- /dev/null +++ b/rules/base_rules/modsecurity_crs_46_et_sql_injection.conf @@ -0,0 +1,2346 @@ +SecRule REQUEST_FILENAME "!@pmFromFile modsecurity_46_et_sql_injection.data" "phase:2,nolog,pass,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,skipAfter:END_ET_SQLI_RULES" + +# (sid 2007508) ET WEB_SPECIFIC 20/20 Auto Gallery SQL Injection Attempt -- vehiclelistings.asp vehicleID +SecRule REQUEST_URI_RAW "(?i:\/vehiclelistings\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007508,rev:3,msg:'ET WEB_SPECIFIC 20/20 Auto Gallery SQL Injection Attempt -- vehiclelistings.asp vehicleID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_2020_Auto_gallery'" +SecRule &TX:'/SQL_INJECTION.*ARGS:vehicleID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC 20/20 Auto Gallery SQL Injection Attempt -- vehiclelistings.asp vehicleID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007514) ET WEB_SPECIFIC 20/20 Auto Gallery SQL Injection Attempt -- vehiclelistings.asp categoryID_list +SecRule REQUEST_URI_RAW "(?i:\/vehiclelistings\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007514,rev:3,msg:'ET WEB_SPECIFIC 20/20 Auto Gallery SQL Injection Attempt -- vehiclelistings.asp categoryID_list ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_2020_Auto_gallery'" +SecRule &TX:'/SQL_INJECTION.*ARGS:categoryID_list/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC 20/20 Auto Gallery SQL Injection Attempt -- vehiclelistings.asp categoryID_list ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007520) ET WEB_SPECIFIC 20/20 Auto Gallery SQL Injection Attempt -- vehiclelistings.asp sale_type +SecRule REQUEST_URI_RAW "(?i:\/vehiclelistings\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007520,rev:3,msg:'ET WEB_SPECIFIC 20/20 Auto Gallery SQL Injection Attempt -- vehiclelistings.asp sale_type ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_2020_Auto_gallery'" +SecRule &TX:'/SQL_INJECTION.*ARGS:sale_type/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC 20/20 Auto Gallery SQL Injection Attempt -- vehiclelistings.asp sale_type ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007526) ET WEB_SPECIFIC 20/20 Auto Gallery SQL Injection Attempt -- vehiclelistings.asp stock_number +SecRule REQUEST_URI_RAW "(?i:\/vehiclelistings\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007526,rev:3,msg:'ET WEB_SPECIFIC 20/20 Auto Gallery SQL Injection Attempt -- vehiclelistings.asp stock_number ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_2020_Auto_gallery'" +SecRule &TX:'/SQL_INJECTION.*ARGS:stock_number/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC 20/20 Auto Gallery SQL Injection Attempt -- vehiclelistings.asp stock_number ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007532) ET WEB_SPECIFIC 20/20 Auto Gallery SQL Injection Attempt -- vehiclelistings.asp manufacturer +SecRule REQUEST_URI_RAW "(?i:\/vehiclelistings\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007532,rev:3,msg:'ET WEB_SPECIFIC 20/20 Auto Gallery SQL Injection Attempt -- vehiclelistings.asp manufacturer ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_2020_Auto_gallery'" +SecRule &TX:'/SQL_INJECTION.*ARGS:manufacturer/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC 20/20 Auto Gallery SQL Injection Attempt -- vehiclelistings.asp manufacturer ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007538) ET WEB_SPECIFIC 20/20 Auto Gallery SQL Injection Attempt -- vehiclelistings.asp model +SecRule REQUEST_URI_RAW "(?i:\/vehiclelistings\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007538,rev:3,msg:'ET WEB_SPECIFIC 20/20 Auto Gallery SQL Injection Attempt -- vehiclelistings.asp model ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_2020_Auto_gallery'" +SecRule &TX:'/SQL_INJECTION.*ARGS:model/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC 20/20 Auto Gallery SQL Injection Attempt -- vehiclelistings.asp model ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007544) ET WEB_SPECIFIC 20/20 Auto Gallery SQL Injection Attempt -- vehiclelistings.asp vehicleID +SecRule REQUEST_URI_RAW "(?i:\/vehiclelistings\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007544,rev:3,msg:'ET WEB_SPECIFIC 20/20 Auto Gallery SQL Injection Attempt -- vehiclelistings.asp vehicleID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_2020_Auto_gallery'" +SecRule &TX:'/SQL_INJECTION.*ARGS:vehicleID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC 20/20 Auto Gallery SQL Injection Attempt -- vehiclelistings.asp vehicleID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007550) ET WEB_SPECIFIC 20/20 Auto Gallery SQL Injection Attempt -- vehiclelistings.asp year +SecRule REQUEST_URI_RAW "(?i:\/vehiclelistings\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007550,rev:3,msg:'ET WEB_SPECIFIC 20/20 Auto Gallery SQL Injection Attempt -- vehiclelistings.asp year ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_2020_Auto_gallery'" +SecRule &TX:'/SQL_INJECTION.*ARGS:year/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC 20/20 Auto Gallery SQL Injection Attempt -- vehiclelistings.asp year ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007556) ET WEB_SPECIFIC 20/20 Auto Gallery SQL Injection Attempt -- vehiclelistings.asp vin +SecRule REQUEST_URI_RAW "(?i:\/vehiclelistings\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007556,rev:3,msg:'ET WEB_SPECIFIC 20/20 Auto Gallery SQL Injection Attempt -- vehiclelistings.asp vin ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_2020_Auto_gallery'" +SecRule &TX:'/SQL_INJECTION.*ARGS:vin/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC 20/20 Auto Gallery SQL Injection Attempt -- vehiclelistings.asp vin ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007562) ET WEB_SPECIFIC 20/20 Auto Gallery SQL Injection Attempt -- vehiclelistings.asp listing_price +SecRule REQUEST_URI_RAW "(?i:\/vehiclelistings\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007562,rev:3,msg:'ET WEB_SPECIFIC 20/20 Auto Gallery SQL Injection Attempt -- vehiclelistings.asp listing_price ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_2020_Auto_gallery'" +SecRule &TX:'/SQL_INJECTION.*ARGS:listing_price/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC 20/20 Auto Gallery SQL Injection Attempt -- vehiclelistings.asp listing_price ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004063) ET WEB_SPECIFIC 2z Project SQL Injection Attempt -- rating.php rating +SecRule REQUEST_URI_RAW "(?i:\/includes\/rating\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004063,rev:4,msg:'ET WEB_SPECIFIC 2z Project SQL Injection Attempt -- rating.php rating ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_2z_project'" +SecRule &TX:'/SQL_INJECTION.*ARGS:rating/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC 2z Project SQL Injection Attempt -- rating.php rating ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004075) ET WEB_SPECIFIC 2z Project SQL Injection Attempt -- rating.php post_id +SecRule REQUEST_URI_RAW "(?i:\/includes\/rating\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004075,rev:4,msg:'ET WEB_SPECIFIC 2z Project SQL Injection Attempt -- rating.php post_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_2z_project'" +SecRule &TX:'/SQL_INJECTION.*ARGS:post_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC 2z Project SQL Injection Attempt -- rating.php post_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007221) ET WEB_SPECIFIC 8pixel.net simpleblog SQL Injection Attempt -- edit.asp id +SecRule REQUEST_URI_RAW "(?i:\/admin\/edit\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007221,rev:3,msg:'ET WEB_SPECIFIC 8pixel.net simpleblog SQL Injection Attempt -- edit.asp id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_8pixel'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC 8pixel.net simpleblog SQL Injection Attempt -- edit.asp id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005061) ET WEB_SPECIFIC ACGVannu SQL Injection Attempt -- modif.html id_mod +SecRule REQUEST_URI_RAW "(?i:\/templates\/modif\.html)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005061,rev:4,msg:'ET WEB_SPECIFIC ACGVannu SQL Injection Attempt -- modif.html id_mod ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_ACGVannu'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id_mod/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC ACGVannu SQL Injection Attempt -- modif.html id_mod ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005577) ET WEB_SPECIFIC All In One Control Panel (AIOCP) SQL Injection Attempt -- cp_authorization.php xuser_name +SecRule REQUEST_URI_RAW "(?i:\/shared\/code\/cp_authorization\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005577,rev:3,msg:'ET WEB_SPECIFIC All In One Control Panel (AIOCP) SQL Injection Attempt -- cp_authorization.php xuser_name ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_AIOCP'" +SecRule &TX:'/SQL_INJECTION.*ARGS:xuser_name/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC All In One Control Panel (AIOCP) SQL Injection Attempt -- cp_authorization.php xuser_name ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005583) ET WEB_SPECIFIC All In One Control Panel (AIOCP) SQL Injection Attempt -- cp_downloads.php did +SecRule REQUEST_URI_RAW "(?i:\/public\/code\/cp_downloads\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005583,rev:3,msg:'ET WEB_SPECIFIC All In One Control Panel (AIOCP) SQL Injection Attempt -- cp_downloads.php did ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_AIOCP'" +SecRule &TX:'/SQL_INJECTION.*ARGS:did/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC All In One Control Panel (AIOCP) SQL Injection Attempt -- cp_downloads.php did ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004533) ET WEB_SPECIFIC AJ Auction SQL Injection Attempt -- subcat.php cate_id +SecRule REQUEST_URI_RAW "(?i:\/subcat\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004533,rev:4,msg:'ET WEB_SPECIFIC AJ Auction SQL Injection Attempt -- subcat.php cate_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_AJ'" +SecRule &TX:'/SQL_INJECTION.*ARGS:cate_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC AJ Auction SQL Injection Attempt -- subcat.php cate_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004539) ET WEB_SPECIFIC AJDating SQL Injection Attempt -- view_profile.php user_id +SecRule REQUEST_URI_RAW "(?i:\/view_profile\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004539,rev:4,msg:'ET WEB_SPECIFIC AJDating SQL Injection Attempt -- view_profile.php user_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_AJ'" +SecRule &TX:'/SQL_INJECTION.*ARGS:user_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC AJDating SQL Injection Attempt -- view_profile.php user_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004545) ET WEB_SPECIFIC AJ Classifieds SQL Injection Attempt -- postingdetails.php postingid +SecRule REQUEST_URI_RAW "(?i:\/postingdetails\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004545,rev:4,msg:'ET WEB_SPECIFIC AJ Classifieds SQL Injection Attempt -- postingdetails.php postingid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_AJ'" +SecRule &TX:'/SQL_INJECTION.*ARGS:postingid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC AJ Classifieds SQL Injection Attempt -- postingdetails.php postingid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004550) ET WEB_SPECIFIC AJ Forum SQL Injection Attempt -- topic_title.php td_id +SecRule REQUEST_URI_RAW "(?i:\/topic_title\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004550,rev:4,msg:'ET WEB_SPECIFIC AJ Forum SQL Injection Attempt -- topic_title.php td_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_AJ'" +SecRule &TX:'/SQL_INJECTION.*ARGS:td_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC AJ Forum SQL Injection Attempt -- topic_title.php td_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006823) ET WEB_SPECIFIC ASPMForum SQL Injection Attempt -- forum2.asp soruid +SecRule REQUEST_URI_RAW "(?i:\/forum2\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006823,rev:3,msg:'ET WEB_SPECIFIC ASPMForum SQL Injection Attempt -- forum2.asp soruid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_ASPMForum'" +SecRule &TX:'/SQL_INJECTION.*ARGS:soruid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC ASPMForum SQL Injection Attempt -- forum2.asp soruid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006829) ET WEB_SPECIFIC ASPMForum SQL Injection Attempt -- kullanicilistesi.asp ak +SecRule REQUEST_URI_RAW "(?i:\/kullanicilistesi\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006829,rev:3,msg:'ET WEB_SPECIFIC ASPMForum SQL Injection Attempt -- kullanicilistesi.asp ak ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_ASPMForum'" +SecRule &TX:'/SQL_INJECTION.*ARGS:ak/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC ASPMForum SQL Injection Attempt -- kullanicilistesi.asp ak ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006835) ET WEB_SPECIFIC ASPMForum SQL Injection Attempt -- aramayap.asp kelimeler +SecRule REQUEST_URI_RAW "(?i:\/aramayap\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006835,rev:3,msg:'ET WEB_SPECIFIC ASPMForum SQL Injection Attempt -- aramayap.asp kelimeler ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_ASPMForum'" +SecRule &TX:'/SQL_INJECTION.*ARGS:kelimeler/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC ASPMForum SQL Injection Attempt -- aramayap.asp kelimeler ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006841) ET WEB_SPECIFIC ASPMForum SQL Injection Attempt -- giris.asp kullaniciadi +SecRule REQUEST_URI_RAW "(?i:\/giris\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006841,rev:3,msg:'ET WEB_SPECIFIC ASPMForum SQL Injection Attempt -- giris.asp kullaniciadi ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_ASPMForum'" +SecRule &TX:'/SQL_INJECTION.*ARGS:kullaniciadi/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC ASPMForum SQL Injection Attempt -- giris.asp kullaniciadi ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006847) ET WEB_SPECIFIC ASPMForum SQL Injection Attempt -- mesajkutum.asp mesajno +SecRule REQUEST_URI_RAW "(?i:\/mesajkutum\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006847,rev:3,msg:'ET WEB_SPECIFIC ASPMForum SQL Injection Attempt -- mesajkutum.asp mesajno ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_ASPMForum'" +SecRule &TX:'/SQL_INJECTION.*ARGS:mesajno/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC ASPMForum SQL Injection Attempt -- mesajkutum.asp mesajno ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006853) ET WEB_SPECIFIC ASPMForum SQL Injection Attempt -- kullanicilistesi.asp harf +SecRule REQUEST_URI_RAW "(?i:\/kullanicilistesi\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006853,rev:3,msg:'ET WEB_SPECIFIC ASPMForum SQL Injection Attempt -- kullanicilistesi.asp harf ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_ASPMForum'" +SecRule &TX:'/SQL_INJECTION.*ARGS:harf/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC ASPMForum SQL Injection Attempt -- kullanicilistesi.asp harf ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006859) ET WEB_SPECIFIC ASPMForum SQL Injection Attempt -- forum.asp baslik +SecRule REQUEST_URI_RAW "(?i:\/forum\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006859,rev:3,msg:'ET WEB_SPECIFIC ASPMForum SQL Injection Attempt -- forum.asp baslik ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_ASPMForum'" +SecRule &TX:'/SQL_INJECTION.*ARGS:baslik/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC ASPMForum SQL Injection Attempt -- forum.asp baslik ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005109) ET WEB_SPECIFIC ASP EDGE SQL Injection Attempt -- artreplydelete.asp username +SecRule REQUEST_URI_RAW "(?i:\/artreplydelete\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005109,rev:4,msg:'ET WEB_SPECIFIC ASP EDGE SQL Injection Attempt -- artreplydelete.asp username ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_ASP_EDGE'" +SecRule &TX:'/SQL_INJECTION.*ARGS:username/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC ASP EDGE SQL Injection Attempt -- artreplydelete.asp username ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005168) ET WEB_SPECIFIC ASP NEWS SQL Injection Attempt -- news_detail.asp id +SecRule REQUEST_URI_RAW "(?i:\/news_detail\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005168,rev:4,msg:'ET WEB_SPECIFIC ASP NEWS SQL Injection Attempt -- news_detail.asp id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_ASP_NEWS'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC ASP NEWS SQL Injection Attempt -- news_detail.asp id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005174) ET WEB_SPECIFIC ASP EDGE SQL Injection Attempt -- user.asp user +SecRule REQUEST_URI_RAW "(?i:\/user\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005174,rev:4,msg:'ET WEB_SPECIFIC ASP EDGE SQL Injection Attempt -- user.asp user ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_ASP_NEWS'" +SecRule &TX:'/SQL_INJECTION.*ARGS:user/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC ASP EDGE SQL Injection Attempt -- user.asp user ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005887) ET WEB_SPECIFIC ASP SiteWare autoDealer SQL Injection Attempt -- detail.asp iPro +SecRule REQUEST_URI_RAW "(?i:\/detail\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005887,rev:4,msg:'ET WEB_SPECIFIC ASP SiteWare autoDealer SQL Injection Attempt -- detail.asp iPro ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_ASP_Siteware'" +SecRule &TX:'/SQL_INJECTION.*ARGS:iPro/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC ASP SiteWare autoDealer SQL Injection Attempt -- detail.asp iPro ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007004) ET WEB_SPECIFIC ASP ListPics SQL Injection Attempt -- listpics.asp ID +SecRule REQUEST_URI_RAW "(?i:\/listpics\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007004,rev:3,msg:'ET WEB_SPECIFIC ASP ListPics SQL Injection Attempt -- listpics.asp ID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_ASP_listpics'" +SecRule &TX:'/SQL_INJECTION.*ARGS:ID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC ASP ListPics SQL Injection Attempt -- listpics.asp ID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004323) ET WEB_SPECIFIC Absolute Image Gallery SQL Injection Attempt -- gallery.asp categoryid +SecRule REQUEST_URI_RAW "(?i:\/gallery\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004323,rev:3,msg:'ET WEB_SPECIFIC Absolute Image Gallery SQL Injection Attempt -- gallery.asp categoryid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Absolute_Image_Gallery'" +SecRule &TX:'/SQL_INJECTION.*ARGS:categoryid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Absolute Image Gallery SQL Injection Attempt -- gallery.asp categoryid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007396) ET WEB_SPECIFIC Alan Ward A-Cart Pro SQL Injection Attempt -- product.asp productid +SecRule REQUEST_URI_RAW "(?i:\/product\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007396,rev:3,msg:'ET WEB_SPECIFIC Alan Ward A-Cart Pro SQL Injection Attempt -- product.asp productid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Acart'" +SecRule &TX:'/SQL_INJECTION.*ARGS:productid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Alan Ward A-Cart Pro SQL Injection Attempt -- product.asp productid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007402) ET WEB_SPECIFIC Alan Ward A-Cart Pro SQL Injection Attempt -- search.asp search +SecRule REQUEST_URI_RAW "(?i:\/search\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007402,rev:3,msg:'ET WEB_SPECIFIC Alan Ward A-Cart Pro SQL Injection Attempt -- search.asp search ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Acart'" +SecRule &TX:'/SQL_INJECTION.*ARGS:search/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Alan Ward A-Cart Pro SQL Injection Attempt -- search.asp search ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007480) ET WEB_SPECIFIC ActiveNews Manager SQL Injection Attempt -- activenews_view.asp articleID +SecRule REQUEST_URI_RAW "(?i:\/activenews_view\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007480,rev:3,msg:'ET WEB_SPECIFIC ActiveNews Manager SQL Injection Attempt -- activenews_view.asp articleID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_ActiveNews'" +SecRule &TX:'/SQL_INJECTION.*ARGS:articleID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC ActiveNews Manager SQL Injection Attempt -- activenews_view.asp articleID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007485) ET WEB_SPECIFIC ActiveNews Manager SQL Injection Attempt -- default.asp page +SecRule REQUEST_URI_RAW "(?i:\/default\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007485,rev:3,msg:'ET WEB_SPECIFIC ActiveNews Manager SQL Injection Attempt -- default.asp page ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_ActiveNews'" +SecRule &TX:'/SQL_INJECTION.*ARGS:page/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC ActiveNews Manager SQL Injection Attempt -- default.asp page ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007491) ET WEB_SPECIFIC ActiveNews Manager SQL Injection Attempt -- activeNews_categories.asp catID +SecRule REQUEST_URI_RAW "(?i:\/activeNews_categories\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007491,rev:3,msg:'ET WEB_SPECIFIC ActiveNews Manager SQL Injection Attempt -- activeNews_categories.asp catID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_ActiveNews'" +SecRule &TX:'/SQL_INJECTION.*ARGS:catID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC ActiveNews Manager SQL Injection Attempt -- activeNews_categories.asp catID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007497) ET WEB_SPECIFIC ActiveNews Manager SQL Injection Attempt -- activeNews_comments.asp articleID +SecRule REQUEST_URI_RAW "(?i:\/activeNews_comments\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007497,rev:3,msg:'ET WEB_SPECIFIC ActiveNews Manager SQL Injection Attempt -- activeNews_comments.asp articleID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_ActiveNews'" +SecRule &TX:'/SQL_INJECTION.*ARGS:articleID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC ActiveNews Manager SQL Injection Attempt -- activeNews_comments.asp articleID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007503) ET WEB_SPECIFIC ActiveNews Manager SQL Injection Attempt -- activenews_search.asp query +SecRule REQUEST_URI_RAW "(?i:\/activenews_search\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007503,rev:3,msg:'ET WEB_SPECIFIC ActiveNews Manager SQL Injection Attempt -- activenews_search.asp query ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_ActiveNews'" +SecRule &TX:'/SQL_INJECTION.*ARGS:query/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC ActiveNews Manager SQL Injection Attempt -- activenews_search.asp query ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004891) ET WEB_SPECIFIC Aktueldownload Haber script SQL Injection Attempt -- HaberDetay.asp id +SecRule REQUEST_URI_RAW "(?i:\/HaberDetay\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004891,rev:4,msg:'ET WEB_SPECIFIC Aktueldownload Haber script SQL Injection Attempt -- HaberDetay.asp id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Aktueldownload_Haber_script'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Aktueldownload Haber script SQL Injection Attempt -- HaberDetay.asp id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004897) ET WEB_SPECIFIC Aktueldownload Haber script SQL Injection Attempt -- rss.asp kid +SecRule REQUEST_URI_RAW "(?i:\/rss\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004897,rev:4,msg:'ET WEB_SPECIFIC Aktueldownload Haber script SQL Injection Attempt -- rss.asp kid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Aktueldownload_Haber_script'" +SecRule &TX:'/SQL_INJECTION.*ARGS:kid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Aktueldownload Haber script SQL Injection Attempt -- rss.asp kid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005776) ET WEB_SPECIFIC @lex Guestbook SQL Injection Attempt -- index.php lang +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005776,rev:4,msg:'ET WEB_SPECIFIC @lex Guestbook SQL Injection Attempt -- index.php lang ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Alex_Guestbook'" +SecRule &TX:'/SQL_INJECTION.*ARGS:lang/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC @lex Guestbook SQL Injection Attempt -- index.php lang ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004021) ET WEB_SPECIFIC AlstraSoft E-Friends SQL Injection Attempt -- index.php pack +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004021,rev:4,msg:'ET WEB_SPECIFIC AlstraSoft E-Friends SQL Injection Attempt -- index.php pack ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Alstrasoft'" +SecRule &TX:'/SQL_INJECTION.*ARGS:pack/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC AlstraSoft E-Friends SQL Injection Attempt -- index.php pack ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004721) ET WEB_SPECIFIC ANGEL Learning Management Suite (LMS) SQL Injection Attempt -- default.asp id +SecRule REQUEST_URI_RAW "(?i:\/section\/default\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004721,rev:4,msg:'ET WEB_SPECIFIC ANGEL Learning Management Suite (LMS) SQL Injection Attempt -- default.asp id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Angel_Learning_Mgmt'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC ANGEL Learning Management Suite (LMS) SQL Injection Attempt -- default.asp id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006565) ET WEB_SPECIFIC AnnonceScriptHP SQL Injection Attempt -- email.php id +SecRule REQUEST_URI_RAW "(?i:\/email\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006565,rev:3,msg:'ET WEB_SPECIFIC AnnonceScriptHP SQL Injection Attempt -- email.php id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_AnnounceScriptHP'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC AnnonceScriptHP SQL Injection Attempt -- email.php id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006571) ET WEB_SPECIFIC AnnonceScriptHP SQL Injection Attempt -- voirannonce.php no +SecRule REQUEST_URI_RAW "(?i:\/voirannonce\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006571,rev:3,msg:'ET WEB_SPECIFIC AnnonceScriptHP SQL Injection Attempt -- voirannonce.php no ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_AnnounceScriptHP'" +SecRule &TX:'/SQL_INJECTION.*ARGS:no/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC AnnonceScriptHP SQL Injection Attempt -- voirannonce.php no ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006577) ET WEB_SPECIFIC AnnonceScriptHP SQL Injection Attempt -- fiche_membre.php idmembre +SecRule REQUEST_URI_RAW "(?i:\/admin\/admin_membre\/fiche_membre\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006577,rev:3,msg:'ET WEB_SPECIFIC AnnonceScriptHP SQL Injection Attempt -- fiche_membre.php idmembre ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_AnnounceScriptHP'" +SecRule &TX:'/SQL_INJECTION.*ARGS:idmembre/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC AnnonceScriptHP SQL Injection Attempt -- fiche_membre.php idmembre ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006583) ET WEB_SPECIFIC AnnonceScriptHP SQL Injection Attempt -- okvalannonce.php idannonce +SecRule REQUEST_URI_RAW "(?i:\/admin\/admin_annonce\/okvalannonce\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006583,rev:3,msg:'ET WEB_SPECIFIC AnnonceScriptHP SQL Injection Attempt -- okvalannonce.php idannonce ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_AnnounceScriptHP'" +SecRule &TX:'/SQL_INJECTION.*ARGS:idannonce/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC AnnonceScriptHP SQL Injection Attempt -- okvalannonce.php idannonce ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006589) ET WEB_SPECIFIC AnnonceScriptHP SQL Injection Attempt -- changeannonce.php idannonce +SecRule REQUEST_URI_RAW "(?i:\/admin\/admin_annonce\/changeannonce\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006589,rev:3,msg:'ET WEB_SPECIFIC AnnonceScriptHP SQL Injection Attempt -- changeannonce.php idannonce ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_AnnounceScriptHP'" +SecRule &TX:'/SQL_INJECTION.*ARGS:idannonce/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC AnnonceScriptHP SQL Injection Attempt -- changeannonce.php idannonce ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006787) ET WEB_SPECIFIC Aspee and Dogantepe Ziyaretci Defteri SQL Injection Attempt -- giris.asp kullanici +SecRule REQUEST_URI_RAW "(?i:\/giris\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006787,rev:3,msg:'ET WEB_SPECIFIC Aspee and Dogantepe Ziyaretci Defteri SQL Injection Attempt -- giris.asp kullanici ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Aspee'" +SecRule &TX:'/SQL_INJECTION.*ARGS:kullanici/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Aspee and Dogantepe Ziyaretci Defteri SQL Injection Attempt -- giris.asp kullanici ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006793) ET WEB_SPECIFIC Aspee and Dogantepe Ziyaretci Defteri SQL Injection Attempt -- giris.asp parola +SecRule REQUEST_URI_RAW "(?i:\/giris\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006793,rev:3,msg:'ET WEB_SPECIFIC Aspee and Dogantepe Ziyaretci Defteri SQL Injection Attempt -- giris.asp parola ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Aspee'" +SecRule &TX:'/SQL_INJECTION.*ARGS:parola/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Aspee and Dogantepe Ziyaretci Defteri SQL Injection Attempt -- giris.asp parola ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004728) ET WEB_SPECIFIC Audins Audiens SQL Injection Attempt -- index.php PHPSESSID +SecRule REQUEST_URI_RAW "(?i:\/system\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004728,rev:4,msg:'ET WEB_SPECIFIC Audins Audiens SQL Injection Attempt -- index.php PHPSESSID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Audins'" +SecRule &TX:'/SQL_INJECTION.*ARGS:PHPSESSID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Audins Audiens SQL Injection Attempt -- index.php PHPSESSID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007456) ET WEB_SPECIFIC BPG-InfoTech Content Management System SQL Injection Attempt -- publications_list.asp vjob +SecRule REQUEST_URI_RAW "(?i:\/publications_list\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007456,rev:3,msg:'ET WEB_SPECIFIC BPG-InfoTech Content Management System SQL Injection Attempt -- publications_list.asp vjob ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_BPG_Infotech'" +SecRule &TX:'/SQL_INJECTION.*ARGS:vjob/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC BPG-InfoTech Content Management System SQL Injection Attempt -- publications_list.asp vjob ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007462) ET WEB_SPECIFIC BPG-InfoTech Content Management System SQL Injection Attempt -- publication_view.asp InfoID +SecRule REQUEST_URI_RAW "(?i:\/publication_view\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007462,rev:3,msg:'ET WEB_SPECIFIC BPG-InfoTech Content Management System SQL Injection Attempt -- publication_view.asp InfoID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_BPG_Infotech'" +SecRule &TX:'/SQL_INJECTION.*ARGS:InfoID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC BPG-InfoTech Content Management System SQL Injection Attempt -- publication_view.asp InfoID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004335) ET WEB_SPECIFIC BP Blog SQL Injection Attempt -- default.asp layout +SecRule REQUEST_URI_RAW "(?i:\/default\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004335,rev:4,msg:'ET WEB_SPECIFIC BP Blog SQL Injection Attempt -- default.asp layout ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_BP_Blog'" +SecRule &TX:'/SQL_INJECTION.*ARGS:layout/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC BP Blog SQL Injection Attempt -- default.asp layout ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007215) ET WEB_SPECIFIC BasicForum SQL Injection Attempt -- edit.asp id +SecRule REQUEST_URI_RAW "(?i:\/edit\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007215,rev:3,msg:'ET WEB_SPECIFIC BasicForum SQL Injection Attempt -- edit.asp id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Basicforum'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC BasicForum SQL Injection Attempt -- edit.asp id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006337) ET WEB_SPECIFIC Bluetrait SQL Injection Attempt -- bt-trackback.php +SecRule REQUEST_URI_RAW "(?i:\/bt\-trackback\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006337,rev:4,msg:'ET WEB_SPECIFIC Bluetrait SQL Injection Attempt -- bt-trackback.php ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Bluetrait'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\(.+SELECT)" + +# (sid 2004832) ET WEB_SPECIFIC Bookmark4U SQL Injection Attempt -- config.php sqlcmd +SecRule REQUEST_URI_RAW "(?i:\/admin\/config\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004832,rev:4,msg:'ET WEB_SPECIFIC Bookmark4U SQL Injection Attempt -- config.php sqlcmd ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Bookmark4U'" +SecRule &TX:'/SQL_INJECTION.*ARGS:sqlcmd/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Bookmark4U SQL Injection Attempt -- config.php sqlcmd ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004027) ET WEB_SPECIFIC BtiTracker SQL Injection Attempt -- account_change.php style +SecRule REQUEST_URI_RAW "(?i:\/account_change\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004027,rev:4,msg:'ET WEB_SPECIFIC BtiTracker SQL Injection Attempt -- account_change.php style ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_BtiTracker'" +SecRule &TX:'/SQL_INJECTION.*ARGS:style/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC BtiTracker SQL Injection Attempt -- account_change.php style ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004033) ET WEB_SPECIFIC BtiTracker SQL Injection Attempt -- account_change.php langue +SecRule REQUEST_URI_RAW "(?i:\/account_change\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004033,rev:4,msg:'ET WEB_SPECIFIC BtiTracker SQL Injection Attempt -- account_change.php langue ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_BtiTracker'" +SecRule &TX:'/SQL_INJECTION.*ARGS:langue/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC BtiTracker SQL Injection Attempt -- account_change.php langue ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004989) ET WEB_SPECIFIC BtitTracker SQL Injection Attempt -- torrents.php by +SecRule REQUEST_URI_RAW "(?i:\/torrents\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004989,rev:4,msg:'ET WEB_SPECIFIC BtitTracker SQL Injection Attempt -- torrents.php by ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_BtitTracker'" +SecRule &TX:'/SQL_INJECTION.*ARGS:by/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC BtitTracker SQL Injection Attempt -- torrents.php by ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004995) ET WEB_SPECIFIC BtitTracker SQL Injection Attempt -- torrents.php order +SecRule REQUEST_URI_RAW "(?i:\/torrents\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004995,rev:4,msg:'ET WEB_SPECIFIC BtitTracker SQL Injection Attempt -- torrents.php order ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_BtitTracker'" +SecRule &TX:'/SQL_INJECTION.*ARGS:order/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC BtitTracker SQL Injection Attempt -- torrents.php order ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2003780) ET WEB_SPECIFIC Burak Yilmaz Blog SQL Injection Attempt -- bry.asp id +SecRule REQUEST_URI_RAW "(?i:\/bry\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2003780,rev:4,msg:'ET WEB_SPECIFIC Burak Yilmaz Blog SQL Injection Attempt -- bry.asp id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Burak'" +SecRule REQUEST_URI_RAW "@contains (" "chain" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Burak Yilmaz Blog SQL Injection Attempt -- bry.asp id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006253) ET WEB_SPECIFIC Burak Yylmaz Download Portal SQL Injection Attempt -- HABERLER.ASP kid +SecRule REQUEST_URI_RAW "(?i:\/HABERLER\.ASP)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006253,rev:4,msg:'ET WEB_SPECIFIC Burak Yylmaz Download Portal SQL Injection Attempt -- HABERLER.ASP kid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Burak'" +SecRule &TX:'/SQL_INJECTION.*ARGS:kid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Burak Yylmaz Download Portal SQL Injection Attempt -- HABERLER.ASP kid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006259) ET WEB_SPECIFIC Burak Yylmaz Download Portal SQL Injection Attempt -- HABERLER.ASP id +SecRule REQUEST_URI_RAW "(?i:\/HABERLER\.ASP)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006259,rev:4,msg:'ET WEB_SPECIFIC Burak Yylmaz Download Portal SQL Injection Attempt -- HABERLER.ASP id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Burak'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Burak Yylmaz Download Portal SQL Injection Attempt -- HABERLER.ASP id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006265) ET WEB_SPECIFIC Burak Yylmaz Download Portal SQL Injection Attempt -- ASPKAT.ASP id +SecRule REQUEST_URI_RAW "(?i:\/ASPKAT\.ASP)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006265,rev:4,msg:'ET WEB_SPECIFIC Burak Yylmaz Download Portal SQL Injection Attempt -- ASPKAT.ASP id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Burak'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Burak Yylmaz Download Portal SQL Injection Attempt -- ASPKAT.ASP id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006271) ET WEB_SPECIFIC Burak Yylmaz Download Portal SQL Injection Attempt -- ASPKAT.ASP kid +SecRule REQUEST_URI_RAW "(?i:\/ASPKAT\.ASP)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006271,rev:4,msg:'ET WEB_SPECIFIC Burak Yylmaz Download Portal SQL Injection Attempt -- ASPKAT.ASP kid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Burak'" +SecRule &TX:'/SQL_INJECTION.*ARGS:kid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Burak Yylmaz Download Portal SQL Injection Attempt -- ASPKAT.ASP kid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006277) ET WEB_SPECIFIC Burak Yylmaz Download Portal SQL Injection Attempt -- down.asp id +SecRule REQUEST_URI_RAW "(?i:\/down\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006277,rev:4,msg:'ET WEB_SPECIFIC Burak Yylmaz Download Portal SQL Injection Attempt -- down.asp id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Burak'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Burak Yylmaz Download Portal SQL Injection Attempt -- down.asp id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2003797) ET WEB_SPECIFIC CMS Made Simple SQL Injection Attempt -- stylesheet.php templateid +SecRule REQUEST_URI_RAW "(?i:\/stylesheet\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2003797,rev:5,msg:'ET WEB_SPECIFIC CMS Made Simple SQL Injection Attempt -- stylesheet.php templateid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_CMS_Made_Simple'" +SecRule REQUEST_URI_RAW "@contains (" "chain" +SecRule &TX:'/SQL_INJECTION.*ARGS:templateid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC CMS Made Simple SQL Injection Attempt -- stylesheet.php templateid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006169) ET WEB_SPECIFIC Calendar MX BASIC SQL Injection Attempt -- calendar_detail.asp ID +SecRule REQUEST_URI_RAW "(?i:\/calendar_detail\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006169,rev:4,msg:'ET WEB_SPECIFIC Calendar MX BASIC SQL Injection Attempt -- calendar_detail.asp ID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Calendar_MX'" +SecRule &TX:'/SQL_INJECTION.*ARGS:ID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Calendar MX BASIC SQL Injection Attempt -- calendar_detail.asp ID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006187) ET WEB_SPECIFIC Newsletter MX SQL Injection Attempt -- admin_mail_adressee.asp ID +SecRule REQUEST_URI_RAW "(?i:\/admin\/admin_mail_adressee\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006187,rev:4,msg:'ET WEB_SPECIFIC Newsletter MX SQL Injection Attempt -- admin_mail_adressee.asp ID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Calendar_MX'" +SecRule &TX:'/SQL_INJECTION.*ARGS:ID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Newsletter MX SQL Injection Attempt -- admin_mail_adressee.asp ID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007468) ET WEB_SPECIFIC CandyPress Store SQL Injection Attempt -- openPolicy.asp policy +SecRule REQUEST_URI_RAW "(?i:\/openPolicy\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007468,rev:3,msg:'ET WEB_SPECIFIC CandyPress Store SQL Injection Attempt -- openPolicy.asp policy ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_CandyPress'" +SecRule &TX:'/SQL_INJECTION.*ARGS:policy/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC CandyPress Store SQL Injection Attempt -- openPolicy.asp policy ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007474) ET WEB_SPECIFIC CandyPress Store SQL Injection Attempt -- prodList.asp brand +SecRule REQUEST_URI_RAW "(?i:\/prodList\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007474,rev:3,msg:'ET WEB_SPECIFIC CandyPress Store SQL Injection Attempt -- prodList.asp brand ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_CandyPress'" +SecRule &TX:'/SQL_INJECTION.*ARGS:brand/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC CandyPress Store SQL Injection Attempt -- prodList.asp brand ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007227) ET WEB_SPECIFIC ClickTech Click Blog SQL Injection Attempt -- displayCalendar.asp date +SecRule REQUEST_URI_RAW "(?i:\/displayCalendar\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007227,rev:3,msg:'ET WEB_SPECIFIC ClickTech Click Blog SQL Injection Attempt -- displayCalendar.asp date ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Clicktech'" +SecRule &TX:'/SQL_INJECTION.*ARGS:date/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC ClickTech Click Blog SQL Injection Attempt -- displayCalendar.asp date ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007233) ET WEB_SPECIFIC ClickTech Click Gallery SQL Injection Attempt -- view_gallery.asp currentpage +SecRule REQUEST_URI_RAW "(?i:\/view_gallery\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007233,rev:3,msg:'ET WEB_SPECIFIC ClickTech Click Gallery SQL Injection Attempt -- view_gallery.asp currentpage ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Clicktech'" +SecRule &TX:'/SQL_INJECTION.*ARGS:currentpage/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC ClickTech Click Gallery SQL Injection Attempt -- view_gallery.asp currentpage ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007239) ET WEB_SPECIFIC ClickTech Click Gallery SQL Injection Attempt -- view_gallery.asp gallery_id +SecRule REQUEST_URI_RAW "(?i:\/view_gallery\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007239,rev:3,msg:'ET WEB_SPECIFIC ClickTech Click Gallery SQL Injection Attempt -- view_gallery.asp gallery_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Clicktech'" +SecRule &TX:'/SQL_INJECTION.*ARGS:gallery_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC ClickTech Click Gallery SQL Injection Attempt -- view_gallery.asp gallery_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007245) ET WEB_SPECIFIC ClickTech Click Gallery SQL Injection Attempt -- download_image.asp image_id +SecRule REQUEST_URI_RAW "(?i:\/download_image\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007245,rev:3,msg:'ET WEB_SPECIFIC ClickTech Click Gallery SQL Injection Attempt -- download_image.asp image_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Clicktech'" +SecRule &TX:'/SQL_INJECTION.*ARGS:image_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC ClickTech Click Gallery SQL Injection Attempt -- download_image.asp image_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007251) ET WEB_SPECIFIC ClickTech Click Gallery SQL Injection Attempt -- gallery.asp currentpage +SecRule REQUEST_URI_RAW "(?i:\/gallery\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007251,rev:3,msg:'ET WEB_SPECIFIC ClickTech Click Gallery SQL Injection Attempt -- gallery.asp currentpage ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Clicktech'" +SecRule &TX:'/SQL_INJECTION.*ARGS:currentpage/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC ClickTech Click Gallery SQL Injection Attempt -- gallery.asp currentpage ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007257) ET WEB_SPECIFIC ClickTech Click Gallery SQL Injection Attempt -- gallery.asp orderby +SecRule REQUEST_URI_RAW "(?i:\/gallery\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007257,rev:3,msg:'ET WEB_SPECIFIC ClickTech Click Gallery SQL Injection Attempt -- gallery.asp orderby ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Clicktech'" +SecRule &TX:'/SQL_INJECTION.*ARGS:orderby/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC ClickTech Click Gallery SQL Injection Attempt -- gallery.asp orderby ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007263) ET WEB_SPECIFIC ClickTech Click Gallery SQL Injection Attempt -- view_recent.asp currentpage +SecRule REQUEST_URI_RAW "(?i:\/view_recent\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007263,rev:3,msg:'ET WEB_SPECIFIC ClickTech Click Gallery SQL Injection Attempt -- view_recent.asp currentpage ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Clicktech'" +SecRule &TX:'/SQL_INJECTION.*ARGS:currentpage/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC ClickTech Click Gallery SQL Injection Attempt -- view_recent.asp currentpage ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007269) ET WEB_SPECIFIC ClickTech ClickContact SQL Injection Attempt -- default.asp AlphaSort +SecRule REQUEST_URI_RAW "(?i:\/default\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007269,rev:3,msg:'ET WEB_SPECIFIC ClickTech ClickContact SQL Injection Attempt -- default.asp AlphaSort ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Clicktech'" +SecRule &TX:'/SQL_INJECTION.*ARGS:AlphaSort/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC ClickTech ClickContact SQL Injection Attempt -- default.asp AlphaSort ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007275) ET WEB_SPECIFIC ClickTech ClickContact SQL Injection Attempt -- default.asp In +SecRule REQUEST_URI_RAW "(?i:\/default\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007275,rev:3,msg:'ET WEB_SPECIFIC ClickTech ClickContact SQL Injection Attempt -- default.asp In ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Clicktech'" +SecRule &TX:'/SQL_INJECTION.*ARGS:In/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC ClickTech ClickContact SQL Injection Attempt -- default.asp In ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007281) ET WEB_SPECIFIC ClickTech ClickContact SQL Injection Attempt -- default.asp orderby +SecRule REQUEST_URI_RAW "(?i:\/default\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007281,rev:3,msg:'ET WEB_SPECIFIC ClickTech ClickContact SQL Injection Attempt -- default.asp orderby ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Clicktech'" +SecRule &TX:'/SQL_INJECTION.*ARGS:orderby/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC ClickTech ClickContact SQL Injection Attempt -- default.asp orderby ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004879) ET WEB_SPECIFIC CodeAvalanche News SQL Injection Attempt -- inc_listnews.asp CAT_ID +SecRule REQUEST_URI_RAW "(?i:\/inc_listnews\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004879,rev:4,msg:'ET WEB_SPECIFIC CodeAvalanche News SQL Injection Attempt -- inc_listnews.asp CAT_ID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_CodeAvalance'" +SecRule &TX:'/SQL_INJECTION.*ARGS:CAT_ID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC CodeAvalanche News SQL Injection Attempt -- inc_listnews.asp CAT_ID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006508) ET WEB_SPECIFIC Comersus Shop Cart SQL Injection Attempt -- comersus_optReviewReadExec.asp idProduct +SecRule REQUEST_URI_RAW "(?i:\/comersus_optReviewReadExec\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006508,rev:4,msg:'ET WEB_SPECIFIC Comersus Shop Cart SQL Injection Attempt -- comersus_optReviewReadExec.asp idProduct ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Comersus'" +SecRule &TX:'/SQL_INJECTION.*ARGS:idProduct/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Comersus Shop Cart SQL Injection Attempt -- comersus_optReviewReadExec.asp idProduct ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004639) ET WEB_SPECIFIC Comicsense SQL Injection Attempt -- index.php epi +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004639,rev:4,msg:'ET WEB_SPECIFIC Comicsense SQL Injection Attempt -- index.php epi ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_ComicSense_Portal'" +SecRule &TX:'/SQL_INJECTION.*ARGS:epi/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Comicsense SQL Injection Attempt -- index.php epi ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004709) ET WEB_SPECIFIC Connectix Boards SQL Injection Attempt -- admin.php uploadimage +SecRule REQUEST_URI_RAW "(?i:\/admin\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004709,rev:4,msg:'ET WEB_SPECIFIC Connectix Boards SQL Injection Attempt -- admin.php uploadimage ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Connectix_Portal'" +SecRule &TX:'/SQL_INJECTION.*ARGS:uploadimage/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Connectix Boards SQL Injection Attempt -- admin.php uploadimage ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004715) ET WEB_SPECIFIC Connectix Boards SQL Injection Attempt -- index.php p_skin +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004715,rev:4,msg:'ET WEB_SPECIFIC Connectix Boards SQL Injection Attempt -- index.php p_skin ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Connectix_Portal'" +SecRule &TX:'/SQL_INJECTION.*ARGS:p_skin/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Connectix Boards SQL Injection Attempt -- index.php p_skin ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007340) ET WEB_SPECIFIC ContentNow SQL Injection Attempt -- index.php pageid +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007340,rev:3,msg:'ET WEB_SPECIFIC ContentNow SQL Injection Attempt -- index.php pageid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_ContentNow'" +SecRule &TX:'/SQL_INJECTION.*ARGS:pageid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC ContentNow SQL Injection Attempt -- index.php pageid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006307) ET WEB_SPECIFIC Contra Haber Sistemi SQL Injection Attempt -- haber.asp id +SecRule REQUEST_URI_RAW "(?i:\/haber\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006307,rev:4,msg:'ET WEB_SPECIFIC Contra Haber Sistemi SQL Injection Attempt -- haber.asp id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Contra_Haber'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Contra Haber Sistemi SQL Injection Attempt -- haber.asp id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004813) ET WEB_SPECIFIC Coppermine Photo Gallery (CPG) SQL Injection Attempt -- thumbnails.php cpg131_fav +SecRule REQUEST_URI_RAW "(?i:\/thumbnails\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004813,rev:4,msg:'ET WEB_SPECIFIC Coppermine Photo Gallery (CPG) SQL Injection Attempt -- thumbnails.php cpg131_fav ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Coppermine_Photo_Gallery'" +SecRule &TX:'/SQL_INJECTION.*ARGS:cpg131_fav/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Coppermine Photo Gallery (CPG) SQL Injection Attempt -- thumbnails.php cpg131_fav ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005845) ET WEB_SPECIFIC Coppermine Photo Gallery SQL Injection Attempt -- albmgr.php cat +SecRule REQUEST_URI_RAW "(?i:\/albmgr\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005845,rev:4,msg:'ET WEB_SPECIFIC Coppermine Photo Gallery SQL Injection Attempt -- albmgr.php cat ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Coppermine_Photo_Gallery'" +SecRule &TX:'/SQL_INJECTION.*ARGS:cat/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Coppermine Photo Gallery SQL Injection Attempt -- albmgr.php cat ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005851) ET WEB_SPECIFIC Coppermine Photo Gallery SQL Injection Attempt -- usermgr.php gid +SecRule REQUEST_URI_RAW "(?i:\/usermgr\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005851,rev:4,msg:'ET WEB_SPECIFIC Coppermine Photo Gallery SQL Injection Attempt -- usermgr.php gid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Coppermine_Photo_Gallery'" +SecRule &TX:'/SQL_INJECTION.*ARGS:gid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Coppermine Photo Gallery SQL Injection Attempt -- usermgr.php gid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005857) ET WEB_SPECIFIC Coppermine Photo Gallery SQL Injection Attempt -- db_ecard.php start +SecRule REQUEST_URI_RAW "(?i:\/db_ecard\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005857,rev:4,msg:'ET WEB_SPECIFIC Coppermine Photo Gallery SQL Injection Attempt -- db_ecard.php start ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Coppermine_Photo_Gallery'" +SecRule &TX:'/SQL_INJECTION.*ARGS:start/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Coppermine Photo Gallery SQL Injection Attempt -- db_ecard.php start ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2003756) ET WEB_SPECIFIC CreaScripts CreaDirectory SQL Injection Attempt -- error.asp id +SecRule REQUEST_URI_RAW "(?i:\/error\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2003756,rev:4,msg:'ET WEB_SPECIFIC CreaScripts CreaDirectory SQL Injection Attempt -- error.asp id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Creascripts'" +SecRule REQUEST_URI_RAW "@contains (" "chain" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC CreaScripts CreaDirectory SQL Injection Attempt -- error.asp id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005863) ET WEB_SPECIFIC CreateAuction SQL Injection Attempt -- cats.asp catid +SecRule REQUEST_URI_RAW "(?i:\/cats\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005863,rev:4,msg:'ET WEB_SPECIFIC CreateAuction SQL Injection Attempt -- cats.asp catid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_CreateAuction'" +SecRule &TX:'/SQL_INJECTION.*ARGS:catid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC CreateAuction SQL Injection Attempt -- cats.asp catid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004039) ET WEB_SPECIFIC CubeCart SQL Injection Attempt -- cart.inc.php +SecRule REQUEST_URI_RAW "(?i:\/cart\.inc\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004039,rev:4,msg:'ET WEB_SPECIFIC CubeCart SQL Injection Attempt -- cart.inc.php ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_CubeCart'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:.+\(.+SELECT)" + +# (sid 2004087) ET WEB_SPECIFIC DGNews SQL Injection Attempt -- news.php catid +SecRule REQUEST_URI_RAW "(?i:\/news\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004087,rev:4,msg:'ET WEB_SPECIFIC DGNews SQL Injection Attempt -- news.php catid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_DGNews'" +SecRule &TX:'/SQL_INJECTION.*ARGS:catid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC DGNews SQL Injection Attempt -- news.php catid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004460) ET WEB_SPECIFIC DGNews SQL Injection Attempt -- news.php newsid +SecRule REQUEST_URI_RAW "(?i:\/news\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004460,rev:4,msg:'ET WEB_SPECIFIC DGNews SQL Injection Attempt -- news.php newsid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_DGNews'" +SecRule &TX:'/SQL_INJECTION.*ARGS:newsid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC DGNews SQL Injection Attempt -- news.php newsid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004687) ET WEB_SPECIFIC DMXReady Site Engine Manager SQL Injection Attempt -- index.asp mid +SecRule REQUEST_URI_RAW "(?i:\/index\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004687,rev:4,msg:'ET WEB_SPECIFIC DMXReady Site Engine Manager SQL Injection Attempt -- index.asp mid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_DMXReady'" +SecRule &TX:'/SQL_INJECTION.*ARGS:mid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC DMXReady Site Engine Manager SQL Injection Attempt -- index.asp mid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006085) ET WEB_SPECIFIC DMXReady Secure Login Manager SQL Injection Attempt -- set_preferences.asp +SecRule REQUEST_URI_RAW "(?i:\/set_preferences\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006085,rev:4,msg:'ET WEB_SPECIFIC DMXReady Secure Login Manager SQL Injection Attempt -- set_preferences.asp ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_DMXReady'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\(.+SELECT)" + +# (sid 2006091) ET WEB_SPECIFIC DMXReady Secure Login Manager SQL Injection Attempt -- send_password_preferences.asp +SecRule REQUEST_URI_RAW "(?i:\/send_password_preferences\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006091,rev:4,msg:'ET WEB_SPECIFIC DMXReady Secure Login Manager SQL Injection Attempt -- send_password_preferences.asp ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_DMXReady'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\(.+SELECT)" + +# (sid 2006097) ET WEB_SPECIFIC DMXReady Secure Login Manager SQL Injection Attempt -- list.asp +SecRule REQUEST_URI_RAW "(?i:\/SecureLoginManager\/list\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006097,rev:4,msg:'ET WEB_SPECIFIC DMXReady Secure Login Manager SQL Injection Attempt -- list.asp ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_DMXReady'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\(.+SELECT)" + +# (sid 2006103) ET WEB_SPECIFIC DMXReady Secure Login Manager SQL Injection Attempt -- login.asp sent +SecRule REQUEST_URI_RAW "(?i:\/login\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006103,rev:4,msg:'ET WEB_SPECIFIC DMXReady Secure Login Manager SQL Injection Attempt -- login.asp sent ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_DMXReady'" +SecRule &TX:'/SQL_INJECTION.*ARGS:sent/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC DMXReady Secure Login Manager SQL Injection Attempt -- login.asp sent ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006109) ET WEB_SPECIFIC DMXReady Secure Login Manager SQL Injection Attempt -- content.asp sent +SecRule REQUEST_URI_RAW "(?i:\/content\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006109,rev:4,msg:'ET WEB_SPECIFIC DMXReady Secure Login Manager SQL Injection Attempt -- content.asp sent ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_DMXReady'" +SecRule &TX:'/SQL_INJECTION.*ARGS:sent/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC DMXReady Secure Login Manager SQL Injection Attempt -- content.asp sent ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006115) ET WEB_SPECIFIC DMXReady Secure Login Manager SQL Injection Attempt -- members.asp sent +SecRule REQUEST_URI_RAW "(?i:\/members\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006115,rev:4,msg:'ET WEB_SPECIFIC DMXReady Secure Login Manager SQL Injection Attempt -- members.asp sent ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_DMXReady'" +SecRule &TX:'/SQL_INJECTION.*ARGS:sent/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC DMXReady Secure Login Manager SQL Injection Attempt -- members.asp sent ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006121) ET WEB_SPECIFIC DMXReady Secure Login Manager SQL Injection Attempt -- inc_secureloginmanager.asp sent +SecRule REQUEST_URI_RAW "(?i:\/applications\/SecureLoginManager\/inc_secureloginmanager\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006121,rev:4,msg:'ET WEB_SPECIFIC DMXReady Secure Login Manager SQL Injection Attempt -- inc_secureloginmanager.asp sent ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_DMXReady'" +SecRule &TX:'/SQL_INJECTION.*ARGS:sent/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC DMXReady Secure Login Manager SQL Injection Attempt -- inc_secureloginmanager.asp sent ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005899) ET WEB_SPECIFIC Digitizing Quote And Ordering System SQL Injection Attempt -- search.asp ordernum +SecRule REQUEST_URI_RAW "(?i:\/search\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005899,rev:4,msg:'ET WEB_SPECIFIC Digitizing Quote And Ordering System SQL Injection Attempt -- search.asp ordernum ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_DQOS'" +SecRule &TX:'/SQL_INJECTION.*ARGS:ordernum/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Digitizing Quote And Ordering System SQL Injection Attempt -- search.asp ordernum ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004838) ET WEB_SPECIFIC Design4Online UserPages2 SQL Injection Attempt -- page.asp art_id +SecRule REQUEST_URI_RAW "(?i:\/page\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004838,rev:4,msg:'ET WEB_SPECIFIC Design4Online UserPages2 SQL Injection Attempt -- page.asp art_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Design4Online'" +SecRule &TX:'/SQL_INJECTION.*ARGS:art_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Design4Online UserPages2 SQL Injection Attempt -- page.asp art_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005595) ET WEB_SPECIFIC Digiappz DigiAffiliate SQL Injection Attempt -- visu_user.asp id +SecRule REQUEST_URI_RAW "(?i:\/visu_user\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005595,rev:4,msg:'ET WEB_SPECIFIC Digiappz DigiAffiliate SQL Injection Attempt -- visu_user.asp id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Digiappz'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Digiappz DigiAffiliate SQL Injection Attempt -- visu_user.asp id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005839) ET WEB_SPECIFIC Digirez SQL Injection Attempt -- info_book.asp book_id +SecRule REQUEST_URI_RAW "(?i:\/info_book\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005839,rev:4,msg:'ET WEB_SPECIFIC Digirez SQL Injection Attempt -- info_book.asp book_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Digirez'" +SecRule &TX:'/SQL_INJECTION.*ARGS:book_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Digirez SQL Injection Attempt -- info_book.asp book_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004051) ET WEB_SPECIFIC Dokeos SQL Injection Attempt -- courseLog.php scormcontopen +SecRule REQUEST_URI_RAW "(?i:\/tracking\/courseLog\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004051,rev:4,msg:'ET WEB_SPECIFIC Dokeos SQL Injection Attempt -- courseLog.php scormcontopen ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Dokeos'" +SecRule &TX:'/SQL_INJECTION.*ARGS:scormcontopen/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Dokeos SQL Injection Attempt -- courseLog.php scormcontopen ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004069) ET WEB_SPECIFIC Dokeos SQL Injection Attempt -- my_progress.php course +SecRule REQUEST_URI_RAW "(?i:\/main\/auth\/my_progress\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004069,rev:4,msg:'ET WEB_SPECIFIC Dokeos SQL Injection Attempt -- my_progress.php course ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Dokeos'" +SecRule &TX:'/SQL_INJECTION.*ARGS:course/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Dokeos SQL Injection Attempt -- my_progress.php course ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006145) ET WEB_SPECIFIC Dragon Business Directory SQL Injection Attempt -- bus_details.asp ID +SecRule REQUEST_URI_RAW "(?i:\/bus_details\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006145,rev:4,msg:'ET WEB_SPECIFIC Dragon Business Directory SQL Injection Attempt -- bus_details.asp ID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Dragon_Business_Dir'" +SecRule &TX:'/SQL_INJECTION.*ARGS:ID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Dragon Business Directory SQL Injection Attempt -- bus_details.asp ID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004389) ET WEB_SPECIFIC fystyq Duyuru Scripti SQL Injection Attempt -- goster.asp id +SecRule REQUEST_URI_RAW "(?i:\/goster\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004389,rev:4,msg:'ET WEB_SPECIFIC fystyq Duyuru Scripti SQL Injection Attempt -- goster.asp id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Duruyu'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC fystyq Duyuru Scripti SQL Injection Attempt -- goster.asp id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006691) ET WEB_SPECIFIC DUware DUdownload SQL Injection Attempt -- detail.asp iFile +SecRule REQUEST_URI_RAW "(?i:\/detail\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006691,rev:4,msg:'ET WEB_SPECIFIC DUware DUdownload SQL Injection Attempt -- detail.asp iFile ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Duware'" +SecRule &TX:'/SQL_INJECTION.*ARGS:iFile/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC DUware DUdownload SQL Injection Attempt -- detail.asp iFile ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006698) ET WEB_SPECIFIC DUware DUdownload SQL Injection Attempt -- detail.asp action +SecRule REQUEST_URI_RAW "(?i:\/detail\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006698,rev:4,msg:'ET WEB_SPECIFIC DUware DUdownload SQL Injection Attempt -- detail.asp action ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Duware'" +SecRule &TX:'/SQL_INJECTION.*ARGS:action/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC DUware DUdownload SQL Injection Attempt -- detail.asp action ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006704) ET WEB_SPECIFIC DUware DUpaypal SQL Injection Attempt -- detail.asp iType +SecRule REQUEST_URI_RAW "(?i:\/detail\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006704,rev:4,msg:'ET WEB_SPECIFIC DUware DUpaypal SQL Injection Attempt -- detail.asp iType ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Duware'" +SecRule &TX:'/SQL_INJECTION.*ARGS:iType/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC DUware DUpaypal SQL Injection Attempt -- detail.asp iType ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006710) ET WEB_SPECIFIC DuWare DuClassmate SQL Injection Attempt -- default.asp iCity +SecRule REQUEST_URI_RAW "(?i:\/default\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006710,rev:4,msg:'ET WEB_SPECIFIC DuWare DuClassmate SQL Injection Attempt -- default.asp iCity ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Duware'" +SecRule &TX:'/SQL_INJECTION.*ARGS:iCity/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC DuWare DuClassmate SQL Injection Attempt -- default.asp iCity ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006716) ET WEB_SPECIFIC DuWare DuNews SQL Injection Attempt -- detail.asp iNews +SecRule REQUEST_URI_RAW "(?i:\/detail\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006716,rev:4,msg:'ET WEB_SPECIFIC DuWare DuNews SQL Injection Attempt -- detail.asp iNews ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Duware'" +SecRule &TX:'/SQL_INJECTION.*ARGS:iNews/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC DuWare DuNews SQL Injection Attempt -- detail.asp iNews ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006722) ET WEB_SPECIFIC DuWare DuNews SQL Injection Attempt -- detail.asp iType +SecRule REQUEST_URI_RAW "(?i:\/detail\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006722,rev:4,msg:'ET WEB_SPECIFIC DuWare DuNews SQL Injection Attempt -- detail.asp iType ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Duware'" +SecRule &TX:'/SQL_INJECTION.*ARGS:iType/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC DuWare DuNews SQL Injection Attempt -- detail.asp iType ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006728) ET WEB_SPECIFIC DuWare DuNews SQL Injection Attempt -- detail.asp Action +SecRule REQUEST_URI_RAW "(?i:\/detail\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006728,rev:4,msg:'ET WEB_SPECIFIC DuWare DuNews SQL Injection Attempt -- detail.asp Action ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Duware'" +SecRule &TX:'/SQL_INJECTION.*ARGS:Action/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC DuWare DuNews SQL Injection Attempt -- detail.asp Action ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2003774) ET WEB_SPECIFIC E-Annu SQL Injection Attempt -- home.php a +SecRule REQUEST_URI_RAW "(?i:\/home\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2003774,rev:4,msg:'ET WEB_SPECIFIC E-Annu SQL Injection Attempt -- home.php a ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_E-Annu'" +SecRule REQUEST_URI_RAW "@contains (" "chain" +SecRule &TX:'/SQL_INJECTION.*ARGS:a/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC E-Annu SQL Injection Attempt -- home.php a ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004628) ET WEB_SPECIFIC EQdkp SQL Injection Attempt -- listmembers.php rank +SecRule REQUEST_URI_RAW "(?i:\/listmembers\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004628,rev:4,msg:'ET WEB_SPECIFIC EQdkp SQL Injection Attempt -- listmembers.php rank ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_EQdkp'" +SecRule &TX:'/SQL_INJECTION.*ARGS:rank/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC EQdkp SQL Injection Attempt -- listmembers.php rank ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005272) ET WEB_SPECIFIC Easebay Resources Paypal Subscription Manager SQL Injection Attempt -- memberlist.php keyword +SecRule REQUEST_URI_RAW "(?i:\/admin\/memberlist\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005272,rev:4,msg:'ET WEB_SPECIFIC Easebay Resources Paypal Subscription Manager SQL Injection Attempt -- memberlist.php keyword ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Easebay'" +SecRule &TX:'/SQL_INJECTION.*ARGS:keyword/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Easebay Resources Paypal Subscription Manager SQL Injection Attempt -- memberlist.php keyword ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005278) ET WEB_SPECIFIC Easebay Resources Login Manager SQL Injection Attempt -- memberlist.php init_row +SecRule REQUEST_URI_RAW "(?i:\/admin\/memberlist\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005278,rev:4,msg:'ET WEB_SPECIFIC Easebay Resources Login Manager SQL Injection Attempt -- memberlist.php init_row ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Easebay'" +SecRule &TX:'/SQL_INJECTION.*ARGS:init_row/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Easebay Resources Login Manager SQL Injection Attempt -- memberlist.php init_row ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005043) ET WEB_SPECIFIC EasyMoblog SQL Injection Attempt -- add_comment.php i +SecRule REQUEST_URI_RAW "(?i:\/add_comment\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005043,rev:4,msg:'ET WEB_SPECIFIC EasyMoblog SQL Injection Attempt -- add_comment.php i ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_EasyMoblog'" +SecRule &TX:'/SQL_INJECTION.*ARGS:i/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC EasyMoblog SQL Injection Attempt -- add_comment.php i ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005049) ET WEB_SPECIFIC EasyMoblog SQL Injection Attempt -- add_comment.php post_id +SecRule REQUEST_URI_RAW "(?i:\/add_comment\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005049,rev:4,msg:'ET WEB_SPECIFIC EasyMoblog SQL Injection Attempt -- add_comment.php post_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_EasyMoblog'" +SecRule &TX:'/SQL_INJECTION.*ARGS:post_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC EasyMoblog SQL Injection Attempt -- add_comment.php post_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005055) ET WEB_SPECIFIC EasyMoblog SQL Injection Attempt -- list_comments.php i +SecRule REQUEST_URI_RAW "(?i:\/list_comments\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005055,rev:4,msg:'ET WEB_SPECIFIC EasyMoblog SQL Injection Attempt -- list_comments.php i ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_EasyMoblog'" +SecRule &TX:'/SQL_INJECTION.*ARGS:i/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC EasyMoblog SQL Injection Attempt -- list_comments.php i ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006558) ET WEB_SPECIFIC EasyPage SQL Injection Attempt -- default.aspx docId +SecRule REQUEST_URI_RAW "(?i:\/sptrees\/default\.aspx)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006558,rev:3,msg:'ET WEB_SPECIFIC EasyPage SQL Injection Attempt -- default.aspx docId ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_EasyPage'" +SecRule &TX:'/SQL_INJECTION.*ARGS:docId/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC EasyPage SQL Injection Attempt -- default.aspx docId ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005091) ET WEB_SPECIFIC Eclectic Designs CascadianFAQ SQL Injection Attempt -- index.php qid +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005091,rev:4,msg:'ET WEB_SPECIFIC Eclectic Designs CascadianFAQ SQL Injection Attempt -- index.php qid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Eclectic_Designs'" +SecRule &TX:'/SQL_INJECTION.*ARGS:qid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Eclectic Designs CascadianFAQ SQL Injection Attempt -- index.php qid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005115) ET WEB_SPECIFIC Eclectic Designs CascadianFAQ SQL Injection Attempt -- index.php catid +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005115,rev:4,msg:'ET WEB_SPECIFIC Eclectic Designs CascadianFAQ SQL Injection Attempt -- index.php catid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Eclectic_Designs'" +SecRule &TX:'/SQL_INJECTION.*ARGS:catid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Eclectic Designs CascadianFAQ SQL Injection Attempt -- index.php catid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005989) ET WEB_SPECIFIC Efkan Forum SQL Injection Attempt -- admin.asp grup +SecRule REQUEST_URI_RAW "(?i:\/admin\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005989,rev:4,msg:'ET WEB_SPECIFIC Efkan Forum SQL Injection Attempt -- admin.asp grup ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Efkan'" +SecRule &TX:'/SQL_INJECTION.*ARGS:grup/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Efkan Forum SQL Injection Attempt -- admin.asp grup ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005995) ET WEB_SPECIFIC Efkan Forum SQL Injection Attempt -- default.asp id +SecRule REQUEST_URI_RAW "(?i:\/default\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005995,rev:4,msg:'ET WEB_SPECIFIC Efkan Forum SQL Injection Attempt -- default.asp id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Efkan'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Efkan Forum SQL Injection Attempt -- default.asp id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006001) ET WEB_SPECIFIC Efkan Forum SQL Injection Attempt -- admin.asp id +SecRule REQUEST_URI_RAW "(?i:\/admin\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006001,rev:4,msg:'ET WEB_SPECIFIC Efkan Forum SQL Injection Attempt -- admin.asp id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Efkan'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Efkan Forum SQL Injection Attempt -- admin.asp id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006163) ET WEB_SPECIFIC Efkan Forum SQL Injection Attempt -- default.asp grup +SecRule REQUEST_URI_RAW "(?i:\/default\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006163,rev:4,msg:'ET WEB_SPECIFIC Efkan Forum SQL Injection Attempt -- default.asp grup ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Efkan'" +SecRule &TX:'/SQL_INJECTION.*ARGS:grup/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Efkan Forum SQL Injection Attempt -- default.asp grup ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006453) ET WEB_SPECIFIC Elxis CMS SQL Injection Attempt -- mod_banners.php +SecRule REQUEST_URI_RAW "(?i:\/mod_banners\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006453,rev:4,msg:'ET WEB_SPECIFIC Elxis CMS SQL Injection Attempt -- mod_banners.php ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Elxis'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:.+\(.+SELECT)" + +# (sid 2006139) ET WEB_SPECIFIC Enthrallweb eMates SQL Injection Attempt -- newsdetail.asp ID +SecRule REQUEST_URI_RAW "(?i:\/newsdetail\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006139,rev:4,msg:'ET WEB_SPECIFIC Enthrallweb eMates SQL Injection Attempt -- newsdetail.asp ID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Enthrallweb'" +SecRule &TX:'/SQL_INJECTION.*ARGS:ID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Enthrallweb eMates SQL Injection Attempt -- newsdetail.asp ID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006151) ET WEB_SPECIFIC Enthrallweb eCars SQL Injection Attempt -- Types.asp Type_id +SecRule REQUEST_URI_RAW "(?i:\/Types\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006151,rev:4,msg:'ET WEB_SPECIFIC Enthrallweb eCars SQL Injection Attempt -- Types.asp Type_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Enthrallweb'" +SecRule &TX:'/SQL_INJECTION.*ARGS:Type_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Enthrallweb eCars SQL Injection Attempt -- Types.asp Type_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006157) ET WEB_SPECIFIC Enthrallweb ePages SQL Injection Attempt -- actualpic.asp Biz_ID +SecRule REQUEST_URI_RAW "(?i:\/actualpic\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006157,rev:4,msg:'ET WEB_SPECIFIC Enthrallweb ePages SQL Injection Attempt -- actualpic.asp Biz_ID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Enthrallweb'" +SecRule &TX:'/SQL_INJECTION.*ARGS:Biz_ID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Enthrallweb ePages SQL Injection Attempt -- actualpic.asp Biz_ID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007046) ET WEB_SPECIFIC Enthrallweb eClassifieds SQL Injection Attempt -- ad.asp AD_ID +SecRule REQUEST_URI_RAW "(?i:\/ad\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007046,rev:4,msg:'ET WEB_SPECIFIC Enthrallweb eClassifieds SQL Injection Attempt -- ad.asp AD_ID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Enthrallweb'" +SecRule &TX:'/SQL_INJECTION.*ARGS:AD_ID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Enthrallweb eClassifieds SQL Injection Attempt -- ad.asp AD_ID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007052) ET WEB_SPECIFIC Enthrallweb eClassifieds SQL Injection Attempt -- ad.asp cat_id +SecRule REQUEST_URI_RAW "(?i:\/ad\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007052,rev:4,msg:'ET WEB_SPECIFIC Enthrallweb eClassifieds SQL Injection Attempt -- ad.asp cat_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Enthrallweb'" +SecRule &TX:'/SQL_INJECTION.*ARGS:cat_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Enthrallweb eClassifieds SQL Injection Attempt -- ad.asp cat_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007058) ET WEB_SPECIFIC Enthrallweb eClassifieds SQL Injection Attempt -- ad.asp sub_id +SecRule REQUEST_URI_RAW "(?i:\/ad\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007058,rev:4,msg:'ET WEB_SPECIFIC Enthrallweb eClassifieds SQL Injection Attempt -- ad.asp sub_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Enthrallweb'" +SecRule &TX:'/SQL_INJECTION.*ARGS:sub_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Enthrallweb eClassifieds SQL Injection Attempt -- ad.asp sub_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007028) ET WEB_SPECIFIC Enthrallweb eClassifieds SQL Injection Attempt -- ad.asp ad_id +SecRule REQUEST_URI_RAW "(?i:\/ad\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007028,rev:4,msg:'ET WEB_SPECIFIC Enthrallweb eClassifieds SQL Injection Attempt -- ad.asp ad_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Enthrallweb'" +SecRule &TX:'/SQL_INJECTION.*ARGS:ad_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Enthrallweb eClassifieds SQL Injection Attempt -- ad.asp ad_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007034) ET WEB_SPECIFIC Enthrallweb eClassifieds SQL Injection Attempt -- dircat.asp cid +SecRule REQUEST_URI_RAW "(?i:\/dircat\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007034,rev:4,msg:'ET WEB_SPECIFIC Enthrallweb eClassifieds SQL Injection Attempt -- dircat.asp cid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Enthrallweb'" +SecRule &TX:'/SQL_INJECTION.*ARGS:cid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Enthrallweb eClassifieds SQL Injection Attempt -- dircat.asp cid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007040) ET WEB_SPECIFIC Enthrallweb eClassifieds SQL Injection Attempt -- dirSub.asp sid +SecRule REQUEST_URI_RAW "(?i:\/dirSub\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007040,rev:4,msg:'ET WEB_SPECIFIC Enthrallweb eClassifieds SQL Injection Attempt -- dirSub.asp sid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Enthrallweb'" +SecRule &TX:'/SQL_INJECTION.*ARGS:sid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Enthrallweb eClassifieds SQL Injection Attempt -- dirSub.asp sid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007080) ET WEB_SPECIFIC Enthrallweb eHomes SQL Injection Attempt -- dircat.asp cid +SecRule REQUEST_URI_RAW "(?i:\/dircat\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007080,rev:3,msg:'ET WEB_SPECIFIC Enthrallweb eHomes SQL Injection Attempt -- dircat.asp cid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Enthrallweb'" +SecRule &TX:'/SQL_INJECTION.*ARGS:cid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Enthrallweb eHomes SQL Injection Attempt -- dircat.asp cid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007086) ET WEB_SPECIFIC Enthrallweb eHomes SQL Injection Attempt -- dirSub.asp sid +SecRule REQUEST_URI_RAW "(?i:\/dirSub\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007086,rev:3,msg:'ET WEB_SPECIFIC Enthrallweb eHomes SQL Injection Attempt -- dirSub.asp sid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Enthrallweb'" +SecRule &TX:'/SQL_INJECTION.*ARGS:sid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Enthrallweb eHomes SQL Injection Attempt -- dirSub.asp sid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007092) ET WEB_SPECIFIC Enthrallweb eHomes SQL Injection Attempt -- types.asp TYPE_ID +SecRule REQUEST_URI_RAW "(?i:\/types\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007092,rev:3,msg:'ET WEB_SPECIFIC Enthrallweb eHomes SQL Injection Attempt -- types.asp TYPE_ID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Enthrallweb'" +SecRule &TX:'/SQL_INJECTION.*ARGS:TYPE_ID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Enthrallweb eHomes SQL Injection Attempt -- types.asp TYPE_ID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007098) ET WEB_SPECIFIC Enthrallweb eHomes SQL Injection Attempt -- homeDetail.asp AD_ID +SecRule REQUEST_URI_RAW "(?i:\/homeDetail\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007098,rev:3,msg:'ET WEB_SPECIFIC Enthrallweb eHomes SQL Injection Attempt -- homeDetail.asp AD_ID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Enthrallweb'" +SecRule &TX:'/SQL_INJECTION.*ARGS:AD_ID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Enthrallweb eHomes SQL Injection Attempt -- homeDetail.asp AD_ID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007104) ET WEB_SPECIFIC Enthrallweb eHomes SQL Injection Attempt -- result.asp cat +SecRule REQUEST_URI_RAW "(?i:\/result\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007104,rev:3,msg:'ET WEB_SPECIFIC Enthrallweb eHomes SQL Injection Attempt -- result.asp cat ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Enthrallweb'" +SecRule &TX:'/SQL_INJECTION.*ARGS:cat/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Enthrallweb eHomes SQL Injection Attempt -- result.asp cat ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007110) ET WEB_SPECIFIC Enthrallweb eHomes SQL Injection Attempt -- compareHomes.asp compare +SecRule REQUEST_URI_RAW "(?i:\/compareHomes\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007110,rev:3,msg:'ET WEB_SPECIFIC Enthrallweb eHomes SQL Injection Attempt -- compareHomes.asp compare ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Enthrallweb'" +SecRule &TX:'/SQL_INJECTION.*ARGS:compare/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Enthrallweb eHomes SQL Injection Attempt -- compareHomes.asp compare ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007116) ET WEB_SPECIFIC Enthrallweb eHomes SQL Injection Attempt -- compareHomes.asp clear +SecRule REQUEST_URI_RAW "(?i:\/compareHomes\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007116,rev:3,msg:'ET WEB_SPECIFIC Enthrallweb eHomes SQL Injection Attempt -- compareHomes.asp clear ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Enthrallweb'" +SecRule &TX:'/SQL_INJECTION.*ARGS:clear/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Enthrallweb eHomes SQL Injection Attempt -- compareHomes.asp clear ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007122) ET WEB_SPECIFIC Enthrallweb eHomes SQL Injection Attempt -- compareHomes.asp adID +SecRule REQUEST_URI_RAW "(?i:\/compareHomes\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007122,rev:3,msg:'ET WEB_SPECIFIC Enthrallweb eHomes SQL Injection Attempt -- compareHomes.asp adID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Enthrallweb'" +SecRule &TX:'/SQL_INJECTION.*ARGS:adID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Enthrallweb eHomes SQL Injection Attempt -- compareHomes.asp adID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007128) ET WEB_SPECIFIC Enthrallweb eHomes SQL Injection Attempt -- result.asp aminprice +SecRule REQUEST_URI_RAW "(?i:\/result\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007128,rev:3,msg:'ET WEB_SPECIFIC Enthrallweb eHomes SQL Injection Attempt -- result.asp aminprice ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Enthrallweb'" +SecRule &TX:'/SQL_INJECTION.*ARGS:aminprice/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Enthrallweb eHomes SQL Injection Attempt -- result.asp aminprice ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007134) ET WEB_SPECIFIC Enthrallweb eHomes SQL Injection Attempt -- result.asp amaxprice +SecRule REQUEST_URI_RAW "(?i:\/result\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007134,rev:3,msg:'ET WEB_SPECIFIC Enthrallweb eHomes SQL Injection Attempt -- result.asp amaxprice ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Enthrallweb'" +SecRule &TX:'/SQL_INJECTION.*ARGS:amaxprice/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Enthrallweb eHomes SQL Injection Attempt -- result.asp amaxprice ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007140) ET WEB_SPECIFIC Enthrallweb eHomes SQL Injection Attempt -- result.asp abedrooms +SecRule REQUEST_URI_RAW "(?i:\/result\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007140,rev:3,msg:'ET WEB_SPECIFIC Enthrallweb eHomes SQL Injection Attempt -- result.asp abedrooms ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Enthrallweb'" +SecRule &TX:'/SQL_INJECTION.*ARGS:abedrooms/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Enthrallweb eHomes SQL Injection Attempt -- result.asp abedrooms ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005260) ET WEB_SPECIFIC Enthusiast SQL Injection Attempt -- show_owned.php cat +SecRule REQUEST_URI_RAW "(?i:\/show_owned\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005260,rev:4,msg:'ET WEB_SPECIFIC Enthusiast SQL Injection Attempt -- show_owned.php cat ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Enthusiast'" +SecRule &TX:'/SQL_INJECTION.*ARGS:cat/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Enthusiast SQL Injection Attempt -- show_owned.php cat ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005266) ET WEB_SPECIFIC Enthusiast SQL Injection Attempt -- show_joined.php cat +SecRule REQUEST_URI_RAW "(?i:\/show_joined\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005266,rev:4,msg:'ET WEB_SPECIFIC Enthusiast SQL Injection Attempt -- show_joined.php cat ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Enthusiast'" +SecRule &TX:'/SQL_INJECTION.*ARGS:cat/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Enthusiast SQL Injection Attempt -- show_joined.php cat ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006223) ET WEB_SPECIFIC Eric GUILLAUME uploader&downloader SQL Injection Attempt -- administre2.php id_user +SecRule REQUEST_URI_RAW "(?i:\/administration\/administre2\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006223,rev:4,msg:'ET WEB_SPECIFIC Eric GUILLAUME uploader&downloader SQL Injection Attempt -- administre2.php id_user ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Eric_Guillaume'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id_user/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Eric GUILLAUME uploader&downloader SQL Injection Attempt -- administre2.php id_user ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005881) ET WEB_SPECIFIC E-SMARTCART SQL Injection Attempt -- productdetail.asp product_id +SecRule REQUEST_URI_RAW "(?i:\/productdetail\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005881,rev:4,msg:'ET WEB_SPECIFIC E-SMARTCART SQL Injection Attempt -- productdetail.asp product_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Esmartcart'" +SecRule &TX:'/SQL_INJECTION.*ARGS:product_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC E-SMARTCART SQL Injection Attempt -- productdetail.asp product_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005340) ET WEB_SPECIFIC e-Vision CMS SQL Injection Attempt -- style.php template +SecRule REQUEST_URI_RAW "(?i:\/style\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005340,rev:4,msg:'ET WEB_SPECIFIC e-Vision CMS SQL Injection Attempt -- style.php template ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Evision'" +SecRule &TX:'/SQL_INJECTION.*ARGS:template/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC e-Vision CMS SQL Injection Attempt -- style.php template ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007064) ET WEB_SPECIFIC Evolve shopping cart SQL Injection Attempt -- products.asp partno +SecRule REQUEST_URI_RAW "(?i:\/products\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007064,rev:3,msg:'ET WEB_SPECIFIC Evolve shopping cart SQL Injection Attempt -- products.asp partno ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Evolve'" +SecRule &TX:'/SQL_INJECTION.*ARGS:partno/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Evolve shopping cart SQL Injection Attempt -- products.asp partno ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005085) ET WEB_SPECIFIC ExoPHPDesk SQL Injection Attempt -- faq.php id +SecRule REQUEST_URI_RAW "(?i:\/faq\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005085,rev:4,msg:'ET WEB_SPECIFIC ExoPHPDesk SQL Injection Attempt -- faq.php id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_ExoPHPDesk'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC ExoPHPDesk SQL Injection Attempt -- faq.php id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006817) ET WEB_SPECIFIC Expinion.net iNews SQL Injection Attempt -- articles.asp ex +SecRule REQUEST_URI_RAW "(?i:\/articles\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006817,rev:4,msg:'ET WEB_SPECIFIC Expinion.net iNews SQL Injection Attempt -- articles.asp ex ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Expinion.net'" +SecRule &TX:'/SQL_INJECTION.*ARGS:ex/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Expinion.net iNews SQL Injection Attempt -- articles.asp ex ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006343) ET WEB_SPECIFIC EzHRS HR Assist SQL Injection Attempt -- vdateUsr.asp +SecRule REQUEST_URI_RAW "(?i:\/vdateUsr\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006343,rev:4,msg:'ET WEB_SPECIFIC EzHRS HR Assist SQL Injection Attempt -- vdateUsr.asp ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_EzHRS'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\(.+SELECT)" + +# (sid 2005619) ET WEB_SPECIFIC Ezboxx Portal System Beta SQL Injection Attempt -- ShowAppendix.asp iid +SecRule REQUEST_URI_RAW "(?i:\/boxx\/ShowAppendix\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005619,rev:4,msg:'ET WEB_SPECIFIC Ezboxx Portal System Beta SQL Injection Attempt -- ShowAppendix.asp iid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Ezboxx'" +SecRule &TX:'/SQL_INJECTION.*ARGS:iid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Ezboxx Portal System Beta SQL Injection Attempt -- ShowAppendix.asp iid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2003850) ET WEB_SPECIFIC FAQEngine SQL Injection Attempt -- question.php questionref +SecRule REQUEST_URI_RAW "(?i:\/question\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2003850,rev:4,msg:'ET WEB_SPECIFIC FAQEngine SQL Injection Attempt -- question.php questionref ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_FAQEngine'" +SecRule REQUEST_URI_RAW "@contains (" "chain" +SecRule &TX:'/SQL_INJECTION.*ARGS:questionref/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC FAQEngine SQL Injection Attempt -- question.php questionref ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006127) ET WEB_SPECIFIC Mxmania File Upload Manager (FUM) SQL Injection Attempt -- detail.asp ID +SecRule REQUEST_URI_RAW "(?i:\/detail\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006127,rev:4,msg:'ET WEB_SPECIFIC Mxmania File Upload Manager (FUM) SQL Injection Attempt -- detail.asp ID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_FUM'" +SecRule &TX:'/SQL_INJECTION.*ARGS:ID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Mxmania File Upload Manager (FUM) SQL Injection Attempt -- detail.asp ID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006331) ET WEB_SPECIFIC Fantastic News SQL Injection Attempt -- news.php id +SecRule REQUEST_URI_RAW "(?i:\/news\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006331,rev:4,msg:'ET WEB_SPECIFIC Fantastic News SQL Injection Attempt -- news.php id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Fantastic_News'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Fantastic News SQL Injection Attempt -- news.php id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2003792) ET WEB_SPECIFIC FileRun SQL Injection Attempt -- index.php fid +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2003792,rev:4,msg:'ET WEB_SPECIFIC FileRun SQL Injection Attempt -- index.php fid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_FileRun'" +SecRule REQUEST_URI_RAW "@contains (" "chain" +SecRule &TX:'/SQL_INJECTION.*ARGS:fid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC FileRun SQL Injection Attempt -- index.php fid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006902) ET WEB_SPECIFIC FipsSHOP SQL Injection Attempt -- index.asp cat +SecRule REQUEST_URI_RAW "(?i:\/index\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006902,rev:4,msg:'ET WEB_SPECIFIC FipsSHOP SQL Injection Attempt -- index.asp cat ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_FipsSHOP'" +SecRule &TX:'/SQL_INJECTION.*ARGS:cat/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC FipsSHOP SQL Injection Attempt -- index.asp cat ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006908) ET WEB_SPECIFIC FipsSHOP SQL Injection Attempt -- index.asp did +SecRule REQUEST_URI_RAW "(?i:\/index\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006908,rev:4,msg:'ET WEB_SPECIFIC FipsSHOP SQL Injection Attempt -- index.asp did ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_FipsSHOP'" +SecRule &TX:'/SQL_INJECTION.*ARGS:did/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC FipsSHOP SQL Injection Attempt -- index.asp did ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007186) ET WEB_SPECIFIC Fixit iDMS Pro Image Gallery SQL Injection Attempt -- filelist.asp show_id +SecRule REQUEST_URI_RAW "(?i:\/filelist\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007186,rev:3,msg:'ET WEB_SPECIFIC Fixit iDMS Pro Image Gallery SQL Injection Attempt -- filelist.asp show_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Fixit_iDMS'" +SecRule &TX:'/SQL_INJECTION.*ARGS:show_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Fixit iDMS Pro Image Gallery SQL Injection Attempt -- filelist.asp show_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007192) ET WEB_SPECIFIC Fixit iDMS Pro Image Gallery SQL Injection Attempt -- filelist.asp parentid +SecRule REQUEST_URI_RAW "(?i:\/filelist\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007192,rev:3,msg:'ET WEB_SPECIFIC Fixit iDMS Pro Image Gallery SQL Injection Attempt -- filelist.asp parentid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Fixit_iDMS'" +SecRule &TX:'/SQL_INJECTION.*ARGS:parentid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Fixit iDMS Pro Image Gallery SQL Injection Attempt -- filelist.asp parentid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007198) ET WEB_SPECIFIC Fixit iDMS Pro Image Gallery SQL Injection Attempt -- showfile.asp fid +SecRule REQUEST_URI_RAW "(?i:\/showfile\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007198,rev:3,msg:'ET WEB_SPECIFIC Fixit iDMS Pro Image Gallery SQL Injection Attempt -- showfile.asp fid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Fixit_iDMS'" +SecRule &TX:'/SQL_INJECTION.*ARGS:fid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Fixit iDMS Pro Image Gallery SQL Injection Attempt -- showfile.asp fid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2003827) ET WEB_SPECIFIC Flashgames SQL Injection Attempt -- game.php lid +SecRule REQUEST_URI_RAW "(?i:\/game\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2003827,rev:4,msg:'ET WEB_SPECIFIC Flashgames SQL Injection Attempt -- game.php lid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Flashgames'" +SecRule REQUEST_URI_RAW "@contains (" "chain" +SecRule &TX:'/SQL_INJECTION.*ARGS:lid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Flashgames SQL Injection Attempt -- game.php lid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005150) ET WEB_SPECIFIC Forum Livre SQL Injection Attempt -- info_user.asp user +SecRule REQUEST_URI_RAW "(?i:\/info_user\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005150,rev:4,msg:'ET WEB_SPECIFIC Forum Livre SQL Injection Attempt -- info_user.asp user ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Forum_Livre'" +SecRule &TX:'/SQL_INJECTION.*ARGS:user/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Forum Livre SQL Injection Attempt -- info_user.asp user ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004921) ET WEB_SPECIFIC Fullaspsite ASP Hosting Site SQL Injection Attempt -- listmain.asp cat +SecRule REQUEST_URI_RAW "(?i:\/listmain\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004921,rev:4,msg:'ET WEB_SPECIFIC Fullaspsite ASP Hosting Site SQL Injection Attempt -- listmain.asp cat ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Fullaspsite'" +SecRule &TX:'/SQL_INJECTION.*ARGS:cat/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Fullaspsite ASP Hosting Site SQL Injection Attempt -- listmain.asp cat ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005079) ET WEB_SPECIFIC Fullaspsite Asp Hosting Sitesi SQL Injection Attempt -- windows.asp kategori_id +SecRule REQUEST_URI_RAW "(?i:\/windows\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005079,rev:4,msg:'ET WEB_SPECIFIC Fullaspsite Asp Hosting Sitesi SQL Injection Attempt -- windows.asp kategori_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Fullaspsite'" +SecRule &TX:'/SQL_INJECTION.*ARGS:kategori_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Fullaspsite Asp Hosting Sitesi SQL Injection Attempt -- windows.asp kategori_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005376) ET WEB_SPECIFIC Fullaspsite GeometriX Download Portal SQL Injection Attempt -- down_indir.asp id +SecRule REQUEST_URI_RAW "(?i:\/down_indir\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005376,rev:4,msg:'ET WEB_SPECIFIC Fullaspsite GeometriX Download Portal SQL Injection Attempt -- down_indir.asp id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Fullaspsite'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Fullaspsite GeometriX Download Portal SQL Injection Attempt -- down_indir.asp id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006465) ET WEB_SPECIFIC FuseTalk SQL Injection Attempt -- index.cfm +SecRule REQUEST_URI_RAW "(?i:\/index\.cfm)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006465,rev:4,msg:'ET WEB_SPECIFIC FuseTalk SQL Injection Attempt -- index.cfm ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Fusetalk'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:.+\(.+SELECT)" + +# (sid 2006471) ET WEB_SPECIFIC FuseTalk SQL Injection Attempt -- autherror.cfm errorcode +SecRule REQUEST_URI_RAW "(?i:\/forum\/include\/error\/autherror\.cfm)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006471,rev:4,msg:'ET WEB_SPECIFIC FuseTalk SQL Injection Attempt -- autherror.cfm errorcode ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Fusetalk'" +SecRule &TX:'/SQL_INJECTION.*ARGS:errorcode/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC FuseTalk SQL Injection Attempt -- autherror.cfm errorcode ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006193) ET WEB_SPECIFIC Future Internet SQL Injection Attempt -- index.cfm newsId +SecRule REQUEST_URI_RAW "(?i:\/index\.cfm)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006193,rev:4,msg:'ET WEB_SPECIFIC Future Internet SQL Injection Attempt -- index.cfm newsId ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Future_Internet'" +SecRule &TX:'/SQL_INJECTION.*ARGS:newsId/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Future Internet SQL Injection Attempt -- index.cfm newsId ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006199) ET WEB_SPECIFIC Future Internet SQL Injection Attempt -- index.cfm categoryid +SecRule REQUEST_URI_RAW "(?i:\/index\.cfm)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006199,rev:4,msg:'ET WEB_SPECIFIC Future Internet SQL Injection Attempt -- index.cfm categoryid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Future_Internet'" +SecRule &TX:'/SQL_INJECTION.*ARGS:categoryid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Future Internet SQL Injection Attempt -- index.cfm categoryid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006205) ET WEB_SPECIFIC Future Internet SQL Injection Attempt -- index.cfm langId +SecRule REQUEST_URI_RAW "(?i:\/index\.cfm)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006205,rev:4,msg:'ET WEB_SPECIFIC Future Internet SQL Injection Attempt -- index.cfm langId ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Future_Internet'" +SecRule &TX:'/SQL_INJECTION.*ARGS:langId/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Future Internet SQL Injection Attempt -- index.cfm langId ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005334) ET WEB_SPECIFIC Fuzzylime Forum SQL Injection Attempt -- low.php topic +SecRule REQUEST_URI_RAW "(?i:\/low\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005334,rev:4,msg:'ET WEB_SPECIFIC Fuzzylime Forum SQL Injection Attempt -- low.php topic ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Fuzzylime'" +SecRule &TX:'/SQL_INJECTION.*ARGS:topic/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Fuzzylime Forum SQL Injection Attempt -- low.php topic ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004003) ET WEB_SPECIFIC Gazi Download Portal SQL Injection Attempt -- down_indir.asp id +SecRule REQUEST_URI_RAW "(?i:\/down_indir\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004003,rev:4,msg:'ET WEB_SPECIFIC Gazi Download Portal SQL Injection Attempt -- down_indir.asp id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Gazi'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Gazi Download Portal SQL Injection Attempt -- down_indir.asp id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004401) ET WEB_SPECIFIC GaziYapBoz Game Portal SQL Injection Attempt -- kategori.asp kategori +SecRule REQUEST_URI_RAW "(?i:\/kategori\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004401,rev:4,msg:'ET WEB_SPECIFIC GaziYapBoz Game Portal SQL Injection Attempt -- kategori.asp kategori ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_GaziYapBoz'" +SecRule &TX:'/SQL_INJECTION.*ARGS:kategori/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC GaziYapBoz Game Portal SQL Injection Attempt -- kategori.asp kategori ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005013) ET WEB_SPECIFIC GlobalMegaCorp dvddb SQL Injection Attempt -- common.php user +SecRule REQUEST_URI_RAW "(?i:\/inc\/common\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005013,rev:4,msg:'ET WEB_SPECIFIC GlobalMegaCorp dvddb SQL Injection Attempt -- common.php user ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_GlobalMegaCorp'" +SecRule &TX:'/SQL_INJECTION.*ARGS:user/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC GlobalMegaCorp dvddb SQL Injection Attempt -- common.php user ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2003844) ET WEB_SPECIFIC Glossaire SQL Injection Attempt -- glossaire-p-f.php sid +SecRule REQUEST_URI_RAW "(?i:\/glossaire\-p\-f\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2003844,rev:4,msg:'ET WEB_SPECIFIC Glossaire SQL Injection Attempt -- glossaire-p-f.php sid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Glossaire'" +SecRule REQUEST_URI_RAW "@contains (" "chain" +SecRule &TX:'/SQL_INJECTION.*ARGS:sid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Glossaire SQL Injection Attempt -- glossaire-p-f.php sid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004353) ET WEB_SPECIFIC Grayscale Blog SQL Injection Attempt -- userdetail.php id +SecRule REQUEST_URI_RAW "(?i:\/userdetail\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004353,rev:4,msg:'ET WEB_SPECIFIC Grayscale Blog SQL Injection Attempt -- userdetail.php id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Grayscale_Blog'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Grayscale Blog SQL Injection Attempt -- userdetail.php id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004359) ET WEB_SPECIFIC Grayscale Blog SQL Injection Attempt -- jump.php id +SecRule REQUEST_URI_RAW "(?i:\/jump\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004359,rev:4,msg:'ET WEB_SPECIFIC Grayscale Blog SQL Injection Attempt -- jump.php id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Grayscale_Blog'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Grayscale Blog SQL Injection Attempt -- jump.php id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004365) ET WEB_SPECIFIC Grayscale Blog SQL Injection Attempt -- detail.php id +SecRule REQUEST_URI_RAW "(?i:\/detail\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004365,rev:4,msg:'ET WEB_SPECIFIC Grayscale Blog SQL Injection Attempt -- detail.php id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Grayscale_Blog'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Grayscale Blog SQL Injection Attempt -- detail.php id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004371) ET WEB_SPECIFIC Grayscale Blog SQL Injection Attempt -- jump.php url +SecRule REQUEST_URI_RAW "(?i:\/jump\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004371,rev:4,msg:'ET WEB_SPECIFIC Grayscale Blog SQL Injection Attempt -- jump.php url ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Grayscale_Blog'" +SecRule &TX:'/SQL_INJECTION.*ARGS:url/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Grayscale Blog SQL Injection Attempt -- jump.php url ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005311) ET WEB_SPECIFIC Guo Xu Guos Posting System (GPS) SQL Injection Attempt -- print.asp id +SecRule REQUEST_URI_RAW "(?i:\/print\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005311,rev:4,msg:'ET WEB_SPECIFIC Guo Xu Guos Posting System (GPS) SQL Injection Attempt -- print.asp id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Guo_Xu_Guos'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Guo Xu Guos Posting System (GPS) SQL Injection Attempt -- print.asp id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004395) ET WEB_SPECIFIC HC NEWSSYSTEM SQL Injection Attempt -- index.php ID +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004395,rev:4,msg:'ET WEB_SPECIFIC HC NEWSSYSTEM SQL Injection Attempt -- index.php ID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_HC_News'" +SecRule &TX:'/SQL_INJECTION.*ARGS:ID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC HC NEWSSYSTEM SQL Injection Attempt -- index.php ID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007408) ET WEB_SPECIFIC HIOX Star Rating System Script (HSRS) SQL Injection Attempt -- addrating.php ipadd +SecRule REQUEST_URI_RAW "(?i:\/addrating\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007408,rev:3,msg:'ET WEB_SPECIFIC HIOX Star Rating System Script (HSRS) SQL Injection Attempt -- addrating.php ipadd ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_HIOX'" +SecRule &TX:'/SQL_INJECTION.*ARGS:ipadd/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC HIOX Star Rating System Script (HSRS) SQL Injection Attempt -- addrating.php ipadd ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007414) ET WEB_SPECIFIC HIOX Star Rating System Script (HSRS) SQL Injection Attempt -- addrating.php url +SecRule REQUEST_URI_RAW "(?i:\/addrating\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007414,rev:3,msg:'ET WEB_SPECIFIC HIOX Star Rating System Script (HSRS) SQL Injection Attempt -- addrating.php url ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_HIOX'" +SecRule &TX:'/SQL_INJECTION.*ARGS:url/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC HIOX Star Rating System Script (HSRS) SQL Injection Attempt -- addrating.php url ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004425) ET WEB_SPECIFIC Hazir Site SQL Injection Attempt -- giris_yap.asp sifre +SecRule REQUEST_URI_RAW "(?i:\/giris_yap\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004425,rev:4,msg:'ET WEB_SPECIFIC Hazir Site SQL Injection Attempt -- giris_yap.asp sifre ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Hazir'" +SecRule &TX:'/SQL_INJECTION.*ARGS:sifre/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Hazir Site SQL Injection Attempt -- giris_yap.asp sifre ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004633) ET WEB_SPECIFIC Hunkaray Okul Portaly SQL Injection Attempt -- haberoku.asp id +SecRule REQUEST_URI_RAW "(?i:\/haberoku\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004633,rev:4,msg:'ET WEB_SPECIFIC Hunkaray Okul Portaly SQL Injection Attempt -- haberoku.asp id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Hunkaray'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Hunkaray Okul Portaly SQL Injection Attempt -- haberoku.asp id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005067) ET WEB_SPECIFIC Hunkaray Duyuru Scripti SQL Injection Attempt -- oku.asp id +SecRule REQUEST_URI_RAW "(?i:\/oku\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005067,rev:4,msg:'ET WEB_SPECIFIC Hunkaray Duyuru Scripti SQL Injection Attempt -- oku.asp id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Hunkaray'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Hunkaray Duyuru Scripti SQL Injection Attempt -- oku.asp id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005643) ET WEB_SPECIFIC Image Gallery with Access Database SQL Injection Attempt -- dispimage.asp id +SecRule REQUEST_URI_RAW "(?i:\/dispimage\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005643,rev:4,msg:'ET WEB_SPECIFIC Image Gallery with Access Database SQL Injection Attempt -- dispimage.asp id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Image_Gallery'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Image Gallery with Access Database SQL Injection Attempt -- dispimage.asp id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005649) ET WEB_SPECIFIC Image Gallery with Access Database SQL Injection Attempt -- default.asp order +SecRule REQUEST_URI_RAW "(?i:\/default\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005649,rev:4,msg:'ET WEB_SPECIFIC Image Gallery with Access Database SQL Injection Attempt -- default.asp order ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Image_Gallery'" +SecRule &TX:'/SQL_INJECTION.*ARGS:order/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Image Gallery with Access Database SQL Injection Attempt -- default.asp order ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005655) ET WEB_SPECIFIC Image Gallery with Access Database SQL Injection Attempt -- default.asp page +SecRule REQUEST_URI_RAW "(?i:\/default\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005655,rev:4,msg:'ET WEB_SPECIFIC Image Gallery with Access Database SQL Injection Attempt -- default.asp page ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Image_Gallery'" +SecRule &TX:'/SQL_INJECTION.*ARGS:page/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Image Gallery with Access Database SQL Injection Attempt -- default.asp page ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006866) ET WEB_SPECIFIC Infinitytechs Restaurants CM SQL Injection Attempt -- rating.asp id +SecRule REQUEST_URI_RAW "(?i:\/rating\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006866,rev:4,msg:'ET WEB_SPECIFIC Infinitytechs Restaurants CM SQL Injection Attempt -- rating.asp id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Infinitytechs'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Infinitytechs Restaurants CM SQL Injection Attempt -- rating.asp id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006872) ET WEB_SPECIFIC Infinitytechs Restaurants CM SQL Injection Attempt -- meal_rest.asp mealid +SecRule REQUEST_URI_RAW "(?i:\/meal_rest\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006872,rev:4,msg:'ET WEB_SPECIFIC Infinitytechs Restaurants CM SQL Injection Attempt -- meal_rest.asp mealid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Infinitytechs'" +SecRule &TX:'/SQL_INJECTION.*ARGS:mealid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Infinitytechs Restaurants CM SQL Injection Attempt -- meal_rest.asp mealid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006878) ET WEB_SPECIFIC Infinitytechs Restaurants CM SQL Injection Attempt -- res_details.asp resid +SecRule REQUEST_URI_RAW "(?i:\/res_details\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006878,rev:4,msg:'ET WEB_SPECIFIC Infinitytechs Restaurants CM SQL Injection Attempt -- res_details.asp resid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Infinitytechs'" +SecRule &TX:'/SQL_INJECTION.*ARGS:resid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Infinitytechs Restaurants CM SQL Injection Attempt -- res_details.asp resid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004801) ET WEB_SPECIFIC Invision Power Board (IPB) SQL Injection Attempt -- class_session.php CLIENT_IP +SecRule REQUEST_URI_RAW "(?i:\/classes\/class_session\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004801,rev:4,msg:'ET WEB_SPECIFIC Invision Power Board (IPB) SQL Injection Attempt -- class_session.php CLIENT_IP ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Invision'" +SecRule &TX:'/SQL_INJECTION.*ARGS:CLIENT_IP/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Invision Power Board (IPB) SQL Injection Attempt -- class_session.php CLIENT_IP ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006673) ET WEB_SPECIFIC Invision Gallery SQL Injection Attempt -- post.php img +SecRule REQUEST_URI_RAW "(?i:\/forum\/modules\/gallery\/post\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006673,rev:4,msg:'ET WEB_SPECIFIC Invision Gallery SQL Injection Attempt -- post.php img ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Invision'" +SecRule &TX:'/SQL_INJECTION.*ARGS:img/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Invision Gallery SQL Injection Attempt -- post.php img ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006679) ET WEB_SPECIFIC Invision Gallery SQL Injection Attempt -- index.php img +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006679,rev:4,msg:'ET WEB_SPECIFIC Invision Gallery SQL Injection Attempt -- index.php img ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Invision'" +SecRule &TX:'/SQL_INJECTION.*ARGS:img/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Invision Gallery SQL Injection Attempt -- index.php img ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006685) ET WEB_SPECIFIC Invision Community Blog Mod SQL Injection Attempt -- entry_reply_entry.php eid +SecRule REQUEST_URI_RAW "(?i:\/lib\/entry_reply_entry\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006685,rev:4,msg:'ET WEB_SPECIFIC Invision Community Blog Mod SQL Injection Attempt -- entry_reply_entry.php eid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Invision'" +SecRule &TX:'/SQL_INJECTION.*ARGS:eid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Invision Community Blog Mod SQL Injection Attempt -- entry_reply_entry.php eid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006211) ET WEB_SPECIFIC Ixprim SQL Injection Attempt -- ixm_ixpnews.php story_id +SecRule REQUEST_URI_RAW "(?i:\/ixm_ixpnews\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006211,rev:4,msg:'ET WEB_SPECIFIC Ixprim SQL Injection Attempt -- ixm_ixpnews.php story_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Ixprim'" +SecRule &TX:'/SQL_INJECTION.*ARGS:story_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Ixprim SQL Injection Attempt -- ixm_ixpnews.php story_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005346) ET WEB_SPECIFIC Just For Fun Network Management System (JFFNMS) SQL Injection Attempt -- auth.php pass +SecRule REQUEST_URI_RAW "(?i:\/auth\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005346,rev:4,msg:'ET WEB_SPECIFIC Just For Fun Network Management System (JFFNMS) SQL Injection Attempt -- auth.php pass ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_JFF_NM'" +SecRule &TX:'/SQL_INJECTION.*ARGS:pass/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Just For Fun Network Management System (JFFNMS) SQL Injection Attempt -- auth.php pass ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005364) ET WEB_SPECIFIC Just For Fun Network Management System (JFFNMS) SQL Injection Attempt -- auth.php user +SecRule REQUEST_URI_RAW "(?i:\/auth\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005364,rev:4,msg:'ET WEB_SPECIFIC Just For Fun Network Management System (JFFNMS) SQL Injection Attempt -- auth.php user ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_JFF_NM'" +SecRule &TX:'/SQL_INJECTION.*ARGS:user/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Just For Fun Network Management System (JFFNMS) SQL Injection Attempt -- auth.php user ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005370) ET WEB_SPECIFIC Just For Fun Network Management System (JFFNMS) SQL Injection Attempt -- auth.php pass +SecRule REQUEST_URI_RAW "(?i:\/auth\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005370,rev:4,msg:'ET WEB_SPECIFIC Just For Fun Network Management System (JFFNMS) SQL Injection Attempt -- auth.php pass ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_JFF_NM'" +SecRule &TX:'/SQL_INJECTION.*ARGS:pass/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Just For Fun Network Management System (JFFNMS) SQL Injection Attempt -- auth.php pass ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004156) ET WEB_SPECIFIC JGBBS SQL Injection Attempt -- search.asp title +SecRule REQUEST_URI_RAW "(?i:\/search\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004156,rev:4,msg:'ET WEB_SPECIFIC JGBBS SQL Injection Attempt -- search.asp title ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_JGBBS'" +SecRule &TX:'/SQL_INJECTION.*ARGS:title/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC JGBBS SQL Injection Attempt -- search.asp title ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004341) ET WEB_SPECIFIC JGBBS SQL Injection Attempt -- search.asp author +SecRule REQUEST_URI_RAW "(?i:\/search\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004341,rev:4,msg:'ET WEB_SPECIFIC JGBBS SQL Injection Attempt -- search.asp author ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_JGBBS'" +SecRule &TX:'/SQL_INJECTION.*ARGS:author/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC JGBBS SQL Injection Attempt -- search.asp author ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004484) ET WEB_SPECIFIC PHP JackKnife SQL Injection Attempt -- G_Display.php iCategoryUnq +SecRule REQUEST_URI_RAW "(?i:\/G_Display\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004484,rev:4,msg:'ET WEB_SPECIFIC PHP JackKnife SQL Injection Attempt -- G_Display.php iCategoryUnq ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_JackKnife'" +SecRule &TX:'/SQL_INJECTION.*ARGS:iCategoryUnq/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC PHP JackKnife SQL Injection Attempt -- G_Display.php iCategoryUnq ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004490) ET WEB_SPECIFIC PHP JackKnife SQL Injection Attempt -- DisplayResults.php iSearchID +SecRule REQUEST_URI_RAW "(?i:\/Search\/DisplayResults\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004490,rev:4,msg:'ET WEB_SPECIFIC PHP JackKnife SQL Injection Attempt -- DisplayResults.php iSearchID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_JackKnife'" +SecRule &TX:'/SQL_INJECTION.*ARGS:iSearchID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC PHP JackKnife SQL Injection Attempt -- DisplayResults.php iSearchID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006496) ET WEB_SPECIFIC Jasmine CMS SQL Injection Attempt -- login.php login_username +SecRule REQUEST_URI_RAW "(?i:\/login\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006496,rev:4,msg:'ET WEB_SPECIFIC Jasmine CMS SQL Injection Attempt -- login.php login_username ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Jasmine_CMS'" +SecRule &TX:'/SQL_INJECTION.*ARGS:login_username/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Jasmine CMS SQL Injection Attempt -- login.php login_username ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006502) ET WEB_SPECIFIC Jasmine CMS SQL Injection Attempt -- news.php item +SecRule REQUEST_URI_RAW "(?i:\/news\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006502,rev:4,msg:'ET WEB_SPECIFIC Jasmine CMS SQL Injection Attempt -- news.php item ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Jasmine_CMS'" +SecRule &TX:'/SQL_INJECTION.*ARGS:item/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Jasmine CMS SQL Injection Attempt -- news.php item ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004081) ET WEB_SPECIFIC Jelsoft vBulletin SQL Injection Attempt -- attachment.php +SecRule REQUEST_URI_RAW "(?i:\/admincp\/attachment\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004081,rev:4,msg:'ET WEB_SPECIFIC Jelsoft vBulletin SQL Injection Attempt -- attachment.php ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Jelsoft'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:.+\(.+SELECT)" + +# (sid 2004150) ET WEB_SPECIFIC Jelsoft vBulletin SQL Injection Attempt -- attachment.php +SecRule REQUEST_URI_RAW "(?i:\/admincp\/attachment\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004150,rev:4,msg:'ET WEB_SPECIFIC Jelsoft vBulletin SQL Injection Attempt -- attachment.php ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Jelsoft'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\(.+SELECT)" + +# (sid 2004670) ET WEB_SPECIFIC Jelsoft vBulletin SQL Injection Attempt -- inlinemod.php postids +SecRule REQUEST_URI_RAW "(?i:\/inlinemod\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004670,rev:4,msg:'ET WEB_SPECIFIC Jelsoft vBulletin SQL Injection Attempt -- inlinemod.php postids ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Jelsoft'" +SecRule &TX:'/SQL_INJECTION.*ARGS:postids/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Jelsoft vBulletin SQL Injection Attempt -- inlinemod.php postids ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2003943) ET WEB_SPECIFIC Jetbox CMS SQL Injection Attempt -- main_page.php +SecRule REQUEST_URI_RAW "(?i:\/main_page\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2003943,rev:4,msg:'ET WEB_SPECIFIC Jetbox CMS SQL Injection Attempt -- main_page.php ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Jetbox'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:.+\(.+SELECT)" + +# (sid 2003949) ET WEB_SPECIFIC Jetbox CMS SQL Injection Attempt -- open_tree.php +SecRule REQUEST_URI_RAW "(?i:\/open_tree\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2003949,rev:4,msg:'ET WEB_SPECIFIC Jetbox CMS SQL Injection Attempt -- open_tree.php ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Jetbox'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:.+\(.+SELECT)" + +# (sid 2003955) ET WEB_SPECIFIC Jetbox CMS SQL Injection Attempt -- outputs.php +SecRule REQUEST_URI_RAW "(?i:\/outputs\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2003955,rev:4,msg:'ET WEB_SPECIFIC Jetbox CMS SQL Injection Attempt -- outputs.php ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Jetbox'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:.+\(.+SELECT)" + +# (sid 2003961) ET WEB_SPECIFIC Jetbox CMS SQL Injection Attempt -- index.php view +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2003961,rev:4,msg:'ET WEB_SPECIFIC Jetbox CMS SQL Injection Attempt -- index.php view ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Jetbox'" +SecRule &TX:'/SQL_INJECTION.*ARGS:view/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Jetbox CMS SQL Injection Attempt -- index.php view ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2003967) ET WEB_SPECIFIC Jetbox CMS SQL Injection Attempt -- opentree.php id +SecRule REQUEST_URI_RAW "(?i:\/admin\/cms\/opentree\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2003967,rev:4,msg:'ET WEB_SPECIFIC Jetbox CMS SQL Injection Attempt -- opentree.php id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Jetbox'" +SecRule REQUEST_URI_RAW "@contains id[" "chain" +SecRule QUERY_STRING|REQUEST_BODY "(?i:.+\(.+SELECT)" + +# (sid 2003973) ET WEB_SPECIFIC Jetbox CMS SQL Injection Attempt -- index.php login +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2003973,rev:4,msg:'ET WEB_SPECIFIC Jetbox CMS SQL Injection Attempt -- index.php login ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Jetbox'" +SecRule &TX:'/SQL_INJECTION.*ARGS:login/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Jetbox CMS SQL Injection Attempt -- index.php login ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007348) ET WEB_SPECIFIC JiRos FAQ Manager SQL Injection Attempt -- index.asp tID +SecRule REQUEST_URI_RAW "(?i:\/index\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007348,rev:3,msg:'ET WEB_SPECIFIC JiRos FAQ Manager SQL Injection Attempt -- index.asp tID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Jiros'" +SecRule &TX:'/SQL_INJECTION.*ARGS:tID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC JiRos FAQ Manager SQL Injection Attempt -- index.asp tID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007354) ET WEB_SPECIFIC JiRos Links Manager SQL Injection Attempt -- openlink.asp LinkID +SecRule REQUEST_URI_RAW "(?i:\/openlink\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007354,rev:3,msg:'ET WEB_SPECIFIC JiRos Links Manager SQL Injection Attempt -- openlink.asp LinkID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Jiros'" +SecRule &TX:'/SQL_INJECTION.*ARGS:LinkID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC JiRos Links Manager SQL Injection Attempt -- openlink.asp LinkID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007360) ET WEB_SPECIFIC JiRos Links Manager SQL Injection Attempt -- viewlinks.asp CategoryID +SecRule REQUEST_URI_RAW "(?i:\/viewlinks\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007360,rev:3,msg:'ET WEB_SPECIFIC JiRos Links Manager SQL Injection Attempt -- viewlinks.asp CategoryID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Jiros'" +SecRule &TX:'/SQL_INJECTION.*ARGS:CategoryID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC JiRos Links Manager SQL Injection Attempt -- viewlinks.asp CategoryID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004377) ET WEB_SPECIFIC PHP Labs JobSitePro SQL Injection Attempt -- search.php salary +SecRule REQUEST_URI_RAW "(?i:\/search\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004377,rev:4,msg:'ET WEB_SPECIFIC PHP Labs JobSitePro SQL Injection Attempt -- search.php salary ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Jobsitepro'" +SecRule &TX:'/SQL_INJECTION.*ARGS:salary/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC PHP Labs JobSitePro SQL Injection Attempt -- search.php salary ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2003762) ET WEB_SPECIFIC John Mordo Jobs SQL Injection Attempt -- index.php cid +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2003762,rev:4,msg:'ET WEB_SPECIFIC John Mordo Jobs SQL Injection Attempt -- index.php cid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_John_Mordo'" +SecRule REQUEST_URI_RAW "@contains (" "chain" +SecRule &TX:'/SQL_INJECTION.*ARGS:cid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC John Mordo Jobs SQL Injection Attempt -- index.php cid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005296) ET WEB_SPECIFIC Joomla! SQL Injection Attempt -- category.php catid +SecRule REQUEST_URI_RAW "(?i:\/models\/category\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005296,rev:4,msg:'ET WEB_SPECIFIC Joomla! SQL Injection Attempt -- category.php catid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Joomla'" +SecRule &TX:'/SQL_INJECTION.*ARGS:catid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Joomla! SQL Injection Attempt -- category.php catid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005302) ET WEB_SPECIFIC Joomla! SQL Injection Attempt -- letterman.class.php id +SecRule REQUEST_URI_RAW "(?i:\/letterman\.class\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005302,rev:4,msg:'ET WEB_SPECIFIC Joomla! SQL Injection Attempt -- letterman.class.php id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Joomla'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Joomla! SQL Injection Attempt -- letterman.class.php id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005394) ET WEB_SPECIFIC Joomla! SQL Injection Attempt -- example.php +SecRule REQUEST_URI_RAW "(?i:\/plugins\/user\/example\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005394,rev:4,msg:'ET WEB_SPECIFIC Joomla! SQL Injection Attempt -- example.php ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Joomla'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\(.+SELECT)" + +# (sid 2005400) ET WEB_SPECIFIC Joomla! SQL Injection Attempt -- gmail.php +SecRule REQUEST_URI_RAW "(?i:\/gmail\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005400,rev:4,msg:'ET WEB_SPECIFIC Joomla! SQL Injection Attempt -- gmail.php ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Joomla'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\(.+SELECT)" + +# (sid 2005406) ET WEB_SPECIFIC Joomla! SQL Injection Attempt -- example.php +SecRule REQUEST_URI_RAW "(?i:\/example\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005406,rev:4,msg:'ET WEB_SPECIFIC Joomla! SQL Injection Attempt -- example.php ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Joomla'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\(.+SELECT)" + +# (sid 2005412) ET WEB_SPECIFIC Joomla! SQL Injection Attempt -- ldap.php +SecRule REQUEST_URI_RAW "(?i:\/plugins\/authentication\/ldap\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005412,rev:4,msg:'ET WEB_SPECIFIC Joomla! SQL Injection Attempt -- ldap.php ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Joomla'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\(.+SELECT)" + +# (sid 2005418) ET WEB_SPECIFIC Joomla! SQL Injection Attempt -- menu.php +SecRule REQUEST_URI_RAW "(?i:\/modules\/mod_mainmenu\/menu\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005418,rev:4,msg:'ET WEB_SPECIFIC Joomla! SQL Injection Attempt -- menu.php ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Joomla'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\(.+SELECT)" + +# (sid 2005424) ET WEB_SPECIFIC Joomla! SQL Injection Attempt -- content.php where +SecRule REQUEST_URI_RAW "(?i:\/plugins\/search\/content\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005424,rev:4,msg:'ET WEB_SPECIFIC Joomla! SQL Injection Attempt -- content.php where ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Joomla'" +SecRule &TX:'/SQL_INJECTION.*ARGS:where/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Joomla! SQL Injection Attempt -- content.php where ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005430) ET WEB_SPECIFIC Joomla! SQL Injection Attempt -- weblinks.php where +SecRule REQUEST_URI_RAW "(?i:\/plugins\/search\/weblinks\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005430,rev:4,msg:'ET WEB_SPECIFIC Joomla! SQL Injection Attempt -- weblinks.php where ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Joomla'" +SecRule &TX:'/SQL_INJECTION.*ARGS:where/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Joomla! SQL Injection Attempt -- weblinks.php where ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005436) ET WEB_SPECIFIC Joomla! SQL Injection Attempt -- contacts.php text +SecRule REQUEST_URI_RAW "(?i:\/plugins\/search\/contacts\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005436,rev:4,msg:'ET WEB_SPECIFIC Joomla! SQL Injection Attempt -- contacts.php text ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Joomla'" +SecRule &TX:'/SQL_INJECTION.*ARGS:text/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Joomla! SQL Injection Attempt -- contacts.php text ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005442) ET WEB_SPECIFIC Joomla! SQL Injection Attempt -- categories.php text +SecRule REQUEST_URI_RAW "(?i:\/plugins\/search\/categories\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005442,rev:4,msg:'ET WEB_SPECIFIC Joomla! SQL Injection Attempt -- categories.php text ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Joomla'" +SecRule &TX:'/SQL_INJECTION.*ARGS:text/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Joomla! SQL Injection Attempt -- categories.php text ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005448) ET WEB_SPECIFIC Joomla! SQL Injection Attempt -- sections.php text +SecRule REQUEST_URI_RAW "(?i:\/plugins\/search\/sections\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005448,rev:4,msg:'ET WEB_SPECIFIC Joomla! SQL Injection Attempt -- sections.php text ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Joomla'" +SecRule &TX:'/SQL_INJECTION.*ARGS:text/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Joomla! SQL Injection Attempt -- sections.php text ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005454) ET WEB_SPECIFIC Joomla! SQL Injection Attempt -- user.php email +SecRule REQUEST_URI_RAW "(?i:\/database\/table\/user\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005454,rev:4,msg:'ET WEB_SPECIFIC Joomla! SQL Injection Attempt -- user.php email ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Joomla'" +SecRule &TX:'/SQL_INJECTION.*ARGS:email/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Joomla! SQL Injection Attempt -- user.php email ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006764) ET WEB_SPECIFIC KLF-DESIGN (aka Kim L. Fraser) KLF-REALTY SQL Injection Attempt -- search_listing.asp category +SecRule REQUEST_URI_RAW "(?i:\/search_listing\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006764,rev:4,msg:'ET WEB_SPECIFIC KLF-DESIGN (aka Kim L. Fraser) KLF-REALTY SQL Injection Attempt -- search_listing.asp category ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_KLF_Design'" +SecRule &TX:'/SQL_INJECTION.*ARGS:category/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC KLF-DESIGN (aka Kim L. Fraser) KLF-REALTY SQL Injection Attempt -- search_listing.asp category ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006770) ET WEB_SPECIFIC KLF-DESIGN (aka Kim L. Fraser) KLF-REALTY SQL Injection Attempt -- search_listing.asp agent +SecRule REQUEST_URI_RAW "(?i:\/search_listing\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006770,rev:4,msg:'ET WEB_SPECIFIC KLF-DESIGN (aka Kim L. Fraser) KLF-REALTY SQL Injection Attempt -- search_listing.asp agent ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_KLF_Design'" +SecRule &TX:'/SQL_INJECTION.*ARGS:agent/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC KLF-DESIGN (aka Kim L. Fraser) KLF-REALTY SQL Injection Attempt -- search_listing.asp agent ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006776) ET WEB_SPECIFIC KLF-DESIGN (aka Kim L. Fraser) KLF-REALTY SQL Injection Attempt -- detail.asp property_id +SecRule REQUEST_URI_RAW "(?i:\/detail\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006776,rev:4,msg:'ET WEB_SPECIFIC KLF-DESIGN (aka Kim L. Fraser) KLF-REALTY SQL Injection Attempt -- detail.asp property_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_KLF_Design'" +SecRule &TX:'/SQL_INJECTION.*ARGS:property_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC KLF-DESIGN (aka Kim L. Fraser) KLF-REALTY SQL Injection Attempt -- detail.asp property_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004645) ET WEB_SPECIFIC Kartli Alisveris Sistemi SQL Injection Attempt -- news.asp news_id +SecRule REQUEST_URI_RAW "(?i:\/news\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004645,rev:4,msg:'ET WEB_SPECIFIC Kartli Alisveris Sistemi SQL Injection Attempt -- news.asp news_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Kartli'" +SecRule &TX:'/SQL_INJECTION.*ARGS:news_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Kartli Alisveris Sistemi SQL Injection Attempt -- news.asp news_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004126) ET WEB_SPECIFIC Katalog Plyt Audio SQL Injection Attempt -- index.php kolumna +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004126,rev:4,msg:'ET WEB_SPECIFIC Katalog Plyt Audio SQL Injection Attempt -- index.php kolumna ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Katalog_Plyt'" +SecRule &TX:'/SQL_INJECTION.*ARGS:kolumna/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Katalog Plyt Audio SQL Injection Attempt -- index.php kolumna ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004983) ET WEB_SPECIFIC Kisisel Site 2007 SQL Injection Attempt -- forum.asp forumid +SecRule REQUEST_URI_RAW "(?i:\/forum\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004983,rev:4,msg:'ET WEB_SPECIFIC Kisisel Site 2007 SQL Injection Attempt -- forum.asp forumid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Kisisel'" +SecRule &TX:'/SQL_INJECTION.*ARGS:forumid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Kisisel Site 2007 SQL Injection Attempt -- forum.asp forumid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005800) ET WEB_SPECIFIC Kolayindir Download (Yenionline) SQL Injection Attempt -- down.asp id +SecRule REQUEST_URI_RAW "(?i:\/down\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005800,rev:4,msg:'ET WEB_SPECIFIC Kolayindir Download (Yenionline) SQL Injection Attempt -- down.asp id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Kolayindir'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Kolayindir Download (Yenionline) SQL Injection Attempt -- down.asp id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004693) ET WEB_SPECIFIC Kubix SQL Injection Attempt -- index.php member_id +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004693,rev:4,msg:'ET WEB_SPECIFIC Kubix SQL Injection Attempt -- index.php member_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Kubix'" +SecRule &TX:'/SQL_INJECTION.*ARGS:member_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Kubix SQL Injection Attempt -- index.php member_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005073) ET WEB_SPECIFIC Michelles L2J Dropcalc SQL Injection Attempt -- i-search.php itemid +SecRule REQUEST_URI_RAW "(?i:\/i\-search\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005073,rev:4,msg:'ET WEB_SPECIFIC Michelles L2J Dropcalc SQL Injection Attempt -- i-search.php itemid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_L2J_DropCalc'" +SecRule &TX:'/SQL_INJECTION.*ARGS:itemid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Michelles L2J Dropcalc SQL Injection Attempt -- i-search.php itemid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005977) ET WEB_SPECIFIC Neocrome Land Down Under (LDU) SQL Injection Attempt -- journal.php w +SecRule REQUEST_URI_RAW "(?i:\/journal\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005977,rev:4,msg:'ET WEB_SPECIFIC Neocrome Land Down Under (LDU) SQL Injection Attempt -- journal.php w ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_LDU'" +SecRule &TX:'/SQL_INJECTION.*ARGS:w/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Neocrome Land Down Under (LDU) SQL Injection Attempt -- journal.php w ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006319) ET WEB_SPECIFIC Neocrome Land Down Under (LDU) SQL Injection Attempt -- polls.php id +SecRule REQUEST_URI_RAW "(?i:\/polls\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006319,rev:4,msg:'ET WEB_SPECIFIC Neocrome Land Down Under (LDU) SQL Injection Attempt -- polls.php id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_LDU'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Neocrome Land Down Under (LDU) SQL Injection Attempt -- polls.php id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004527) ET WEB_SPECIFIC LI-Guestbook SQL Injection Attempt -- guestbook.php country +SecRule REQUEST_URI_RAW "(?i:\/guestbook\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004527,rev:4,msg:'ET WEB_SPECIFIC LI-Guestbook SQL Injection Attempt -- guestbook.php country ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_LI_Guestbook'" +SecRule &TX:'/SQL_INJECTION.*ARGS:country/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC LI-Guestbook SQL Injection Attempt -- guestbook.php country ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007298) ET WEB_SPECIFIC Doug Luxem Liberum Help Desk SQL Injection Attempt -- status.asp id +SecRule REQUEST_URI_RAW "(?i:\/inout\/status\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007298,rev:3,msg:'ET WEB_SPECIFIC Doug Luxem Liberum Help Desk SQL Injection Attempt -- status.asp id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Liberum'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Doug Luxem Liberum Help Desk SQL Injection Attempt -- status.asp id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007304) ET WEB_SPECIFIC Doug Luxem Liberum Help Desk SQL Injection Attempt -- update.asp id +SecRule REQUEST_URI_RAW "(?i:\/inout\/update\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007304,rev:3,msg:'ET WEB_SPECIFIC Doug Luxem Liberum Help Desk SQL Injection Attempt -- update.asp id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Liberum'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Doug Luxem Liberum Help Desk SQL Injection Attempt -- update.asp id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007310) ET WEB_SPECIFIC Doug Luxem Liberum Help Desk SQL Injection Attempt -- forgotpass.asp id +SecRule REQUEST_URI_RAW "(?i:\/forgotpass\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007310,rev:3,msg:'ET WEB_SPECIFIC Doug Luxem Liberum Help Desk SQL Injection Attempt -- forgotpass.asp id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Liberum'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Doug Luxem Liberum Help Desk SQL Injection Attempt -- forgotpass.asp id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007316) ET WEB_SPECIFIC Doug Luxem Liberum Help Desk SQL Injection Attempt -- forgotpass.asp uid +SecRule REQUEST_URI_RAW "(?i:\/forgotpass\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007316,rev:3,msg:'ET WEB_SPECIFIC Doug Luxem Liberum Help Desk SQL Injection Attempt -- forgotpass.asp uid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Liberum'" +SecRule &TX:'/SQL_INJECTION.*ARGS:uid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Doug Luxem Liberum Help Desk SQL Injection Attempt -- forgotpass.asp uid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007322) ET WEB_SPECIFIC Doug Luxem Liberum Help Desk SQL Injection Attempt -- update.asp uid +SecRule REQUEST_URI_RAW "(?i:\/inout\/update\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007322,rev:3,msg:'ET WEB_SPECIFIC Doug Luxem Liberum Help Desk SQL Injection Attempt -- update.asp uid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Liberum'" +SecRule &TX:'/SQL_INJECTION.*ARGS:uid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Doug Luxem Liberum Help Desk SQL Injection Attempt -- update.asp uid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007328) ET WEB_SPECIFIC Doug Luxem Liberum Help Desk SQL Injection Attempt -- status.asp uid +SecRule REQUEST_URI_RAW "(?i:\/inout\/status\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007328,rev:3,msg:'ET WEB_SPECIFIC Doug Luxem Liberum Help Desk SQL Injection Attempt -- status.asp uid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Liberum'" +SecRule &TX:'/SQL_INJECTION.*ARGS:uid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Doug Luxem Liberum Help Desk SQL Injection Attempt -- status.asp uid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007334) ET WEB_SPECIFIC Doug Luxem Liberum Help Desk SQL Injection Attempt -- details.asp id +SecRule REQUEST_URI_RAW "(?i:\/details\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007334,rev:3,msg:'ET WEB_SPECIFIC Doug Luxem Liberum Help Desk SQL Injection Attempt -- details.asp id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Liberum'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Doug Luxem Liberum Help Desk SQL Injection Attempt -- details.asp id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006661) ET WEB_SPECIFIC LINK Content Management Server (CMS) SQL Injection Attempt -- navigacija.php IDMeniGlavni +SecRule REQUEST_URI_RAW "(?i:\/navigacija\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006661,rev:4,msg:'ET WEB_SPECIFIC LINK Content Management Server (CMS) SQL Injection Attempt -- navigacija.php IDMeniGlavni ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Link_CMS'" +SecRule &TX:'/SQL_INJECTION.*ARGS:IDMeniGlavni/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC LINK Content Management Server (CMS) SQL Injection Attempt -- navigacija.php IDMeniGlavni ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006667) ET WEB_SPECIFIC LINK Content Management Server (CMS) SQL Injection Attempt -- prikazInformacije.php IDStranicaPodaci +SecRule REQUEST_URI_RAW "(?i:\/prikazInformacije\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006667,rev:4,msg:'ET WEB_SPECIFIC LINK Content Management Server (CMS) SQL Injection Attempt -- prikazInformacije.php IDStranicaPodaci ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Link_CMS'" +SecRule &TX:'/SQL_INJECTION.*ARGS:IDStranicaPodaci/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC LINK Content Management Server (CMS) SQL Injection Attempt -- prikazInformacije.php IDStranicaPodaci ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007366) ET WEB_SPECIFIC Link Exchange Lite SQL Injection Attempt -- linkslist.asp psearch +SecRule REQUEST_URI_RAW "(?i:\/linkslist\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007366,rev:3,msg:'ET WEB_SPECIFIC Link Exchange Lite SQL Injection Attempt -- linkslist.asp psearch ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Link_Exchange_Lite'" +SecRule &TX:'/SQL_INJECTION.*ARGS:psearch/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Link Exchange Lite SQL Injection Attempt -- linkslist.asp psearch ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007372) ET WEB_SPECIFIC Link Exchange Lite SQL Injection Attempt -- search.asp +SecRule REQUEST_URI_RAW "(?i:\/search\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007372,rev:3,msg:'ET WEB_SPECIFIC Link Exchange Lite SQL Injection Attempt -- search.asp ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Link_Exchange_Lite'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:.+\(.+SELECT)" + +# (sid 2004413) ET WEB_SPECIFIC Links Management Application SQL Injection Attempt -- index.php lcnt +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004413,rev:4,msg:'ET WEB_SPECIFIC Links Management Application SQL Injection Attempt -- index.php lcnt ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Links_Management'" +SecRule &TX:'/SQL_INJECTION.*ARGS:lcnt/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Links Management Application SQL Injection Attempt -- index.php lcnt ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006477) ET WEB_SPECIFIC LiveCMS SQL Injection Attempt -- categoria.php cid +SecRule REQUEST_URI_RAW "(?i:\/categoria\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006477,rev:4,msg:'ET WEB_SPECIFIC LiveCMS SQL Injection Attempt -- categoria.php cid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_LiveCMS'" +SecRule &TX:'/SQL_INJECTION.*ARGS:cid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC LiveCMS SQL Injection Attempt -- categoria.php cid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005833) ET WEB_SPECIFIC LocazoList SQL Injection Attempt -- main.asp subcatID +SecRule REQUEST_URI_RAW "(?i:\/main\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005833,rev:4,msg:'ET WEB_SPECIFIC LocazoList SQL Injection Attempt -- main.asp subcatID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_LocazoList'" +SecRule &TX:'/SQL_INJECTION.*ARGS:subcatID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC LocazoList SQL Injection Attempt -- main.asp subcatID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006325) ET WEB_SPECIFIC Lotfian Request For Travel SQL Injection Attempt -- ProductDetails.asp PID +SecRule REQUEST_URI_RAW "(?i:\/ProductDetails\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006325,rev:4,msg:'ET WEB_SPECIFIC Lotfian Request For Travel SQL Injection Attempt -- ProductDetails.asp PID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Lotfian'" +SecRule &TX:'/SQL_INJECTION.*ARGS:PID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Lotfian Request For Travel SQL Injection Attempt -- ProductDetails.asp PID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004965) ET WEB_SPECIFIC LushiNews SQL Injection Attempt -- comments.php id +SecRule REQUEST_URI_RAW "(?i:\/comments\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004965,rev:4,msg:'ET WEB_SPECIFIC LushiNews SQL Injection Attempt -- comments.php id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Lushi'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC LushiNews SQL Injection Attempt -- comments.php id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004971) ET WEB_SPECIFIC LushiWarPlaner SQL Injection Attempt -- register.php id +SecRule REQUEST_URI_RAW "(?i:\/register\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004971,rev:4,msg:'ET WEB_SPECIFIC LushiWarPlaner SQL Injection Attempt -- register.php id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Lushi'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC LushiWarPlaner SQL Injection Attempt -- register.php id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005139) ET WEB_SPECIFIC MAXdev MDPro SQL Injection Attempt -- index.php startrow +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005139,rev:4,msg:'ET WEB_SPECIFIC MAXdev MDPro SQL Injection Attempt -- index.php startrow ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_MDPro'" +SecRule &TX:'/SQL_INJECTION.*ARGS:startrow/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC MAXdev MDPro SQL Injection Attempt -- index.php startrow ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005516) ET WEB_SPECIFIC MGB OpenSource Guestbook SQL Injection Attempt -- email.php id +SecRule REQUEST_URI_RAW "(?i:\/email\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005516,rev:4,msg:'ET WEB_SPECIFIC MGB OpenSource Guestbook SQL Injection Attempt -- email.php id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_MGB'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC MGB OpenSource Guestbook SQL Injection Attempt -- email.php id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006229) ET WEB_SPECIFIC MGinternet Property Site Manager SQL Injection Attempt -- detail.asp p +SecRule REQUEST_URI_RAW "(?i:\/detail\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006229,rev:4,msg:'ET WEB_SPECIFIC MGinternet Property Site Manager SQL Injection Attempt -- detail.asp p ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_MGinternet'" +SecRule &TX:'/SQL_INJECTION.*ARGS:p/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC MGinternet Property Site Manager SQL Injection Attempt -- detail.asp p ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006235) ET WEB_SPECIFIC MGinternet Property Site Manager SQL Injection Attempt -- listings.asp l +SecRule REQUEST_URI_RAW "(?i:\/listings\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006235,rev:4,msg:'ET WEB_SPECIFIC MGinternet Property Site Manager SQL Injection Attempt -- listings.asp l ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_MGinternet'" +SecRule &TX:'/SQL_INJECTION.*ARGS:l/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC MGinternet Property Site Manager SQL Injection Attempt -- listings.asp l ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006241) ET WEB_SPECIFIC MGinternet Property Site Manager SQL Injection Attempt -- listings.asp typ +SecRule REQUEST_URI_RAW "(?i:\/listings\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006241,rev:4,msg:'ET WEB_SPECIFIC MGinternet Property Site Manager SQL Injection Attempt -- listings.asp typ ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_MGinternet'" +SecRule &TX:'/SQL_INJECTION.*ARGS:typ/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC MGinternet Property Site Manager SQL Injection Attempt -- listings.asp typ ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006247) ET WEB_SPECIFIC MGinternet Property Site Manager SQL Injection Attempt -- listings.asp loc +SecRule REQUEST_URI_RAW "(?i:\/listings\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006247,rev:4,msg:'ET WEB_SPECIFIC MGinternet Property Site Manager SQL Injection Attempt -- listings.asp loc ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_MGinternet'" +SecRule &TX:'/SQL_INJECTION.*ARGS:loc/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC MGinternet Property Site Manager SQL Injection Attempt -- listings.asp loc ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2003991) ET WEB_SPECIFIC Mambo SQL Injection Attempt -- index.php listid +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2003991,rev:4,msg:'ET WEB_SPECIFIC Mambo SQL Injection Attempt -- index.php listid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Mambo'" +SecRule &TX:'/SQL_INJECTION.*ARGS:listid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Mambo SQL Injection Attempt -- index.php listid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004431) ET WEB_SPECIFIC Mambo SQL Injection Attempt -- moscomment.php mcname +SecRule REQUEST_URI_RAW "(?i:\/moscomment\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004431,rev:4,msg:'ET WEB_SPECIFIC Mambo SQL Injection Attempt -- moscomment.php mcname ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Mambo'" +SecRule &TX:'/SQL_INJECTION.*ARGS:mcname/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Mambo SQL Injection Attempt -- moscomment.php mcname ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004437) ET WEB_SPECIFIC Mambo SQL Injection Attempt -- com_comment.php mcname +SecRule REQUEST_URI_RAW "(?i:\/com_comment\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004437,rev:4,msg:'ET WEB_SPECIFIC Mambo SQL Injection Attempt -- com_comment.php mcname ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Mambo'" +SecRule &TX:'/SQL_INJECTION.*ARGS:mcname/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Mambo SQL Injection Attempt -- com_comment.php mcname ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004770) ET WEB_SPECIFIC Mambo LaiThai SQL Injection Attempt -- mambo.php +SecRule REQUEST_URI_RAW "(?i:\/includes\/mambo\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004770,rev:4,msg:'ET WEB_SPECIFIC Mambo LaiThai SQL Injection Attempt -- mambo.php ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Mambo'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\(.+SELECT)" + +# (sid 2005145) ET WEB_SPECIFIC Martyn Kilbryde Newsposter Script SQL Injection Attempt -- news_page.asp uid +SecRule REQUEST_URI_RAW "(?i:\/news_page\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005145,rev:4,msg:'ET WEB_SPECIFIC Martyn Kilbryde Newsposter Script SQL Injection Attempt -- news_page.asp uid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Martyn_Kilbryde_Newsposter'" +SecRule &TX:'/SQL_INJECTION.*ARGS:uid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Martyn Kilbryde Newsposter Script SQL Injection Attempt -- news_page.asp uid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004269) ET WEB_SPECIFIC Koan Software Mega Mall SQL Injection Attempt -- product_review.php x +SecRule REQUEST_URI_RAW "(?i:\/product_review\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004269,rev:4,msg:'ET WEB_SPECIFIC Koan Software Mega Mall SQL Injection Attempt -- product_review.php x ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Mega_Mall'" +SecRule REQUEST_URI_RAW "@contains x[" "chain" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\(.+SELECT)" + +# (sid 2004275) ET WEB_SPECIFIC Koan Software Mega Mall SQL Injection Attempt -- product_review.php t +SecRule REQUEST_URI_RAW "(?i:\/product_review\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004275,rev:4,msg:'ET WEB_SPECIFIC Koan Software Mega Mall SQL Injection Attempt -- product_review.php t ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Mega_Mall'" +SecRule &TX:'/SQL_INJECTION.*ARGS:t/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Koan Software Mega Mall SQL Injection Attempt -- product_review.php t ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004281) ET WEB_SPECIFIC Koan Software Mega Mall SQL Injection Attempt -- product_review.php productId +SecRule REQUEST_URI_RAW "(?i:\/product_review\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004281,rev:4,msg:'ET WEB_SPECIFIC Koan Software Mega Mall SQL Injection Attempt -- product_review.php productId ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Mega_Mall'" +SecRule &TX:'/SQL_INJECTION.*ARGS:productId/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Koan Software Mega Mall SQL Injection Attempt -- product_review.php productId ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004287) ET WEB_SPECIFIC Koan Software Mega Mall SQL Injection Attempt -- product_review.php sk +SecRule REQUEST_URI_RAW "(?i:\/product_review\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004287,rev:4,msg:'ET WEB_SPECIFIC Koan Software Mega Mall SQL Injection Attempt -- product_review.php sk ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Mega_Mall'" +SecRule &TX:'/SQL_INJECTION.*ARGS:sk/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Koan Software Mega Mall SQL Injection Attempt -- product_review.php sk ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004293) ET WEB_SPECIFIC Koan Software Mega Mall SQL Injection Attempt -- product_review.php x +SecRule REQUEST_URI_RAW "(?i:\/product_review\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004293,rev:4,msg:'ET WEB_SPECIFIC Koan Software Mega Mall SQL Injection Attempt -- product_review.php x ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Mega_Mall'" +SecRule &TX:'/SQL_INJECTION.*ARGS:x/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Koan Software Mega Mall SQL Injection Attempt -- product_review.php x ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004299) ET WEB_SPECIFIC Koan Software Mega Mall SQL Injection Attempt -- product_review.php so +SecRule REQUEST_URI_RAW "(?i:\/product_review\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004299,rev:4,msg:'ET WEB_SPECIFIC Koan Software Mega Mall SQL Injection Attempt -- product_review.php so ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Mega_Mall'" +SecRule &TX:'/SQL_INJECTION.*ARGS:so/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Koan Software Mega Mall SQL Injection Attempt -- product_review.php so ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004305) ET WEB_SPECIFIC Koan Software Mega Mall SQL Injection Attempt -- order-track.php orderNo +SecRule REQUEST_URI_RAW "(?i:\/order\-track\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004305,rev:4,msg:'ET WEB_SPECIFIC Koan Software Mega Mall SQL Injection Attempt -- order-track.php orderNo ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Mega_Mall'" +SecRule &TX:'/SQL_INJECTION.*ARGS:orderNo/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Koan Software Mega Mall SQL Injection Attempt -- order-track.php orderNo ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006349) ET WEB_SPECIFIC Messageriescripthp SQL Injection Attempt -- lire-avis.php aa +SecRule REQUEST_URI_RAW "(?i:\/lire\-avis\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006349,rev:4,msg:'ET WEB_SPECIFIC Messageriescripthp SQL Injection Attempt -- lire-avis.php aa ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Messageriescripthp'" +SecRule &TX:'/SQL_INJECTION.*ARGS:aa/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Messageriescripthp SQL Injection Attempt -- lire-avis.php aa ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006799) ET WEB_SPECIFIC Metyus Okul Yonetim Sistemi SQL Injection Attempt -- uye_giris_islem.asp kullanici_ismi +SecRule REQUEST_URI_RAW "(?i:\/uye_giris_islem\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006799,rev:4,msg:'ET WEB_SPECIFIC Metyus Okul Yonetim Sistemi SQL Injection Attempt -- uye_giris_islem.asp kullanici_ismi ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Metyus'" +SecRule &TX:'/SQL_INJECTION.*ARGS:kullanici_ismi/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Metyus Okul Yonetim Sistemi SQL Injection Attempt -- uye_giris_islem.asp kullanici_ismi ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006805) ET WEB_SPECIFIC Metyus Okul Yonetim Sistemi SQL Injection Attempt -- uye_giris_islem.asp sifre +SecRule REQUEST_URI_RAW "(?i:\/uye_giris_islem\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006805,rev:4,msg:'ET WEB_SPECIFIC Metyus Okul Yonetim Sistemi SQL Injection Attempt -- uye_giris_islem.asp sifre ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Metyus'" +SecRule &TX:'/SQL_INJECTION.*ARGS:sifre/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Metyus Okul Yonetim Sistemi SQL Injection Attempt -- uye_giris_islem.asp sifre ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005607) ET WEB_SPECIFIC MiNT Haber Sistemi SQL Injection Attempt -- duyuru.asp id +SecRule REQUEST_URI_RAW "(?i:\/duyuru\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005607,rev:4,msg:'ET WEB_SPECIFIC MiNT Haber Sistemi SQL Injection Attempt -- duyuru.asp id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_MiNT'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC MiNT Haber Sistemi SQL Injection Attempt -- duyuru.asp id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007010) ET WEB_SPECIFIC MidiCart ASP Shopping Cart and ASP Plus Shopping Cart SQL Injection Attempt -- item_show.asp id2006quant +SecRule REQUEST_URI_RAW "(?i:\/item_show\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007010,rev:4,msg:'ET WEB_SPECIFIC MidiCart ASP Shopping Cart and ASP Plus Shopping Cart SQL Injection Attempt -- item_show.asp id2006quant ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Midicart'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id2006quant/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC MidiCart ASP Shopping Cart and ASP Plus Shopping Cart SQL Injection Attempt -- item_show.asp id2006quant ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007016) ET WEB_SPECIFIC MidiCart ASP Shopping Cart and ASP Plus Shopping Cart SQL Injection Attempt -- item_list.asp maingroup +SecRule REQUEST_URI_RAW "(?i:\/item_list\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007016,rev:4,msg:'ET WEB_SPECIFIC MidiCart ASP Shopping Cart and ASP Plus Shopping Cart SQL Injection Attempt -- item_list.asp maingroup ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Midicart'" +SecRule &TX:'/SQL_INJECTION.*ARGS:maingroup/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC MidiCart ASP Shopping Cart and ASP Plus Shopping Cart SQL Injection Attempt -- item_list.asp maingroup ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007022) ET WEB_SPECIFIC MidiCart ASP Shopping Cart and ASP Plus Shopping Cart SQL Injection Attempt -- item_list.asp secondgroup +SecRule REQUEST_URI_RAW "(?i:\/item_list\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007022,rev:4,msg:'ET WEB_SPECIFIC MidiCart ASP Shopping Cart and ASP Plus Shopping Cart SQL Injection Attempt -- item_list.asp secondgroup ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Midicart'" +SecRule &TX:'/SQL_INJECTION.*ARGS:secondgroup/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC MidiCart ASP Shopping Cart and ASP Plus Shopping Cart SQL Injection Attempt -- item_list.asp secondgroup ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004168) ET WEB_SPECIFIC Minerva mod SQL Injection Attempt -- forum.php c +SecRule REQUEST_URI_RAW "(?i:\/forum\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004168,rev:4,msg:'ET WEB_SPECIFIC Minerva mod SQL Injection Attempt -- forum.php c ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Minerva'" +SecRule &TX:'/SQL_INJECTION.*ARGS:c/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Minerva mod SQL Injection Attempt -- forum.php c ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005782) ET WEB_SPECIFIC Motionborg Web Real Estate SQL Injection Attempt -- admin_check_user.asp txtUserName +SecRule REQUEST_URI_RAW "(?i:\/admin_check_user\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005782,rev:4,msg:'ET WEB_SPECIFIC Motionborg Web Real Estate SQL Injection Attempt -- admin_check_user.asp txtUserName ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Motionborg'" +SecRule &TX:'/SQL_INJECTION.*ARGS:txtUserName/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Motionborg Web Real Estate SQL Injection Attempt -- admin_check_user.asp txtUserName ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2003839) ET WEB_SPECIFIC MyConference SQL Injection Attempt -- index.php cid +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2003839,rev:4,msg:'ET WEB_SPECIFIC MyConference SQL Injection Attempt -- index.php cid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_MyConference'" +SecRule REQUEST_URI_RAW "@contains (" "chain" +SecRule &TX:'/SQL_INJECTION.*ARGS:cid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC MyConference SQL Injection Attempt -- index.php cid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006631) ET WEB_SPECIFIC MyStats SQL Injection Attempt -- mystats.php details +SecRule REQUEST_URI_RAW "(?i:\/mystats\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006631,rev:4,msg:'ET WEB_SPECIFIC MyStats SQL Injection Attempt -- mystats.php details ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_MyStats'" +SecRule &TX:'/SQL_INJECTION.*ARGS:details/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC MyStats SQL Injection Attempt -- mystats.php details ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004616) ET WEB_SPECIFIC My Datebook SQL Injection Attempt -- diary.php delete +SecRule REQUEST_URI_RAW "(?i:\/diary\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004616,rev:4,msg:'ET WEB_SPECIFIC My Datebook SQL Injection Attempt -- diary.php delete ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_My_Datebook'" +SecRule &TX:'/SQL_INJECTION.*ARGS:delete/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC My Datebook SQL Injection Attempt -- diary.php delete ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004099) ET WEB_SPECIFIC My Little Forum SQL Injection Attempt -- user.php id +SecRule REQUEST_URI_RAW "(?i:\/user\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004099,rev:4,msg:'ET WEB_SPECIFIC My Little Forum SQL Injection Attempt -- user.php id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_My_Little_Forum'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC My Little Forum SQL Injection Attempt -- user.php id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004746) ET WEB_SPECIFIC Nabopoll SQL Injection Attempt -- result.php surv +SecRule REQUEST_URI_RAW "(?i:\/result\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004746,rev:4,msg:'ET WEB_SPECIFIC Nabopoll SQL Injection Attempt -- result.php surv ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Nabopoll'" +SecRule &TX:'/SQL_INJECTION.*ARGS:surv/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Nabopoll SQL Injection Attempt -- result.php surv ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006884) ET WEB_SPECIFIC Neocrome Land Down Under (LDU) SQL Injection Attempt -- users.php id +SecRule REQUEST_URI_RAW "(?i:\/users\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006884,rev:4,msg:'ET WEB_SPECIFIC Neocrome Land Down Under (LDU) SQL Injection Attempt -- users.php id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Neochrome'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Neocrome Land Down Under (LDU) SQL Injection Attempt -- users.php id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006740) ET WEB_SPECIFIC Neocrome Seditio SQL Injection Attempt -- ipsearch.admin.php +SecRule REQUEST_URI_RAW "(?i:\/plugins\/ipsearch\/ipsearch\.admin\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006740,rev:4,msg:'ET WEB_SPECIFIC Neocrome Seditio SQL Injection Attempt -- ipsearch.admin.php ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Neocrome'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:.+\(.+SELECT)" + +# (sid 2006746) ET WEB_SPECIFIC Neocrome Seditio SQL Injection Attempt -- pfs.edit.inc.php +SecRule REQUEST_URI_RAW "(?i:\/pfs\/pfs\.edit\.inc\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006746,rev:4,msg:'ET WEB_SPECIFIC Neocrome Seditio SQL Injection Attempt -- pfs.edit.inc.php ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Neocrome'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:.+\(.+SELECT)" + +# (sid 2006752) ET WEB_SPECIFIC Neocrome Seditio SQL Injection Attempt -- users.register.inc.php +SecRule REQUEST_URI_RAW "(?i:\/system\/core\/users\/users\.register\.inc\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006752,rev:4,msg:'ET WEB_SPECIFIC Neocrome Seditio SQL Injection Attempt -- users.register.inc.php ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Neocrome'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:.+\(.+SELECT)" + +# (sid 2006758) ET WEB_SPECIFIC Neocrome Seditio SQL Injection Attempt -- polls.php id +SecRule REQUEST_URI_RAW "(?i:\/polls\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006758,rev:4,msg:'ET WEB_SPECIFIC Neocrome Seditio SQL Injection Attempt -- polls.php id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Neocrome'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Neocrome Seditio SQL Injection Attempt -- polls.php id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007292) ET WEB_SPECIFIC Neocrome Seditio SQL Injection Attempt -- users.php id +SecRule REQUEST_URI_RAW "(?i:\/users\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007292,rev:3,msg:'ET WEB_SPECIFIC Neocrome Seditio SQL Injection Attempt -- users.php id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Neocrome'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Neocrome Seditio SQL Injection Attempt -- users.php id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006551) ET WEB_SPECIFIC NetClassifieds Premium Edition SQL Injection Attempt -- ViewCat.php s_user_id +SecRule REQUEST_URI_RAW "(?i:\/ViewCat\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006551,rev:4,msg:'ET WEB_SPECIFIC NetClassifieds Premium Edition SQL Injection Attempt -- ViewCat.php s_user_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_NetClassifieds'" +SecRule &TX:'/SQL_INJECTION.*ARGS:s_user_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC NetClassifieds Premium Edition SQL Injection Attempt -- ViewCat.php s_user_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004162) ET WEB_SPECIFIC NetVIOS Portal SQL Injection Attempt -- page.asp NewsID +SecRule REQUEST_URI_RAW "(?i:\/News\/page\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004162,rev:4,msg:'ET WEB_SPECIFIC NetVIOS Portal SQL Injection Attempt -- page.asp NewsID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_NetVIOS'" +SecRule &TX:'/SQL_INJECTION.*ARGS:NewsID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC NetVIOS Portal SQL Injection Attempt -- page.asp NewsID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004940) ET WEB_SPECIFIC Neuron Blog SQL Injection Attempt -- addcomment2.php commentname +SecRule REQUEST_URI_RAW "(?i:\/pages\/addcomment2\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004940,rev:4,msg:'ET WEB_SPECIFIC Neuron Blog SQL Injection Attempt -- addcomment2.php commentname ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Neuron_Blog'" +SecRule &TX:'/SQL_INJECTION.*ARGS:commentname/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Neuron Blog SQL Injection Attempt -- addcomment2.php commentname ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004947) ET WEB_SPECIFIC Neuron Blog SQL Injection Attempt -- addcomment2.php commentmail +SecRule REQUEST_URI_RAW "(?i:\/pages\/addcomment2\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004947,rev:4,msg:'ET WEB_SPECIFIC Neuron Blog SQL Injection Attempt -- addcomment2.php commentmail ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Neuron_Blog'" +SecRule &TX:'/SQL_INJECTION.*ARGS:commentmail/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Neuron Blog SQL Injection Attempt -- addcomment2.php commentmail ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004953) ET WEB_SPECIFIC Neuron Blog SQL Injection Attempt -- addcomment2.php commentwebsite +SecRule REQUEST_URI_RAW "(?i:\/pages\/addcomment2\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004953,rev:4,msg:'ET WEB_SPECIFIC Neuron Blog SQL Injection Attempt -- addcomment2.php commentwebsite ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Neuron_Blog'" +SecRule &TX:'/SQL_INJECTION.*ARGS:commentwebsite/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Neuron Blog SQL Injection Attempt -- addcomment2.php commentwebsite ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004959) ET WEB_SPECIFIC Neuron Blog SQL Injection Attempt -- addcomment2.php comment +SecRule REQUEST_URI_RAW "(?i:\/pages\/addcomment2\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004959,rev:4,msg:'ET WEB_SPECIFIC Neuron Blog SQL Injection Attempt -- addcomment2.php comment ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Neuron_Blog'" +SecRule &TX:'/SQL_INJECTION.*ARGS:comment/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Neuron Blog SQL Injection Attempt -- addcomment2.php comment ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005679) ET WEB_SPECIFIC Nicola Asuni All In One Control Panel (AIOCP) SQL Injection Attempt -- cp_functions_downloads.php download_category +SecRule REQUEST_URI_RAW "(?i:\/shared\/code\/cp_functions_downloads\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005679,rev:4,msg:'ET WEB_SPECIFIC Nicola Asuni All In One Control Panel (AIOCP) SQL Injection Attempt -- cp_functions_downloads.php download_category ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Nicola_Asuni'" +SecRule &TX:'/SQL_INJECTION.*ARGS:download_category/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Nicola Asuni All In One Control Panel (AIOCP) SQL Injection Attempt -- cp_functions_downloads.php download_category ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005019) ET WEB_SPECIFIC Noname Media Photo Galerie Standard SQL Injection Attempt -- view.php id +SecRule REQUEST_URI_RAW "(?i:\/view\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005019,rev:4,msg:'ET WEB_SPECIFIC Noname Media Photo Galerie Standard SQL Injection Attempt -- view.php id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Noname_Media_Gallerie'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Noname Media Photo Galerie Standard SQL Injection Attempt -- view.php id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006595) ET WEB_SPECIFIC Novell ZENworks Patch Management (ZPM) SQL Injection Attempt -- downloadreport.asp agentid +SecRule REQUEST_URI_RAW "(?i:\/dagent\/downloadreport\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006595,rev:4,msg:'ET WEB_SPECIFIC Novell ZENworks Patch Management (ZPM) SQL Injection Attempt -- downloadreport.asp agentid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Novell_Zenworks'" +SecRule &TX:'/SQL_INJECTION.*ARGS:agentid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Novell ZENworks Patch Management (ZPM) SQL Injection Attempt -- downloadreport.asp agentid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006601) ET WEB_SPECIFIC Novell ZENworks Patch Management (ZPM) SQL Injection Attempt -- downloadreport.asp pass +SecRule REQUEST_URI_RAW "(?i:\/dagent\/downloadreport\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006601,rev:4,msg:'ET WEB_SPECIFIC Novell ZENworks Patch Management (ZPM) SQL Injection Attempt -- downloadreport.asp pass ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Novell_Zenworks'" +SecRule &TX:'/SQL_INJECTION.*ARGS:pass/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Novell ZENworks Patch Management (ZPM) SQL Injection Attempt -- downloadreport.asp pass ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004311) ET WEB_SPECIFIC NukeSentinel SQL Injection Attempt -- nukesentinel.php +SecRule REQUEST_URI_RAW "(?i:\/nukesentinel\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004311,rev:4,msg:'ET WEB_SPECIFIC NukeSentinel SQL Injection Attempt -- nukesentinel.php ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_NukeSentinel'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\(.+SELECT)" + +# (sid 2004734) ET WEB_SPECIFIC NukeSentinel SQL Injection Attempt -- nukesentinel.php +SecRule REQUEST_URI_RAW "(?i:\/nukesentinel\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004734,rev:4,msg:'ET WEB_SPECIFIC NukeSentinel SQL Injection Attempt -- nukesentinel.php ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_NukeSentinel'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\(.+SELECT)" + +# (sid 2004740) ET WEB_SPECIFIC NukeSentinel SQL Injection Attempt -- nsbypass.php +SecRule REQUEST_URI_RAW "(?i:\/includes\/nsbypass\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004740,rev:4,msg:'ET WEB_SPECIFIC NukeSentinel SQL Injection Attempt -- nsbypass.php ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_NukeSentinel'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\(.+SELECT)" + +# (sid 2006811) ET WEB_SPECIFIC Oxygen (O2PHP Bulletin Board) SQL Injection Attempt -- viewthread.php pid +SecRule REQUEST_URI_RAW "(?i:\/viewthread\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006811,rev:4,msg:'ET WEB_SPECIFIC Oxygen (O2PHP Bulletin Board) SQL Injection Attempt -- viewthread.php pid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_O2PHP'" +SecRule &TX:'/SQL_INJECTION.*ARGS:pid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Oxygen (O2PHP Bulletin Board) SQL Injection Attempt -- viewthread.php pid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005601) ET WEB_SPECIFIC Okul Web Otomasyon Sistemi SQL Injection Attempt -- etkinlikbak.asp id +SecRule REQUEST_URI_RAW "(?i:\/etkinlikbak\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005601,rev:4,msg:'ET WEB_SPECIFIC Okul Web Otomasyon Sistemi SQL Injection Attempt -- etkinlikbak.asp id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Okul'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Okul Web Otomasyon Sistemi SQL Injection Attempt -- etkinlikbak.asp id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004454) ET WEB_SPECIFIC Omegasoft SQL Injection Attempt -- OmegaMw7.asp +SecRule REQUEST_URI_RAW "(?i:\/OmegaMw7\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004454,rev:4,msg:'ET WEB_SPECIFIC Omegasoft SQL Injection Attempt -- OmegaMw7.asp ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Omegasoft'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\(.+SELECT)" + +# (sid 2004849) ET WEB_SPECIFIC Online Web Building SQL Injection Attempt -- page.asp art_id +SecRule REQUEST_URI_RAW "(?i:\/user_pages\/page\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004849,rev:4,msg:'ET WEB_SPECIFIC Online Web Building SQL Injection Attempt -- page.asp art_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Online_Web_Building'" +SecRule &TX:'/SQL_INJECTION.*ARGS:art_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Online Web Building SQL Injection Attempt -- page.asp art_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005941) ET WEB_SPECIFIC Outfront Spooky Login SQL Injection Attempt -- register.asp UserUpdate +SecRule REQUEST_URI_RAW "(?i:\/login\/register\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005941,rev:4,msg:'ET WEB_SPECIFIC Outfront Spooky Login SQL Injection Attempt -- register.asp UserUpdate ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Outfront'" +SecRule &TX:'/SQL_INJECTION.*ARGS:UserUpdate/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Outfront Spooky Login SQL Injection Attempt -- register.asp UserUpdate ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005947) ET WEB_SPECIFIC Outfront Spooky Login SQL Injection Attempt -- a_register.asp +SecRule REQUEST_URI_RAW "(?i:\/includes\/a_register\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005947,rev:4,msg:'ET WEB_SPECIFIC Outfront Spooky Login SQL Injection Attempt -- a_register.asp ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Outfront'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\(.+SELECT)" + +# (sid 2004245) ET WEB_SPECIFIC PHP-Stats SQL Injection Attempt -- php-stats.recphp.php ip +SecRule REQUEST_URI_RAW "(?i:\/php\-stats\.recphp\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004245,rev:4,msg:'ET WEB_SPECIFIC PHP-Stats SQL Injection Attempt -- php-stats.recphp.php ip ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_PHP-Stats'" +SecRule &TX:'/SQL_INJECTION.*ARGS:ip/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC PHP-Stats SQL Injection Attempt -- php-stats.recphp.php ip ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006514) ET WEB_SPECIFIC PHPAccounts SQL Injection Attempt -- index.php Outgoing_Type_ID +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006514,rev:4,msg:'ET WEB_SPECIFIC PHPAccounts SQL Injection Attempt -- index.php Outgoing_Type_ID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_PHPAccounts'" +SecRule &TX:'/SQL_INJECTION.*ARGS:Outgoing_Type_ID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC PHPAccounts SQL Injection Attempt -- index.php Outgoing_Type_ID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006520) ET WEB_SPECIFIC PHPAccounts SQL Injection Attempt -- index.php Outgoing_ID +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006520,rev:4,msg:'ET WEB_SPECIFIC PHPAccounts SQL Injection Attempt -- index.php Outgoing_ID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_PHPAccounts'" +SecRule &TX:'/SQL_INJECTION.*ARGS:Outgoing_ID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC PHPAccounts SQL Injection Attempt -- index.php Outgoing_ID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006526) ET WEB_SPECIFIC PHPAccounts SQL Injection Attempt -- index.php Project_ID +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006526,rev:4,msg:'ET WEB_SPECIFIC PHPAccounts SQL Injection Attempt -- index.php Project_ID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_PHPAccounts'" +SecRule &TX:'/SQL_INJECTION.*ARGS:Project_ID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC PHPAccounts SQL Injection Attempt -- index.php Project_ID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006532) ET WEB_SPECIFIC PHPAccounts SQL Injection Attempt -- index.php Client_ID +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006532,rev:4,msg:'ET WEB_SPECIFIC PHPAccounts SQL Injection Attempt -- index.php Client_ID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_PHPAccounts'" +SecRule &TX:'/SQL_INJECTION.*ARGS:Client_ID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC PHPAccounts SQL Injection Attempt -- index.php Client_ID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006538) ET WEB_SPECIFIC PHPAccounts SQL Injection Attempt -- index.php Invoice_ID +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006538,rev:4,msg:'ET WEB_SPECIFIC PHPAccounts SQL Injection Attempt -- index.php Invoice_ID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_PHPAccounts'" +SecRule &TX:'/SQL_INJECTION.*ARGS:Invoice_ID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC PHPAccounts SQL Injection Attempt -- index.php Invoice_ID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006544) ET WEB_SPECIFIC PHPAccounts SQL Injection Attempt -- index.php Vendor_ID +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006544,rev:4,msg:'ET WEB_SPECIFIC PHPAccounts SQL Injection Attempt -- index.php Vendor_ID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_PHPAccounts'" +SecRule &TX:'/SQL_INJECTION.*ARGS:Vendor_ID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC PHPAccounts SQL Injection Attempt -- index.php Vendor_ID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005971) ET WEB_SPECIFIC phpBB2 Plus SQL Injection Attempt -- admin_acronyms.php id +SecRule REQUEST_URI_RAW "(?i:\/admin\/admin_acronyms\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005971,rev:4,msg:'ET WEB_SPECIFIC phpBB2 Plus SQL Injection Attempt -- admin_acronyms.php id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_PHPBB'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC phpBB2 Plus SQL Injection Attempt -- admin_acronyms.php id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006973) ET WEB_SPECIFIC phpBB SQL Injection Attempt -- admin_hacks_list.php hack_id +SecRule REQUEST_URI_RAW "(?i:\/admin_hacks_list\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006973,rev:4,msg:'ET WEB_SPECIFIC phpBB SQL Injection Attempt -- admin_hacks_list.php hack_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_PHPBB'" +SecRule &TX:'/SQL_INJECTION.*ARGS:hack_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC phpBB SQL Injection Attempt -- admin_hacks_list.php hack_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004045) ET WEB_SPECIFIC PHPEcho CMS SQL Injection Attempt -- gallery.php id +SecRule REQUEST_URI_RAW "(?i:\/modules\/admin\/modules\/gallery\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004045,rev:4,msg:'ET WEB_SPECIFIC PHPEcho CMS SQL Injection Attempt -- gallery.php id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_PHPEcho'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC PHPEcho CMS SQL Injection Attempt -- gallery.php id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2003809) ET WEB_SPECIFIC phpHoo3 SQL Injection Attempt -- admin.php ADMIN_USER +SecRule REQUEST_URI_RAW "(?i:\/admin\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2003809,rev:4,msg:'ET WEB_SPECIFIC phpHoo3 SQL Injection Attempt -- admin.php ADMIN_USER ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_PHPHoo3'" +SecRule REQUEST_URI_RAW "@contains (" "chain" +SecRule &TX:'/SQL_INJECTION.*ARGS:ADMIN_USER/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC phpHoo3 SQL Injection Attempt -- admin.php ADMIN_USER ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2003815) ET WEB_SPECIFIC phpHoo3 SQL Injection Attempt -- admin.php ADMIN_PASS +SecRule REQUEST_URI_RAW "(?i:\/admin\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2003815,rev:4,msg:'ET WEB_SPECIFIC phpHoo3 SQL Injection Attempt -- admin.php ADMIN_PASS ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_PHPHoo3'" +SecRule REQUEST_URI_RAW "@contains (" "chain" +SecRule &TX:'/SQL_INJECTION.*ARGS:ADMIN_PASS/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC phpHoo3 SQL Injection Attempt -- admin.php ADMIN_PASS ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004699) ET WEB_SPECIFIC PHPKit SQL Injection Attempt -- include.php catid +SecRule REQUEST_URI_RAW "(?i:\/include\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004699,rev:4,msg:'ET WEB_SPECIFIC PHPKit SQL Injection Attempt -- include.php catid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_PHPKit'" +SecRule &TX:'/SQL_INJECTION.*ARGS:catid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC PHPKit SQL Injection Attempt -- include.php catid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005788) ET WEB_SPECIFIC PHPKIT SQL Injection Attempt -- comment.php subid +SecRule REQUEST_URI_RAW "(?i:\/comment\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005788,rev:4,msg:'ET WEB_SPECIFIC PHPKIT SQL Injection Attempt -- comment.php subid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_PHPKit'" +SecRule &TX:'/SQL_INJECTION.*ARGS:subid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC PHPKIT SQL Injection Attempt -- comment.php subid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004704) ET WEB_SPECIFIC PHPWind SQL Injection Attempt -- admin.php +SecRule REQUEST_URI_RAW "(?i:\/admin\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004704,rev:4,msg:'ET WEB_SPECIFIC PHPWind SQL Injection Attempt -- admin.php ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_PHPWind'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\(.+SELECT)" + +# (sid 2004329) ET WEB_SPECIFIC PHP-Nuke SQL Injection Attempt -- mainfile.php lang +SecRule REQUEST_URI_RAW "(?i:\/mainfile\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004329,rev:4,msg:'ET WEB_SPECIFIC PHP-Nuke SQL Injection Attempt -- mainfile.php lang ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_PHP_Nuke'" +SecRule &TX:'/SQL_INJECTION.*ARGS:lang/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC PHP-Nuke SQL Injection Attempt -- mainfile.php lang ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004855) ET WEB_SPECIFIC PHP-Nuke SQL Injection Attempt -- modules.php category_id +SecRule REQUEST_URI_RAW "(?i:\/modules\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004855,rev:4,msg:'ET WEB_SPECIFIC PHP-Nuke SQL Injection Attempt -- modules.php category_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_PHP_Nuke'" +SecRule &TX:'/SQL_INJECTION.*ARGS:category_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC PHP-Nuke SQL Injection Attempt -- modules.php category_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005460) ET WEB_SPECIFIC Francisco Burzi PHP-Nuke SQL Injection Attempt -- modules.php active +SecRule REQUEST_URI_RAW "(?i:\/admin\/modules\/modules\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005460,rev:4,msg:'ET WEB_SPECIFIC Francisco Burzi PHP-Nuke SQL Injection Attempt -- modules.php active ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_PHP_Nuke'" +SecRule &TX:'/SQL_INJECTION.*ARGS:active/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Francisco Burzi PHP-Nuke SQL Injection Attempt -- modules.php active ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005466) ET WEB_SPECIFIC Francisco Burzi PHP-Nuke SQL Injection Attempt -- index.php ad_class +SecRule REQUEST_URI_RAW "(?i:\/modules\/Advertising\/admin\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005466,rev:4,msg:'ET WEB_SPECIFIC Francisco Burzi PHP-Nuke SQL Injection Attempt -- index.php ad_class ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_PHP_Nuke'" +SecRule &TX:'/SQL_INJECTION.*ARGS:ad_class/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Francisco Burzi PHP-Nuke SQL Injection Attempt -- index.php ad_class ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005472) ET WEB_SPECIFIC Francisco Burzi PHP-Nuke SQL Injection Attempt -- index.php imageurl +SecRule REQUEST_URI_RAW "(?i:\/modules\/Advertising\/admin\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005472,rev:4,msg:'ET WEB_SPECIFIC Francisco Burzi PHP-Nuke SQL Injection Attempt -- index.php imageurl ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_PHP_Nuke'" +SecRule &TX:'/SQL_INJECTION.*ARGS:imageurl/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Francisco Burzi PHP-Nuke SQL Injection Attempt -- index.php imageurl ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005478) ET WEB_SPECIFIC Francisco Burzi PHP-Nuke SQL Injection Attempt -- index.php clickurl +SecRule REQUEST_URI_RAW "(?i:\/modules\/Advertising\/admin\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005478,rev:4,msg:'ET WEB_SPECIFIC Francisco Burzi PHP-Nuke SQL Injection Attempt -- index.php clickurl ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_PHP_Nuke'" +SecRule &TX:'/SQL_INJECTION.*ARGS:clickurl/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Francisco Burzi PHP-Nuke SQL Injection Attempt -- index.php clickurl ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005484) ET WEB_SPECIFIC Francisco Burzi PHP-Nuke SQL Injection Attempt -- index.php ad_code +SecRule REQUEST_URI_RAW "(?i:\/modules\/Advertising\/admin\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005484,rev:4,msg:'ET WEB_SPECIFIC Francisco Burzi PHP-Nuke SQL Injection Attempt -- index.php ad_code ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_PHP_Nuke'" +SecRule &TX:'/SQL_INJECTION.*ARGS:ad_code/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Francisco Burzi PHP-Nuke SQL Injection Attempt -- index.php ad_code ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005491) ET WEB_SPECIFIC Francisco Burzi PHP-Nuke SQL Injection Attempt -- index.php position +SecRule REQUEST_URI_RAW "(?i:\/modules\/Advertising\/admin\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005491,rev:4,msg:'ET WEB_SPECIFIC Francisco Burzi PHP-Nuke SQL Injection Attempt -- index.php position ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_PHP_Nuke'" +SecRule &TX:'/SQL_INJECTION.*ARGS:position/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Francisco Burzi PHP-Nuke SQL Injection Attempt -- index.php position ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005589) ET WEB_SPECIFIC Francisco Burzi PHP-Nuke SQL Injection Attempt -- block-Old_Articles.php cat +SecRule REQUEST_URI_RAW "(?i:\/blocks\/block\-Old_Articles\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005589,rev:4,msg:'ET WEB_SPECIFIC Francisco Burzi PHP-Nuke SQL Injection Attempt -- block-Old_Articles.php cat ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_PHP_Nuke'" +SecRule &TX:'/SQL_INJECTION.*ARGS:cat/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Francisco Burzi PHP-Nuke SQL Injection Attempt -- block-Old_Articles.php cat ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006931) ET WEB_SPECIFIC PHP-Nuke SQL Injection Attempt -- modules.php cid +SecRule REQUEST_URI_RAW "(?i:\/modules\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006931,rev:4,msg:'ET WEB_SPECIFIC PHP-Nuke SQL Injection Attempt -- modules.php cid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_PHP_Nuke'" +SecRule &TX:'/SQL_INJECTION.*ARGS:cid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC PHP-Nuke SQL Injection Attempt -- modules.php cid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006937) ET WEB_SPECIFIC PHP-Nuke SQL Injection Attempt -- modules.php pid +SecRule REQUEST_URI_RAW "(?i:\/modules\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006937,rev:4,msg:'ET WEB_SPECIFIC PHP-Nuke SQL Injection Attempt -- modules.php pid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_PHP_Nuke'" +SecRule &TX:'/SQL_INJECTION.*ARGS:pid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC PHP-Nuke SQL Injection Attempt -- modules.php pid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007180) ET WEB_SPECIFIC Francisco Burzi PHP-Nuke SQL Injection Attempt -- index.php sid +SecRule REQUEST_URI_RAW "(?i:\/modules\/News\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007180,rev:3,msg:'ET WEB_SPECIFIC Francisco Burzi PHP-Nuke SQL Injection Attempt -- index.php sid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_PHP_Nuke'" +SecRule &TX:'/SQL_INJECTION.*ARGS:sid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Francisco Burzi PHP-Nuke SQL Injection Attempt -- index.php sid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005905) ET WEB_SPECIFIC PHP-Update SQL Injection Attempt -- guestadd.php newmessage +SecRule REQUEST_URI_RAW "(?i:\/code\/guestadd\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005905,rev:4,msg:'ET WEB_SPECIFIC PHP-Update SQL Injection Attempt -- guestadd.php newmessage ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_PHP_Update'" +SecRule &TX:'/SQL_INJECTION.*ARGS:newmessage/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC PHP-Update SQL Injection Attempt -- guestadd.php newmessage ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005911) ET WEB_SPECIFIC PHP-Update SQL Injection Attempt -- guestadd.php newname +SecRule REQUEST_URI_RAW "(?i:\/code\/guestadd\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005911,rev:4,msg:'ET WEB_SPECIFIC PHP-Update SQL Injection Attempt -- guestadd.php newname ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_PHP_Update'" +SecRule &TX:'/SQL_INJECTION.*ARGS:newname/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC PHP-Update SQL Injection Attempt -- guestadd.php newname ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005917) ET WEB_SPECIFIC PHP-Update SQL Injection Attempt -- guestadd.php newwebsite +SecRule REQUEST_URI_RAW "(?i:\/code\/guestadd\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005917,rev:4,msg:'ET WEB_SPECIFIC PHP-Update SQL Injection Attempt -- guestadd.php newwebsite ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_PHP_Update'" +SecRule &TX:'/SQL_INJECTION.*ARGS:newwebsite/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC PHP-Update SQL Injection Attempt -- guestadd.php newwebsite ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005923) ET WEB_SPECIFIC PHP-Update SQL Injection Attempt -- guestadd.php newemail +SecRule REQUEST_URI_RAW "(?i:\/code\/guestadd\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005923,rev:4,msg:'ET WEB_SPECIFIC PHP-Update SQL Injection Attempt -- guestadd.php newemail ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_PHP_Update'" +SecRule &TX:'/SQL_INJECTION.*ARGS:newemail/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC PHP-Update SQL Injection Attempt -- guestadd.php newemail ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004610) ET WEB_SPECIFIC PNphpBB2 SQL Injection Attempt -- index.php c +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004610,rev:4,msg:'ET WEB_SPECIFIC PNphpBB2 SQL Injection Attempt -- index.php c ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_PNphpBB2'" +SecRule &TX:'/SQL_INJECTION.*ARGS:c/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC PNphpBB2 SQL Injection Attempt -- index.php c ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004934) ET WEB_SPECIFIC PSY Auction SQL Injection Attempt -- item.php id +SecRule REQUEST_URI_RAW "(?i:\/item\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004934,rev:4,msg:'ET WEB_SPECIFIC PSY Auction SQL Injection Attempt -- item.php id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_PSY_Auction'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC PSY Auction SQL Injection Attempt -- item.php id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006734) ET WEB_SPECIFIC PWP Technologies The Classified Ad System SQL Injection Attempt -- default.asp main +SecRule REQUEST_URI_RAW "(?i:\/default\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006734,rev:4,msg:'ET WEB_SPECIFIC PWP Technologies The Classified Ad System SQL Injection Attempt -- default.asp main ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_PWP'" +SecRule &TX:'/SQL_INJECTION.*ARGS:main/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC PWP Technologies The Classified Ad System SQL Injection Attempt -- default.asp main ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004263) ET WEB_SPECIFIC Particle Blogger SQL Injection Attempt -- post.php postid +SecRule REQUEST_URI_RAW "(?i:\/post\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004263,rev:4,msg:'ET WEB_SPECIFIC Particle Blogger SQL Injection Attempt -- post.php postid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Particle_Blogger'" +SecRule &TX:'/SQL_INJECTION.*ARGS:postid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Particle Blogger SQL Injection Attempt -- post.php postid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005220) ET WEB_SPECIFIC Particle Blogger SQL Injection Attempt -- archives.php month +SecRule REQUEST_URI_RAW "(?i:\/archives\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005220,rev:4,msg:'ET WEB_SPECIFIC Particle Blogger SQL Injection Attempt -- archives.php month ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Particle_Blogger'" +SecRule &TX:'/SQL_INJECTION.*ARGS:month/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Particle Blogger SQL Injection Attempt -- archives.php month ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004622) ET WEB_SPECIFIC Particle Soft Particle Gallery SQL Injection Attempt -- viewimage.php editcomment +SecRule REQUEST_URI_RAW "(?i:\/viewimage\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004622,rev:4,msg:'ET WEB_SPECIFIC Particle Soft Particle Gallery SQL Injection Attempt -- viewimage.php editcomment ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Particle_Gallery'" +SecRule &TX:'/SQL_INJECTION.*ARGS:editcomment/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Particle Soft Particle Gallery SQL Injection Attempt -- viewimage.php editcomment ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004093) ET WEB_SPECIFIC Phil-a-Form SQL Injection Attempt -- index.php form_id +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004093,rev:4,msg:'ET WEB_SPECIFIC Phil-a-Form SQL Injection Attempt -- index.php form_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Phil-A-Form'" +SecRule &TX:'/SQL_INJECTION.*ARGS:form_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Phil-a-Form SQL Injection Attempt -- index.php form_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004928) ET WEB_SPECIFIC Philboard SQL Injection Attempt -- philboard_forum.asp forumid +SecRule REQUEST_URI_RAW "(?i:\/philboard_forum\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004928,rev:4,msg:'ET WEB_SPECIFIC Philboard SQL Injection Attempt -- philboard_forum.asp forumid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Philboard'" +SecRule &TX:'/SQL_INJECTION.*ARGS:forumid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Philboard SQL Injection Attempt -- philboard_forum.asp forumid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004909) ET WEB_SPECIFIC PollMentor SQL Injection Attempt -- pollmentorres.asp id +SecRule REQUEST_URI_RAW "(?i:\/pollmentorres\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004909,rev:4,msg:'ET WEB_SPECIFIC PollMentor SQL Injection Attempt -- pollmentorres.asp id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_PollMentor'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC PollMentor SQL Injection Attempt -- pollmentorres.asp id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005625) ET WEB_SPECIFIC Portix-PHP SQL Injection Attempt -- archive.php blogid +SecRule REQUEST_URI_RAW "(?i:\/simplog\/archive\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005625,rev:4,msg:'ET WEB_SPECIFIC Portix-PHP SQL Injection Attempt -- archive.php blogid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Portix'" +SecRule &TX:'/SQL_INJECTION.*ARGS:blogid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Portix-PHP SQL Injection Attempt -- archive.php blogid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005631) ET WEB_SPECIFIC Portix-PHP SQL Injection Attempt -- archive.php pid +SecRule REQUEST_URI_RAW "(?i:\/simplog\/archive\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005631,rev:4,msg:'ET WEB_SPECIFIC Portix-PHP SQL Injection Attempt -- archive.php pid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Portix'" +SecRule &TX:'/SQL_INJECTION.*ARGS:pid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Portix-PHP SQL Injection Attempt -- archive.php pid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005637) ET WEB_SPECIFIC Portix-PHP SQL Injection Attempt -- index.php blogid +SecRule REQUEST_URI_RAW "(?i:\/simplog\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005637,rev:4,msg:'ET WEB_SPECIFIC Portix-PHP SQL Injection Attempt -- index.php blogid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Portix'" +SecRule &TX:'/SQL_INJECTION.*ARGS:blogid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Portix-PHP SQL Injection Attempt -- index.php blogid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2003803) ET WEB_SPECIFIC v4bJournal module PostNuke SQL Injection Attempt -- index.php id +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2003803,rev:4,msg:'ET WEB_SPECIFIC v4bJournal module PostNuke SQL Injection Attempt -- index.php id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_PostNuke'" +SecRule REQUEST_URI_RAW "@contains (" "chain" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC v4bJournal module PostNuke SQL Injection Attempt -- index.php id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006355) ET WEB_SPECIFIC ProNews SQL Injection Attempt -- lire-avis.php aa +SecRule REQUEST_URI_RAW "(?i:\/lire\-avis\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006355,rev:4,msg:'ET WEB_SPECIFIC ProNews SQL Injection Attempt -- lire-avis.php aa ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_ProNews'" +SecRule &TX:'/SQL_INJECTION.*ARGS:aa/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC ProNews SQL Injection Attempt -- lire-avis.php aa ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005685) ET WEB_SPECIFIC Rapid Classified SQL Injection Attempt -- viewad.asp id +SecRule REQUEST_URI_RAW "(?i:\/viewad\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005685,rev:4,msg:'ET WEB_SPECIFIC Rapid Classified SQL Injection Attempt -- viewad.asp id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Rapid_Classified'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Rapid Classified SQL Injection Attempt -- viewad.asp id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005025) ET WEB_SPECIFIC Raymond BERTHOU script SQL Injection Attempt -- login.asp user +SecRule REQUEST_URI_RAW "(?i:\/login\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005025,rev:4,msg:'ET WEB_SPECIFIC Raymond BERTHOU script SQL Injection Attempt -- login.asp user ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Raymond_Berthou'" +SecRule &TX:'/SQL_INJECTION.*ARGS:user/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Raymond BERTHOU script SQL Injection Attempt -- login.asp user ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005031) ET WEB_SPECIFIC Raymond BERTHOU script SQL Injection Attempt -- login.asp password +SecRule REQUEST_URI_RAW "(?i:\/login\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005031,rev:4,msg:'ET WEB_SPECIFIC Raymond BERTHOU script SQL Injection Attempt -- login.asp password ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Raymond_Berthou'" +SecRule &TX:'/SQL_INJECTION.*ARGS:password/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Raymond BERTHOU script SQL Injection Attempt -- login.asp password ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005097) ET WEB_SPECIFIC Raymond BERTHOU script SQL Injection Attempt -- user_confirm.asp id +SecRule REQUEST_URI_RAW "(?i:\/user_confirm\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005097,rev:4,msg:'ET WEB_SPECIFIC Raymond BERTHOU script SQL Injection Attempt -- user_confirm.asp id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Raymond_Berthou'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Raymond BERTHOU script SQL Injection Attempt -- user_confirm.asp id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005103) ET WEB_SPECIFIC Raymond BERTHOU script SQL Injection Attempt -- user_confirm.asp pass +SecRule REQUEST_URI_RAW "(?i:\/user_confirm\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005103,rev:4,msg:'ET WEB_SPECIFIC Raymond BERTHOU script SQL Injection Attempt -- user_confirm.asp pass ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Raymond_Berthou'" +SecRule &TX:'/SQL_INJECTION.*ARGS:pass/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Raymond BERTHOU script SQL Injection Attempt -- user_confirm.asp pass ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006943) ET WEB_SPECIFIC Recipes Complete Website SQL Injection Attempt -- recipe.php recipeid +SecRule REQUEST_URI_RAW "(?i:\/recipe\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006943,rev:3,msg:'ET WEB_SPECIFIC Recipes Complete Website SQL Injection Attempt -- recipe.php recipeid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Recipes_Complete'" +SecRule &TX:'/SQL_INJECTION.*ARGS:recipeid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Recipes Complete Website SQL Injection Attempt -- recipe.php recipeid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006949) ET WEB_SPECIFIC Recipes Complete Website SQL Injection Attempt -- list.php categoryid +SecRule REQUEST_URI_RAW "(?i:\/list\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006949,rev:3,msg:'ET WEB_SPECIFIC Recipes Complete Website SQL Injection Attempt -- list.php categoryid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Recipes_Complete'" +SecRule &TX:'/SQL_INJECTION.*ARGS:categoryid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Recipes Complete Website SQL Injection Attempt -- list.php categoryid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2003833) ET WEB_SPECIFIC ResManager SQL Injection Attempt -- edit_day.php id_reserv +SecRule REQUEST_URI_RAW "(?i:\/edit_day\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2003833,rev:4,msg:'ET WEB_SPECIFIC ResManager SQL Injection Attempt -- edit_day.php id_reserv ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_ResManager'" +SecRule REQUEST_URI_RAW "@contains (" "chain" +SecRule &TX:'/SQL_INJECTION.*ARGS:id_reserv/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC ResManager SQL Injection Attempt -- edit_day.php id_reserv ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004604) ET WEB_SPECIFIC RevokeSoft RevokeBB SQL Injection Attempt -- class_users.php +SecRule REQUEST_URI_RAW "(?i:\/inc\/class_users\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004604,rev:4,msg:'ET WEB_SPECIFIC RevokeSoft RevokeBB SQL Injection Attempt -- class_users.php ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_RevokeSoft'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\(.+SELECT)" + +# (sid 2005691) ET WEB_SPECIFIC Rialto SQL Injection Attempt -- listfull.asp ID +SecRule REQUEST_URI_RAW "(?i:\/listfull\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005691,rev:4,msg:'ET WEB_SPECIFIC Rialto SQL Injection Attempt -- listfull.asp ID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Rialto'" +SecRule &TX:'/SQL_INJECTION.*ARGS:ID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Rialto SQL Injection Attempt -- listfull.asp ID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005697) ET WEB_SPECIFIC Rialto SQL Injection Attempt -- printmain.asp ID +SecRule REQUEST_URI_RAW "(?i:\/printmain\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005697,rev:4,msg:'ET WEB_SPECIFIC Rialto SQL Injection Attempt -- printmain.asp ID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Rialto'" +SecRule &TX:'/SQL_INJECTION.*ARGS:ID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Rialto SQL Injection Attempt -- printmain.asp ID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005703) ET WEB_SPECIFIC Rialto SQL Injection Attempt -- listmain.asp cat +SecRule REQUEST_URI_RAW "(?i:\/listmain\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005703,rev:4,msg:'ET WEB_SPECIFIC Rialto SQL Injection Attempt -- listmain.asp cat ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Rialto'" +SecRule &TX:'/SQL_INJECTION.*ARGS:cat/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Rialto SQL Injection Attempt -- listmain.asp cat ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005709) ET WEB_SPECIFIC Rialto SQL Injection Attempt -- searchoption.asp cat +SecRule REQUEST_URI_RAW "(?i:\/searchoption\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005709,rev:4,msg:'ET WEB_SPECIFIC Rialto SQL Injection Attempt -- searchoption.asp cat ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Rialto'" +SecRule &TX:'/SQL_INJECTION.*ARGS:cat/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Rialto SQL Injection Attempt -- searchoption.asp cat ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005715) ET WEB_SPECIFIC Rialto SQL Injection Attempt -- searchmain.asp cat +SecRule REQUEST_URI_RAW "(?i:\/searchmain\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005715,rev:4,msg:'ET WEB_SPECIFIC Rialto SQL Injection Attempt -- searchmain.asp cat ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Rialto'" +SecRule &TX:'/SQL_INJECTION.*ARGS:cat/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Rialto SQL Injection Attempt -- searchmain.asp cat ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005721) ET WEB_SPECIFIC Rialto SQL Injection Attempt -- searchkey.asp Keyword +SecRule REQUEST_URI_RAW "(?i:\/searchkey\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005721,rev:4,msg:'ET WEB_SPECIFIC Rialto SQL Injection Attempt -- searchkey.asp Keyword ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Rialto'" +SecRule &TX:'/SQL_INJECTION.*ARGS:Keyword/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Rialto SQL Injection Attempt -- searchkey.asp Keyword ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005727) ET WEB_SPECIFIC Rialto SQL Injection Attempt -- searchmain.asp area +SecRule REQUEST_URI_RAW "(?i:\/searchmain\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005727,rev:4,msg:'ET WEB_SPECIFIC Rialto SQL Injection Attempt -- searchmain.asp area ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Rialto'" +SecRule &TX:'/SQL_INJECTION.*ARGS:area/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Rialto SQL Injection Attempt -- searchmain.asp area ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005733) ET WEB_SPECIFIC Rialto SQL Injection Attempt -- searchoption.asp area +SecRule REQUEST_URI_RAW "(?i:\/searchoption\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005733,rev:4,msg:'ET WEB_SPECIFIC Rialto SQL Injection Attempt -- searchoption.asp area ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Rialto'" +SecRule &TX:'/SQL_INJECTION.*ARGS:area/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Rialto SQL Injection Attempt -- searchoption.asp area ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005740) ET WEB_SPECIFIC Rialto SQL Injection Attempt -- searchkey.asp searchin +SecRule REQUEST_URI_RAW "(?i:\/searchkey\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005740,rev:4,msg:'ET WEB_SPECIFIC Rialto SQL Injection Attempt -- searchkey.asp searchin ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Rialto'" +SecRule &TX:'/SQL_INJECTION.*ARGS:searchin/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Rialto SQL Injection Attempt -- searchkey.asp searchin ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005746) ET WEB_SPECIFIC Rialto SQL Injection Attempt -- searchoption.asp cost1 +SecRule REQUEST_URI_RAW "(?i:\/searchoption\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005746,rev:4,msg:'ET WEB_SPECIFIC Rialto SQL Injection Attempt -- searchoption.asp cost1 ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Rialto'" +SecRule &TX:'/SQL_INJECTION.*ARGS:cost1/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Rialto SQL Injection Attempt -- searchoption.asp cost1 ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005752) ET WEB_SPECIFIC Rialto SQL Injection Attempt -- searchoption.asp cost2 +SecRule REQUEST_URI_RAW "(?i:\/searchoption\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005752,rev:4,msg:'ET WEB_SPECIFIC Rialto SQL Injection Attempt -- searchoption.asp cost2 ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Rialto'" +SecRule &TX:'/SQL_INJECTION.*ARGS:cost2/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Rialto SQL Injection Attempt -- searchoption.asp cost2 ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005758) ET WEB_SPECIFIC Rialto SQL Injection Attempt -- searchoption.asp acreage1 +SecRule REQUEST_URI_RAW "(?i:\/searchoption\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005758,rev:4,msg:'ET WEB_SPECIFIC Rialto SQL Injection Attempt -- searchoption.asp acreage1 ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Rialto'" +SecRule &TX:'/SQL_INJECTION.*ARGS:acreage1/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Rialto SQL Injection Attempt -- searchoption.asp acreage1 ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005764) ET WEB_SPECIFIC Rialto SQL Injection Attempt -- searchoption.asp squarefeet1 +SecRule REQUEST_URI_RAW "(?i:\/searchoption\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005764,rev:4,msg:'ET WEB_SPECIFIC Rialto SQL Injection Attempt -- searchoption.asp squarefeet1 ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Rialto'" +SecRule &TX:'/SQL_INJECTION.*ARGS:squarefeet1/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Rialto SQL Injection Attempt -- searchoption.asp squarefeet1 ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004664) ET WEB_SPECIFIC Rigter Portal System (RPS) SQL Injection Attempt -- index.php categoria +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004664,rev:4,msg:'ET WEB_SPECIFIC Rigter Portal System (RPS) SQL Injection Attempt -- index.php categoria ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Rigter_portal'" +SecRule &TX:'/SQL_INJECTION.*ARGS:categoria/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Rigter Portal System (RPS) SQL Injection Attempt -- index.php categoria ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2003821) ET WEB_SPECIFIC RunCms SQL Injection Attempt -- debug_show.php executed_queries +SecRule REQUEST_URI_RAW "(?i:\/class\/debug\/debug_show\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2003821,rev:4,msg:'ET WEB_SPECIFIC RunCms SQL Injection Attempt -- debug_show.php executed_queries ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_RunCMS'" +SecRule REQUEST_URI_RAW "@contains (" "chain" +SecRule &TX:'/SQL_INJECTION.*ARGS:executed_queries/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC RunCms SQL Injection Attempt -- debug_show.php executed_queries ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2003862) ET WEB_SPECIFIC RunawaySoft Haber portal 1.0 SQL Injection Attempt -- devami.asp id +SecRule REQUEST_URI_RAW "(?i:\/devami\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2003862,rev:4,msg:'ET WEB_SPECIFIC RunawaySoft Haber portal 1.0 SQL Injection Attempt -- devami.asp id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_RunawaySoft'" +SecRule REQUEST_URI_RAW "@contains (" "chain" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC RunawaySoft Haber portal 1.0 SQL Injection Attempt -- devami.asp id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004467) ET WEB_SPECIFIC SalesCart Shopping Cart SQL Injection Attempt -- reorder2.asp +SecRule REQUEST_URI_RAW "(?i:\/cgi\-bin\/reorder2\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004467,rev:4,msg:'ET WEB_SPECIFIC SalesCart Shopping Cart SQL Injection Attempt -- reorder2.asp ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Salescart'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\(.+SELECT)" + +# (sid 2004497) ET WEB_SPECIFIC Savas Guestbook SQL Injection Attempt -- add2.php name +SecRule REQUEST_URI_RAW "(?i:\/add2\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004497,rev:4,msg:'ET WEB_SPECIFIC Savas Guestbook SQL Injection Attempt -- add2.php name ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Savas'" +SecRule &TX:'/SQL_INJECTION.*ARGS:name/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Savas Guestbook SQL Injection Attempt -- add2.php name ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004503) ET WEB_SPECIFIC Savas Guestbook SQL Injection Attempt -- add2.php country +SecRule REQUEST_URI_RAW "(?i:\/add2\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004503,rev:4,msg:'ET WEB_SPECIFIC Savas Guestbook SQL Injection Attempt -- add2.php country ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Savas'" +SecRule &TX:'/SQL_INJECTION.*ARGS:country/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Savas Guestbook SQL Injection Attempt -- add2.php country ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004509) ET WEB_SPECIFIC Savas Guestbook SQL Injection Attempt -- add2.php email +SecRule REQUEST_URI_RAW "(?i:\/add2\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004509,rev:4,msg:'ET WEB_SPECIFIC Savas Guestbook SQL Injection Attempt -- add2.php email ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Savas'" +SecRule &TX:'/SQL_INJECTION.*ARGS:email/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Savas Guestbook SQL Injection Attempt -- add2.php email ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004515) ET WEB_SPECIFIC Savas Guestbook SQL Injection Attempt -- add2.php website +SecRule REQUEST_URI_RAW "(?i:\/add2\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004515,rev:4,msg:'ET WEB_SPECIFIC Savas Guestbook SQL Injection Attempt -- add2.php website ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Savas'" +SecRule &TX:'/SQL_INJECTION.*ARGS:website/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Savas Guestbook SQL Injection Attempt -- add2.php website ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004521) ET WEB_SPECIFIC Savas Guestbook SQL Injection Attempt -- add2.php message +SecRule REQUEST_URI_RAW "(?i:\/add2\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004521,rev:4,msg:'ET WEB_SPECIFIC Savas Guestbook SQL Injection Attempt -- add2.php message ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Savas'" +SecRule &TX:'/SQL_INJECTION.*ARGS:message/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Savas Guestbook SQL Injection Attempt -- add2.php message ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004120) ET WEB_SPECIFIC ScriptMagix Jokes SQL Injection Attempt -- index.php catid +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004120,rev:4,msg:'ET WEB_SPECIFIC ScriptMagix Jokes SQL Injection Attempt -- index.php catid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_ScriptMagix'" +SecRule &TX:'/SQL_INJECTION.*ARGS:catid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC ScriptMagix Jokes SQL Injection Attempt -- index.php catid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006313) ET WEB_SPECIFIC ScriptMate User Manager SQL Injection Attempt -- usermessages.asp mesid +SecRule REQUEST_URI_RAW "(?i:\/utilities\/usermessages\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006313,rev:4,msg:'ET WEB_SPECIFIC ScriptMate User Manager SQL Injection Attempt -- usermessages.asp mesid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_ScriptMate'" +SecRule &TX:'/SQL_INJECTION.*ARGS:mesid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC ScriptMate User Manager SQL Injection Attempt -- usermessages.asp mesid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004419) ET WEB_SPECIFIC Serendipity SQL Injection Attempt -- index.php serendipity +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004419,rev:4,msg:'ET WEB_SPECIFIC Serendipity SQL Injection Attempt -- index.php serendipity ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Serendipity'" +SecRule REQUEST_URI_RAW "@contains serendipity[multiCat][" "chain" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\(.+SELECT)" + +# (sid 2005794) ET WEB_SPECIFIC ShopStoreNow E-commerce Shopping Cart SQL Injection Attempt -- orange.asp CatID +SecRule REQUEST_URI_RAW "(?i:\/orange\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005794,rev:4,msg:'ET WEB_SPECIFIC ShopStoreNow E-commerce Shopping Cart SQL Injection Attempt -- orange.asp CatID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_ShopStoreNow'" +SecRule &TX:'/SQL_INJECTION.*ARGS:CatID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC ShopStoreNow E-commerce Shopping Cart SQL Injection Attempt -- orange.asp CatID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2003856) ET WEB_SPECIFIC SimpNews SQL Injection Attempt -- print.php newsnr +SecRule REQUEST_URI_RAW "(?i:\/print\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2003856,rev:4,msg:'ET WEB_SPECIFIC SimpNews SQL Injection Attempt -- print.php newsnr ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_SimpleNews'" +SecRule REQUEST_URI_RAW "@contains (" "chain" +SecRule &TX:'/SQL_INJECTION.*ARGS:newsnr/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC SimpNews SQL Injection Attempt -- print.php newsnr ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004783) ET WEB_SPECIFIC Simple PHP Forum SQL Injection Attempt -- logon_user.php username +SecRule REQUEST_URI_RAW "(?i:\/logon_user\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004783,rev:4,msg:'ET WEB_SPECIFIC Simple PHP Forum SQL Injection Attempt -- logon_user.php username ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Simple_PHP_Portal'" +SecRule &TX:'/SQL_INJECTION.*ARGS:username/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Simple PHP Forum SQL Injection Attempt -- logon_user.php username ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004789) ET WEB_SPECIFIC Simple PHP Forum SQL Injection Attempt -- update_profile.php username +SecRule REQUEST_URI_RAW "(?i:\/update_profile\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004789,rev:4,msg:'ET WEB_SPECIFIC Simple PHP Forum SQL Injection Attempt -- update_profile.php username ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Simple_PHP_Portal'" +SecRule &TX:'/SQL_INJECTION.*ARGS:username/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Simple PHP Forum SQL Injection Attempt -- update_profile.php username ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005875) ET WEB_SPECIFIC Simple Web Content Management System SQL Injection Attempt -- page.php id +SecRule REQUEST_URI_RAW "(?i:\/page\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005875,rev:4,msg:'ET WEB_SPECIFIC Simple Web Content Management System SQL Injection Attempt -- page.php id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Simple_Web_CMS'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Simple Web Content Management System SQL Injection Attempt -- page.php id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005522) ET WEB_SPECIFIC SmE FileMailer SQL Injection Attempt -- index.php ps +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005522,rev:4,msg:'ET WEB_SPECIFIC SmE FileMailer SQL Injection Attempt -- index.php ps ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_SmE'" +SecRule &TX:'/SQL_INJECTION.*ARGS:ps/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC SmE FileMailer SQL Injection Attempt -- index.php ps ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005528) ET WEB_SPECIFIC SmE FileMailer SQL Injection Attempt -- index.php us +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005528,rev:4,msg:'ET WEB_SPECIFIC SmE FileMailer SQL Injection Attempt -- index.php us ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_SmE'" +SecRule &TX:'/SQL_INJECTION.*ARGS:us/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC SmE FileMailer SQL Injection Attempt -- index.php us ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005534) ET WEB_SPECIFIC SmE FileMailer SQL Injection Attempt -- index.php f +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005534,rev:4,msg:'ET WEB_SPECIFIC SmE FileMailer SQL Injection Attempt -- index.php f ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_SmE'" +SecRule &TX:'/SQL_INJECTION.*ARGS:f/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC SmE FileMailer SQL Injection Attempt -- index.php f ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005540) ET WEB_SPECIFIC SmE FileMailer SQL Injection Attempt -- index.php code +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005540,rev:4,msg:'ET WEB_SPECIFIC SmE FileMailer SQL Injection Attempt -- index.php code ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_SmE'" +SecRule &TX:'/SQL_INJECTION.*ARGS:code/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC SmE FileMailer SQL Injection Attempt -- index.php code ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005546) ET WEB_SPECIFIC SmE FileMailer SQL Injection Attempt -- dl.php code +SecRule REQUEST_URI_RAW "(?i:\/dl\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005546,rev:4,msg:'ET WEB_SPECIFIC SmE FileMailer SQL Injection Attempt -- dl.php code ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_SmE'" +SecRule &TX:'/SQL_INJECTION.*ARGS:code/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC SmE FileMailer SQL Injection Attempt -- dl.php code ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005552) ET WEB_SPECIFIC SmE FileMailer SQL Injection Attempt -- dl.php f +SecRule REQUEST_URI_RAW "(?i:\/dl\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005552,rev:4,msg:'ET WEB_SPECIFIC SmE FileMailer SQL Injection Attempt -- dl.php f ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_SmE'" +SecRule &TX:'/SQL_INJECTION.*ARGS:f/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC SmE FileMailer SQL Injection Attempt -- dl.php f ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005558) ET WEB_SPECIFIC SmE FileMailer SQL Injection Attempt -- dl.php us +SecRule REQUEST_URI_RAW "(?i:\/dl\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005558,rev:4,msg:'ET WEB_SPECIFIC SmE FileMailer SQL Injection Attempt -- dl.php us ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_SmE'" +SecRule &TX:'/SQL_INJECTION.*ARGS:us/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC SmE FileMailer SQL Injection Attempt -- dl.php us ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005564) ET WEB_SPECIFIC SmE FileMailer SQL Injection Attempt -- dl.php ps +SecRule REQUEST_URI_RAW "(?i:\/dl\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005564,rev:4,msg:'ET WEB_SPECIFIC SmE FileMailer SQL Injection Attempt -- dl.php ps ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_SmE'" +SecRule &TX:'/SQL_INJECTION.*ARGS:ps/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC SmE FileMailer SQL Injection Attempt -- dl.php ps ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004867) ET WEB_SPECIFIC Snitz Forums 2000 SQL Injection Attempt -- pop_profile.asp id +SecRule REQUEST_URI_RAW "(?i:\/pop_profile\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004867,rev:4,msg:'ET WEB_SPECIFIC Snitz Forums 2000 SQL Injection Attempt -- pop_profile.asp id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Snitz'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Snitz Forums 2000 SQL Injection Attempt -- pop_profile.asp id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006133) ET WEB_SPECIFIC Softwebs Nepal Ananda Real Estate SQL Injection Attempt -- list.asp agent +SecRule REQUEST_URI_RAW "(?i:\/list\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006133,rev:4,msg:'ET WEB_SPECIFIC Softwebs Nepal Ananda Real Estate SQL Injection Attempt -- list.asp agent ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Softwebs'" +SecRule &TX:'/SQL_INJECTION.*ARGS:agent/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Softwebs Nepal Ananda Real Estate SQL Injection Attempt -- list.asp agent ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006484) ET WEB_SPECIFIC Solar Empire SQL Injection Attempt -- game_listing.php +SecRule REQUEST_URI_RAW "(?i:\/game_listing\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006484,rev:4,msg:'ET WEB_SPECIFIC Solar Empire SQL Injection Attempt -- game_listing.php ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Solar_Empire'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:.+\(.+SELECT)" + +# (sid 2004383) ET WEB_SPECIFIC Triexa SonicMailer Pro SQL Injection Attempt -- index.php list +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004383,rev:4,msg:'ET WEB_SPECIFIC Triexa SonicMailer Pro SQL Injection Attempt -- index.php list ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_SonicMailer'" +SecRule &TX:'/SQL_INJECTION.*ARGS:list/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Triexa SonicMailer Pro SQL Injection Attempt -- index.php list ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004820) ET WEB_SPECIFIC Sphider SQL Injection Attempt -- search.php category +SecRule REQUEST_URI_RAW "(?i:\/search\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004820,rev:4,msg:'ET WEB_SPECIFIC Sphider SQL Injection Attempt -- search.php category ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Sphider'" +SecRule &TX:'/SQL_INJECTION.*ARGS:category/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Sphider SQL Injection Attempt -- search.php category ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005156) ET WEB_SPECIFIC SpoonLabs Vivvo Article Management CMS (phpWordPress) SQL Injection Attempt -- show_webfeed.php wcHeadlines +SecRule REQUEST_URI_RAW "(?i:\/rss\/show_webfeed\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005156,rev:4,msg:'ET WEB_SPECIFIC SpoonLabs Vivvo Article Management CMS (phpWordPress) SQL Injection Attempt -- show_webfeed.php wcHeadlines ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_SpoonLabs'" +SecRule &TX:'/SQL_INJECTION.*ARGS:wcHeadlines/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC SpoonLabs Vivvo Article Management CMS (phpWordPress) SQL Injection Attempt -- show_webfeed.php wcHeadlines ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004826) ET WEB_SPECIFIC Super Link Exchange Script SQL Injection Attempt -- directory.php cat +SecRule REQUEST_URI_RAW "(?i:\/directory\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004826,rev:4,msg:'ET WEB_SPECIFIC Super Link Exchange Script SQL Injection Attempt -- directory.php cat ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Super_Link_Exchange'" +SecRule &TX:'/SQL_INJECTION.*ARGS:cat/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Super Link Exchange Script SQL Injection Attempt -- directory.php cat ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006637) ET WEB_SPECIFIC Superfreaker Studios UPublisher SQL Injection Attempt -- sendarticle.asp +SecRule REQUEST_URI_RAW "(?i:\/sendarticle\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006637,rev:4,msg:'ET WEB_SPECIFIC Superfreaker Studios UPublisher SQL Injection Attempt -- sendarticle.asp ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Superfreaker'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:.+\(.+SELECT)" + +# (sid 2006643) ET WEB_SPECIFIC Superfreaker Studios UPublisher SQL Injection Attempt -- printarticle.asp +SecRule REQUEST_URI_RAW "(?i:\/printarticle\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006643,rev:4,msg:'ET WEB_SPECIFIC Superfreaker Studios UPublisher SQL Injection Attempt -- printarticle.asp ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Superfreaker'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:.+\(.+SELECT)" + +# (sid 2006649) ET WEB_SPECIFIC Superfreaker Studios UPublisher SQL Injection Attempt -- index.asp ID +SecRule REQUEST_URI_RAW "(?i:\/index\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006649,rev:4,msg:'ET WEB_SPECIFIC Superfreaker Studios UPublisher SQL Injection Attempt -- index.asp ID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Superfreaker'" +SecRule &TX:'/SQL_INJECTION.*ARGS:ID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Superfreaker Studios UPublisher SQL Injection Attempt -- index.asp ID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006655) ET WEB_SPECIFIC Superfreaker Studios UPublisher SQL Injection Attempt -- preferences.asp ID +SecRule REQUEST_URI_RAW "(?i:\/preferences\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006655,rev:4,msg:'ET WEB_SPECIFIC Superfreaker Studios UPublisher SQL Injection Attempt -- preferences.asp ID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Superfreaker'" +SecRule &TX:'/SQL_INJECTION.*ARGS:ID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Superfreaker Studios UPublisher SQL Injection Attempt -- preferences.asp ID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005571) ET WEB_SPECIFIC ThWboard SQL Injection Attempt -- index.php board +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005571,rev:4,msg:'ET WEB_SPECIFIC ThWboard SQL Injection Attempt -- index.php board ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_ThWboard'" +SecRule REQUEST_URI_RAW "@contains board[" "chain" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\(.+SELECT)" + +# (sid 2006007) ET WEB_SPECIFIC The Address Book SQL Injection Attempt -- user.php lastname +SecRule REQUEST_URI_RAW "(?i:\/user\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006007,rev:4,msg:'ET WEB_SPECIFIC The Address Book SQL Injection Attempt -- user.php lastname ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_The_Address_Book'" +SecRule &TX:'/SQL_INJECTION.*ARGS:lastname/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC The Address Book SQL Injection Attempt -- user.php lastname ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006013) ET WEB_SPECIFIC The Address Book SQL Injection Attempt -- user.php firstname +SecRule REQUEST_URI_RAW "(?i:\/user\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006013,rev:4,msg:'ET WEB_SPECIFIC The Address Book SQL Injection Attempt -- user.php firstname ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_The_Address_Book'" +SecRule &TX:'/SQL_INJECTION.*ARGS:firstname/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC The Address Book SQL Injection Attempt -- user.php firstname ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006019) ET WEB_SPECIFIC The Address Book SQL Injection Attempt -- user.php passwordOld +SecRule REQUEST_URI_RAW "(?i:\/user\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006019,rev:4,msg:'ET WEB_SPECIFIC The Address Book SQL Injection Attempt -- user.php passwordOld ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_The_Address_Book'" +SecRule &TX:'/SQL_INJECTION.*ARGS:passwordOld/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC The Address Book SQL Injection Attempt -- user.php passwordOld ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006025) ET WEB_SPECIFIC The Address Book SQL Injection Attempt -- user.php passwordNew +SecRule REQUEST_URI_RAW "(?i:\/user\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006025,rev:4,msg:'ET WEB_SPECIFIC The Address Book SQL Injection Attempt -- user.php passwordNew ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_The_Address_Book'" +SecRule &TX:'/SQL_INJECTION.*ARGS:passwordNew/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC The Address Book SQL Injection Attempt -- user.php passwordNew ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006031) ET WEB_SPECIFIC The Address Book SQL Injection Attempt -- user.php id +SecRule REQUEST_URI_RAW "(?i:\/user\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006031,rev:4,msg:'ET WEB_SPECIFIC The Address Book SQL Injection Attempt -- user.php id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_The_Address_Book'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC The Address Book SQL Injection Attempt -- user.php id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006037) ET WEB_SPECIFIC The Address Book SQL Injection Attempt -- user.php language +SecRule REQUEST_URI_RAW "(?i:\/user\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006037,rev:4,msg:'ET WEB_SPECIFIC The Address Book SQL Injection Attempt -- user.php language ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_The_Address_Book'" +SecRule &TX:'/SQL_INJECTION.*ARGS:language/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC The Address Book SQL Injection Attempt -- user.php language ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006043) ET WEB_SPECIFIC The Address Book SQL Injection Attempt -- user.php defaultLetter +SecRule REQUEST_URI_RAW "(?i:\/user\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006043,rev:4,msg:'ET WEB_SPECIFIC The Address Book SQL Injection Attempt -- user.php defaultLetter ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_The_Address_Book'" +SecRule &TX:'/SQL_INJECTION.*ARGS:defaultLetter/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC The Address Book SQL Injection Attempt -- user.php defaultLetter ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006049) ET WEB_SPECIFIC The Address Book SQL Injection Attempt -- user.php newuserPass +SecRule REQUEST_URI_RAW "(?i:\/user\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006049,rev:4,msg:'ET WEB_SPECIFIC The Address Book SQL Injection Attempt -- user.php newuserPass ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_The_Address_Book'" +SecRule &TX:'/SQL_INJECTION.*ARGS:newuserPass/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC The Address Book SQL Injection Attempt -- user.php newuserPass ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006055) ET WEB_SPECIFIC The Address Book SQL Injection Attempt -- user.php newuserType +SecRule REQUEST_URI_RAW "(?i:\/user\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006055,rev:4,msg:'ET WEB_SPECIFIC The Address Book SQL Injection Attempt -- user.php newuserType ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_The_Address_Book'" +SecRule &TX:'/SQL_INJECTION.*ARGS:newuserType/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC The Address Book SQL Injection Attempt -- user.php newuserType ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006061) ET WEB_SPECIFIC The Address Book SQL Injection Attempt -- user.php newuserEmail +SecRule REQUEST_URI_RAW "(?i:\/user\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006061,rev:4,msg:'ET WEB_SPECIFIC The Address Book SQL Injection Attempt -- user.php newuserEmail ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_The_Address_Book'" +SecRule &TX:'/SQL_INJECTION.*ARGS:newuserEmail/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC The Address Book SQL Injection Attempt -- user.php newuserEmail ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006067) ET WEB_SPECIFIC The Address Book SQL Injection Attempt -- search.php goTo +SecRule REQUEST_URI_RAW "(?i:\/search\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006067,rev:4,msg:'ET WEB_SPECIFIC The Address Book SQL Injection Attempt -- search.php goTo ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_The_Address_Book'" +SecRule &TX:'/SQL_INJECTION.*ARGS:goTo/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC The Address Book SQL Injection Attempt -- search.php goTo ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006073) ET WEB_SPECIFIC The Address Book SQL Injection Attempt -- search.php search +SecRule REQUEST_URI_RAW "(?i:\/search\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006073,rev:4,msg:'ET WEB_SPECIFIC The Address Book SQL Injection Attempt -- search.php search ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_The_Address_Book'" +SecRule &TX:'/SQL_INJECTION.*ARGS:search/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC The Address Book SQL Injection Attempt -- search.php search ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006079) ET WEB_SPECIFIC The Address Book SQL Injection Attempt -- save.php groupAddName +SecRule REQUEST_URI_RAW "(?i:\/save\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006079,rev:4,msg:'ET WEB_SPECIFIC The Address Book SQL Injection Attempt -- save.php groupAddName ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_The_Address_Book'" +SecRule &TX:'/SQL_INJECTION.*ARGS:groupAddName/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC The Address Book SQL Injection Attempt -- save.php groupAddName ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004873) ET WEB_SPECIFIC Turuncu Portal SQL Injection Attempt -- h_goster.asp id +SecRule REQUEST_URI_RAW "(?i:\/h_goster\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004873,rev:4,msg:'ET WEB_SPECIFIC Turuncu Portal SQL Injection Attempt -- h_goster.asp id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Turuncu'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Turuncu Portal SQL Injection Attempt -- h_goster.asp id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004676) ET WEB_SPECIFIC Tyger Bug Tracking System (TygerBT) SQL Injection Attempt -- ViewReport.php bug +SecRule REQUEST_URI_RAW "(?i:\/ViewReport\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004676,rev:4,msg:'ET WEB_SPECIFIC Tyger Bug Tracking System (TygerBT) SQL Injection Attempt -- ViewReport.php bug ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Tyger_Bug_Tracker'" +SecRule &TX:'/SQL_INJECTION.*ARGS:bug/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Tyger Bug Tracking System (TygerBT) SQL Injection Attempt -- ViewReport.php bug ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004681) ET WEB_SPECIFIC Tyger Bug Tracking System (TygerBT) SQL Injection Attempt -- ViewBugs.php s +SecRule REQUEST_URI_RAW "(?i:\/ViewBugs\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004681,rev:4,msg:'ET WEB_SPECIFIC Tyger Bug Tracking System (TygerBT) SQL Injection Attempt -- ViewBugs.php s ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Tyger_Bug_Tracker'" +SecRule &TX:'/SQL_INJECTION.*ARGS:s/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Tyger Bug Tracking System (TygerBT) SQL Injection Attempt -- ViewBugs.php s ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005237) ET WEB_SPECIFIC Unique Ads (UDS) SQL Injection Attempt -- banner.php bid +SecRule REQUEST_URI_RAW "(?i:\/banner\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005237,rev:4,msg:'ET WEB_SPECIFIC Unique Ads (UDS) SQL Injection Attempt -- banner.php bid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_UDS'" +SecRule &TX:'/SQL_INJECTION.*ARGS:bid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Unique Ads (UDS) SQL Injection Attempt -- banner.php bid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006890) ET WEB_SPECIFIC Uapplication UPhotoGallery SQL Injection Attempt -- slideshow.asp ci +SecRule REQUEST_URI_RAW "(?i:\/slideshow\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006890,rev:4,msg:'ET WEB_SPECIFIC Uapplication UPhotoGallery SQL Injection Attempt -- slideshow.asp ci ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Uapplication'" +SecRule &TX:'/SQL_INJECTION.*ARGS:ci/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Uapplication UPhotoGallery SQL Injection Attempt -- slideshow.asp ci ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006896) ET WEB_SPECIFIC Uapplication UPhotoGallery SQL Injection Attempt -- thumbnails.asp ci +SecRule REQUEST_URI_RAW "(?i:\/thumbnails\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006896,rev:4,msg:'ET WEB_SPECIFIC Uapplication UPhotoGallery SQL Injection Attempt -- thumbnails.asp ci ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Uapplication'" +SecRule &TX:'/SQL_INJECTION.*ARGS:ci/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Uapplication UPhotoGallery SQL Injection Attempt -- thumbnails.asp ci ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005007) ET WEB_SPECIFIC Ublog Reload SQL Injection Attempt -- badword.asp +SecRule REQUEST_URI_RAW "(?i:\/badword\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005007,rev:4,msg:'ET WEB_SPECIFIC Ublog Reload SQL Injection Attempt -- badword.asp ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Ublog'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\(.+SELECT)" + +# (sid 2007203) ET WEB_SPECIFIC Ultimate Survey Pro SQL Injection Attempt -- index.asp cat +SecRule REQUEST_URI_RAW "(?i:\/index\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007203,rev:3,msg:'ET WEB_SPECIFIC Ultimate Survey Pro SQL Injection Attempt -- index.asp cat ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Ultimate_Survey'" +SecRule &TX:'/SQL_INJECTION.*ARGS:cat/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Ultimate Survey Pro SQL Injection Attempt -- index.asp cat ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007209) ET WEB_SPECIFIC Ultimate Survey Pro SQL Injection Attempt -- index.asp did +SecRule REQUEST_URI_RAW "(?i:\/index\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007209,rev:3,msg:'ET WEB_SPECIFIC Ultimate Survey Pro SQL Injection Attempt -- index.asp did ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Ultimate_Survey'" +SecRule &TX:'/SQL_INJECTION.*ARGS:did/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Ultimate Survey Pro SQL Injection Attempt -- index.asp did ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005673) ET WEB_SPECIFIC VP-ASP Shopping Cart SQL Injection Attempt -- shopgiftregsearch.asp LoginLastname +SecRule REQUEST_URI_RAW "(?i:\/shopgiftregsearch\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005673,rev:4,msg:'ET WEB_SPECIFIC VP-ASP Shopping Cart SQL Injection Attempt -- shopgiftregsearch.asp LoginLastname ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_VP-ASP'" +SecRule &TX:'/SQL_INJECTION.*ARGS:LoginLastname/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC VP-ASP Shopping Cart SQL Injection Attempt -- shopgiftregsearch.asp LoginLastname ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006607) ET WEB_SPECIFIC Vt-Forum Lite SQL Injection Attempt -- vf_memberdetail.asp user +SecRule REQUEST_URI_RAW "(?i:\/vf_memberdetail\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006607,rev:4,msg:'ET WEB_SPECIFIC Vt-Forum Lite SQL Injection Attempt -- vf_memberdetail.asp user ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_VT_Forum'" +SecRule &TX:'/SQL_INJECTION.*ARGS:user/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Vt-Forum Lite SQL Injection Attempt -- vf_memberdetail.asp user ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006283) ET WEB_SPECIFIC VerliAdmin SQL Injection Attempt -- repass.php nick_mod +SecRule REQUEST_URI_RAW "(?i:\/repass\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006283,rev:4,msg:'ET WEB_SPECIFIC VerliAdmin SQL Injection Attempt -- repass.php nick_mod ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Verliadmin'" +SecRule &TX:'/SQL_INJECTION.*ARGS:nick_mod/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC VerliAdmin SQL Injection Attempt -- repass.php nick_mod ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006289) ET WEB_SPECIFIC VerliAdmin SQL Injection Attempt -- repass.php nick +SecRule REQUEST_URI_RAW "(?i:\/repass\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006289,rev:4,msg:'ET WEB_SPECIFIC VerliAdmin SQL Injection Attempt -- repass.php nick ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Verliadmin'" +SecRule &TX:'/SQL_INJECTION.*ARGS:nick/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC VerliAdmin SQL Injection Attempt -- repass.php nick ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006295) ET WEB_SPECIFIC VerliAdmin SQL Injection Attempt -- verify.php nick +SecRule REQUEST_URI_RAW "(?i:\/verify\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006295,rev:4,msg:'ET WEB_SPECIFIC VerliAdmin SQL Injection Attempt -- verify.php nick ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Verliadmin'" +SecRule &TX:'/SQL_INJECTION.*ARGS:nick/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC VerliAdmin SQL Injection Attempt -- verify.php nick ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006301) ET WEB_SPECIFIC VerliAdmin SQL Injection Attempt -- verify.php nick_mod +SecRule REQUEST_URI_RAW "(?i:\/verify\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006301,rev:4,msg:'ET WEB_SPECIFIC VerliAdmin SQL Injection Attempt -- verify.php nick_mod ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Verliadmin'" +SecRule &TX:'/SQL_INJECTION.*ARGS:nick_mod/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC VerliAdmin SQL Injection Attempt -- verify.php nick_mod ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005497) ET WEB_SPECIFIC Virtuemart SQL Injection Attempt -- virtuemart_parser.php Itemid +SecRule REQUEST_URI_RAW "(?i:\/virtuemart_parser\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005497,rev:4,msg:'ET WEB_SPECIFIC Virtuemart SQL Injection Attempt -- virtuemart_parser.php Itemid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Virtuemart'" +SecRule &TX:'/SQL_INJECTION.*ARGS:Itemid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Virtuemart SQL Injection Attempt -- virtuemart_parser.php Itemid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005503) ET WEB_SPECIFIC Virtuemart SQL Injection Attempt -- virtuemart_parser.php product_id +SecRule REQUEST_URI_RAW "(?i:\/virtuemart_parser\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005503,rev:4,msg:'ET WEB_SPECIFIC Virtuemart SQL Injection Attempt -- virtuemart_parser.php product_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Virtuemart'" +SecRule &TX:'/SQL_INJECTION.*ARGS:product_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Virtuemart SQL Injection Attempt -- virtuemart_parser.php product_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005509) ET WEB_SPECIFIC Virtuemart SQL Injection Attempt -- virtuemart_parser.php category_id +SecRule REQUEST_URI_RAW "(?i:\/virtuemart_parser\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005509,rev:4,msg:'ET WEB_SPECIFIC Virtuemart SQL Injection Attempt -- virtuemart_parser.php category_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Virtuemart'" +SecRule &TX:'/SQL_INJECTION.*ARGS:category_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Virtuemart SQL Injection Attempt -- virtuemart_parser.php category_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2003997) ET WEB_SPECIFIC Vizayn Urun Tanitim Sitesi SQL Injection Attempt -- default.asp id +SecRule REQUEST_URI_RAW "(?i:\/default\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2003997,rev:4,msg:'ET WEB_SPECIFIC Vizayn Urun Tanitim Sitesi SQL Injection Attempt -- default.asp id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Vizayn'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Vizayn Urun Tanitim Sitesi SQL Injection Attempt -- default.asp id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005893) ET WEB_SPECIFIC Vizayn Haber SQL Injection Attempt -- haberdetay.asp id +SecRule REQUEST_URI_RAW "(?i:\/haberdetay\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005893,rev:4,msg:'ET WEB_SPECIFIC Vizayn Haber SQL Injection Attempt -- haberdetay.asp id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Vizayn'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Vizayn Haber SQL Injection Attempt -- haberdetay.asp id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007420) ET WEB_SPECIFIC vSpin.net Classified System SQL Injection Attempt -- cat.asp cat +SecRule REQUEST_URI_RAW "(?i:\/cat\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007420,rev:3,msg:'ET WEB_SPECIFIC vSpin.net Classified System SQL Injection Attempt -- cat.asp cat ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Vspin'" +SecRule &TX:'/SQL_INJECTION.*ARGS:cat/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC vSpin.net Classified System SQL Injection Attempt -- cat.asp cat ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007426) ET WEB_SPECIFIC vSpin.net Classified System SQL Injection Attempt -- search.asp keyword +SecRule REQUEST_URI_RAW "(?i:\/search\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007426,rev:3,msg:'ET WEB_SPECIFIC vSpin.net Classified System SQL Injection Attempt -- search.asp keyword ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Vspin'" +SecRule &TX:'/SQL_INJECTION.*ARGS:keyword/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC vSpin.net Classified System SQL Injection Attempt -- search.asp keyword ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007432) ET WEB_SPECIFIC vSpin.net Classified System SQL Injection Attempt -- search.asp order +SecRule REQUEST_URI_RAW "(?i:\/search\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007432,rev:3,msg:'ET WEB_SPECIFIC vSpin.net Classified System SQL Injection Attempt -- search.asp order ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Vspin'" +SecRule &TX:'/SQL_INJECTION.*ARGS:order/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC vSpin.net Classified System SQL Injection Attempt -- search.asp order ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007438) ET WEB_SPECIFIC vSpin.net Classified System SQL Injection Attempt -- search.asp sort +SecRule REQUEST_URI_RAW "(?i:\/search\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007438,rev:3,msg:'ET WEB_SPECIFIC vSpin.net Classified System SQL Injection Attempt -- search.asp sort ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Vspin'" +SecRule &TX:'/SQL_INJECTION.*ARGS:sort/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC vSpin.net Classified System SQL Injection Attempt -- search.asp sort ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007444) ET WEB_SPECIFIC vSpin.net Classified System SQL Injection Attempt -- search.asp menuSelect +SecRule REQUEST_URI_RAW "(?i:\/search\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007444,rev:3,msg:'ET WEB_SPECIFIC vSpin.net Classified System SQL Injection Attempt -- search.asp menuSelect ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Vspin'" +SecRule &TX:'/SQL_INJECTION.*ARGS:menuSelect/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC vSpin.net Classified System SQL Injection Attempt -- search.asp menuSelect ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007450) ET WEB_SPECIFIC vSpin.net Classified System SQL Injection Attempt -- search.asp state +SecRule REQUEST_URI_RAW "(?i:\/search\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007450,rev:3,msg:'ET WEB_SPECIFIC vSpin.net Classified System SQL Injection Attempt -- search.asp state ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Vspin'" +SecRule &TX:'/SQL_INJECTION.*ARGS:state/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC vSpin.net Classified System SQL Injection Attempt -- search.asp state ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004132) ET WEB_SPECIFIC w-Agora SQL Injection Attempt -- search.php search_forum +SecRule REQUEST_URI_RAW "(?i:\/search\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004132,rev:4,msg:'ET WEB_SPECIFIC w-Agora SQL Injection Attempt -- search.php search_forum ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_W-Agora'" +SecRule &TX:'/SQL_INJECTION.*ARGS:search_forum/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC w-Agora SQL Injection Attempt -- search.php search_forum ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004138) ET WEB_SPECIFIC w-Agora SQL Injection Attempt -- search.php search_user +SecRule REQUEST_URI_RAW "(?i:\/search\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004138,rev:4,msg:'ET WEB_SPECIFIC w-Agora SQL Injection Attempt -- search.php search_user ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_W-Agora'" +SecRule &TX:'/SQL_INJECTION.*ARGS:search_user/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC w-Agora SQL Injection Attempt -- search.php search_user ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004651) ET WEB_SPECIFIC W1L3D4 WEBmarket SQL Injection Attempt -- urunbak.asp id +SecRule REQUEST_URI_RAW "(?i:\/urunbak\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004651,rev:4,msg:'ET WEB_SPECIFIC W1L3D4 WEBmarket SQL Injection Attempt -- urunbak.asp id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_W1L3D4_WEBmarlet'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC W1L3D4 WEBmarket SQL Injection Attempt -- urunbak.asp id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005308) ET WEB_SPECIFIC W2B Online Banking SQL Injection Attempt -- mailer.w2b draft +SecRule REQUEST_URI_RAW "(?i:\/mailer\.w2b)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005308,rev:4,msg:'ET WEB_SPECIFIC W2B Online Banking SQL Injection Attempt -- mailer.w2b draft ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_W2B'" +SecRule &TX:'/SQL_INJECTION.*ARGS:draft/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC W2B Online Banking SQL Injection Attempt -- mailer.w2b draft ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005190) ET WEB_SPECIFIC W2B Online Banking SQL Injection Attempt -- DocPay.w2b listDocPay +SecRule REQUEST_URI_RAW "(?i:\/DocPay\.w2b)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005190,rev:4,msg:'ET WEB_SPECIFIC W2B Online Banking SQL Injection Attempt -- DocPay.w2b listDocPay ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_W2B'" +SecRule &TX:'/SQL_INJECTION.*ARGS:listDocPay/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC W2B Online Banking SQL Injection Attempt -- DocPay.w2b listDocPay ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004318) ET WEB_SPECIFIC WBBlog SQL Injection Attempt -- index.php e_id +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004318,rev:4,msg:'ET WEB_SPECIFIC WBBlog SQL Injection Attempt -- index.php e_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_WBBlog'" +SecRule &TX:'/SQL_INJECTION.*ARGS:e_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC WBBlog SQL Injection Attempt -- index.php e_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005953) ET WEB_SPECIFIC Website Designs For Less Click N Print Coupons SQL Injection Attempt -- coupon_detail.asp key +SecRule REQUEST_URI_RAW "(?i:\/coupon_detail\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005953,rev:4,msg:'ET WEB_SPECIFIC Website Designs For Less Click N Print Coupons SQL Injection Attempt -- coupon_detail.asp key ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_WDFL'" +SecRule &TX:'/SQL_INJECTION.*ARGS:key/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Website Designs For Less Click N Print Coupons SQL Injection Attempt -- coupon_detail.asp key ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2003768) ET WEB_SPECIFIC WF-Links (wflinks) SQL Injection Attempt -- viewcat.php cid +SecRule REQUEST_URI_RAW "(?i:\/viewcat\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2003768,rev:4,msg:'ET WEB_SPECIFIC WF-Links (wflinks) SQL Injection Attempt -- viewcat.php cid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_WF-Links'" +SecRule REQUEST_URI_RAW "@contains (" "chain" +SecRule &TX:'/SQL_INJECTION.*ARGS:cid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC WF-Links (wflinks) SQL Injection Attempt -- viewcat.php cid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004257) ET WEB_SPECIFIC WSN Guest SQL Injection Attempt -- comments.php id +SecRule REQUEST_URI_RAW "(?i:\/comments\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004257,rev:4,msg:'ET WEB_SPECIFIC WSN Guest SQL Injection Attempt -- comments.php id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_WSN'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC WSN Guest SQL Injection Attempt -- comments.php id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006459) ET WEB_SPECIFIC WSPortal SQL Injection Attempt -- content.php page +SecRule REQUEST_URI_RAW "(?i:\/content\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006459,rev:4,msg:'ET WEB_SPECIFIC WSPortal SQL Injection Attempt -- content.php page ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_WSPortal'" +SecRule &TX:'/SQL_INJECTION.*ARGS:page/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC WSPortal SQL Injection Attempt -- content.php page ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005959) ET WEB_SPECIFIC While You Were Out (WYWO) InOut Board SQL Injection Attempt -- phonemessage.asp num +SecRule REQUEST_URI_RAW "(?i:\/phonemessage\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005959,rev:4,msg:'ET WEB_SPECIFIC While You Were Out (WYWO) InOut Board SQL Injection Attempt -- phonemessage.asp num ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_WYWO'" +SecRule &TX:'/SQL_INJECTION.*ARGS:num/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC While You Were Out (WYWO) InOut Board SQL Injection Attempt -- phonemessage.asp num ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005965) ET WEB_SPECIFIC While You Were Out (WYWO) InOut Board SQL Injection Attempt -- faqDsp.asp catcode +SecRule REQUEST_URI_RAW "(?i:\/faqDsp\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005965,rev:4,msg:'ET WEB_SPECIFIC While You Were Out (WYWO) InOut Board SQL Injection Attempt -- faqDsp.asp catcode ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_WYWO'" +SecRule &TX:'/SQL_INJECTION.*ARGS:catcode/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC While You Were Out (WYWO) InOut Board SQL Injection Attempt -- faqDsp.asp catcode ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006979) ET WEB_SPECIFIC Wallpaper Complete Website SQL Injection Attempt -- process.php login +SecRule REQUEST_URI_RAW "(?i:\/process\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006979,rev:4,msg:'ET WEB_SPECIFIC Wallpaper Complete Website SQL Injection Attempt -- process.php login ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Wallpaper_Complete'" +SecRule &TX:'/SQL_INJECTION.*ARGS:login/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Wallpaper Complete Website SQL Injection Attempt -- process.php login ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006985) ET WEB_SPECIFIC Wallpaper Complete Website SQL Injection Attempt -- process.php password +SecRule REQUEST_URI_RAW "(?i:\/process\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006985,rev:4,msg:'ET WEB_SPECIFIC Wallpaper Complete Website SQL Injection Attempt -- process.php password ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Wallpaper_Complete'" +SecRule &TX:'/SQL_INJECTION.*ARGS:password/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Wallpaper Complete Website SQL Injection Attempt -- process.php password ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006991) ET WEB_SPECIFIC Wallpaper Complete Website SQL Injection Attempt -- dlwallpaper.php wallpaperid +SecRule REQUEST_URI_RAW "(?i:\/dlwallpaper\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006991,rev:4,msg:'ET WEB_SPECIFIC Wallpaper Complete Website SQL Injection Attempt -- dlwallpaper.php wallpaperid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Wallpaper_Complete'" +SecRule &TX:'/SQL_INJECTION.*ARGS:wallpaperid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Wallpaper Complete Website SQL Injection Attempt -- dlwallpaper.php wallpaperid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006997) ET WEB_SPECIFIC Wallpaper Complete Website SQL Injection Attempt -- wallpaper.php wallpaperid +SecRule REQUEST_URI_RAW "(?i:\/wallpaper\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006997,rev:4,msg:'ET WEB_SPECIFIC Wallpaper Complete Website SQL Injection Attempt -- wallpaper.php wallpaperid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Wallpaper_Complete'" +SecRule &TX:'/SQL_INJECTION.*ARGS:wallpaperid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Wallpaper Complete Website SQL Injection Attempt -- wallpaper.php wallpaperid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007074) ET WEB_SPECIFIC WarHound General Shopping Cart SQL Injection Attempt -- item.asp ItemID +SecRule REQUEST_URI_RAW "(?i:\/item\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007074,rev:3,msg:'ET WEB_SPECIFIC WarHound General Shopping Cart SQL Injection Attempt -- item.asp ItemID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Warhound'" +SecRule &TX:'/SQL_INJECTION.*ARGS:ItemID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC WarHound General Shopping Cart SQL Injection Attempt -- item.asp ItemID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004758) ET WEB_SPECIFIC WebMplayer SQL Injection Attempt -- index.php strid +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004758,rev:4,msg:'ET WEB_SPECIFIC WebMplayer SQL Injection Attempt -- index.php strid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_WebMplayer'" +SecRule &TX:'/SQL_INJECTION.*ARGS:strid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC WebMplayer SQL Injection Attempt -- index.php strid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004764) ET WEB_SPECIFIC WebMplayer SQL Injection Attempt -- filecheck.php id +SecRule REQUEST_URI_RAW "(?i:\/filecheck\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004764,rev:4,msg:'ET WEB_SPECIFIC WebMplayer SQL Injection Attempt -- filecheck.php id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_WebMplayer'" +SecRule REQUEST_URI_RAW "@contains id[" "chain" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\(.+SELECT)" + +# (sid 2004915) ET WEB_SPECIFIC WebTester SQL Injection Attempt -- directions.php testID +SecRule REQUEST_URI_RAW "(?i:\/directions\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004915,rev:4,msg:'ET WEB_SPECIFIC WebTester SQL Injection Attempt -- directions.php testID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_WebTester'" +SecRule &TX:'/SQL_INJECTION.*ARGS:testID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC WebTester SQL Injection Attempt -- directions.php testID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004776) ET WEB_SPECIFIC Ban SQL Injection Attempt -- connexion.php id +SecRule REQUEST_URI_RAW "(?i:\/connexion\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004776,rev:4,msg:'ET WEB_SPECIFIC Ban SQL Injection Attempt -- connexion.php id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Web_Ban'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Ban SQL Injection Attempt -- connexion.php id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004228) ET WEB_SPECIFIC Web Wiz Forums SQL Injection Attempt -- functions_filters.asp +SecRule REQUEST_URI_RAW "(?i:\/functions\/functions_filters\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004228,rev:4,msg:'ET WEB_SPECIFIC Web Wiz Forums SQL Injection Attempt -- functions_filters.asp ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Web_Wiz'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\(.+SELECT)" + +# (sid 2004439) ET WEB_SPECIFIC Web Wiz Forums SQL Injection Attempt -- pop_up_member_search.asp name +SecRule REQUEST_URI_RAW "(?i:\/forum\/pop_up_member_search\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004439,rev:4,msg:'ET WEB_SPECIFIC Web Wiz Forums SQL Injection Attempt -- pop_up_member_search.asp name ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Web_Wiz'" +SecRule &TX:'/SQL_INJECTION.*ARGS:name/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Web Wiz Forums SQL Injection Attempt -- pop_up_member_search.asp name ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004239) ET WEB_SPECIFIC Web Wiz Forums SQL Injection Attempt -- page.asp NewsID +SecRule REQUEST_URI_RAW "(?i:\/News\/page\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004239,rev:4,msg:'ET WEB_SPECIFIC Web Wiz Forums SQL Injection Attempt -- page.asp NewsID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Web_Wiz'" +SecRule &TX:'/SQL_INJECTION.*ARGS:NewsID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Web Wiz Forums SQL Injection Attempt -- page.asp NewsID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005231) ET WEB_SPECIFIC Website Baker SQL Injection Attempt -- eWebQuiz.asp QuizID +SecRule REQUEST_URI_RAW "(?i:\/eWebQuiz\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005231,rev:4,msg:'ET WEB_SPECIFIC Website Baker SQL Injection Attempt -- eWebQuiz.asp QuizID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Website_Baker'" +SecRule &TX:'/SQL_INJECTION.*ARGS:QuizID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Website Baker SQL Injection Attempt -- eWebQuiz.asp QuizID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004144) ET WEB_SPECIFIC Weekly Drawing Contest SQL Injection Attempt -- check_vote.php order +SecRule REQUEST_URI_RAW "(?i:\/check_vote\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004144,rev:4,msg:'ET WEB_SPECIFIC Weekly Drawing Contest SQL Injection Attempt -- check_vote.php order ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Weekly_Drawing'" +SecRule &TX:'/SQL_INJECTION.*ARGS:order/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Weekly Drawing Contest SQL Injection Attempt -- check_vote.php order ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004251) ET WEB_SPECIFIC Woltlab Burning Board SQL Injection Attempt -- usergroups.php +SecRule REQUEST_URI_RAW "(?i:\/usergroups\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004251,rev:4,msg:'ET WEB_SPECIFIC Woltlab Burning Board SQL Injection Attempt -- usergroups.php ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Woltlab'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\(.+SELECT)" + +# (sid 2005001) ET WEB_SPECIFIC Woltlab Burning Board (wBB) Lite SQL Injection Attempt -- pms.php pmid +SecRule REQUEST_URI_RAW "(?i:\/pms\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005001,rev:4,msg:'ET WEB_SPECIFIC Woltlab Burning Board (wBB) Lite SQL Injection Attempt -- pms.php pmid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Woltlab'" +SecRule REQUEST_URI_RAW "@contains pmid[" "chain" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\(.+SELECT)" + +# (sid 2005284) ET WEB_SPECIFIC Woltlab Burning Board (wBB) SQL Injection Attempt -- search.php boardids +SecRule REQUEST_URI_RAW "(?i:\/search\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005284,rev:4,msg:'ET WEB_SPECIFIC Woltlab Burning Board (wBB) SQL Injection Attempt -- search.php boardids ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Woltlab'" +SecRule REQUEST_URI_RAW "@contains boardids[" "chain" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\(.+SELECT)" + +# (sid 2005290) ET WEB_SPECIFIC Woltlab Burning Board (wBB) SQL Injection Attempt -- search.php board +SecRule REQUEST_URI_RAW "(?i:\/search\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005290,rev:4,msg:'ET WEB_SPECIFIC Woltlab Burning Board (wBB) SQL Injection Attempt -- search.php board ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Woltlab'" +SecRule REQUEST_URI_RAW "@contains board[" "chain" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\(.+SELECT)" + +# (sid 2006925) ET WEB_SPECIFIC Woltlab Burning Board Lite SQL Injection Attempt -- thread.php threadvisit +SecRule REQUEST_URI_RAW "(?i:\/thread\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006925,rev:4,msg:'ET WEB_SPECIFIC Woltlab Burning Board Lite SQL Injection Attempt -- thread.php threadvisit ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Woltlab'" +SecRule &TX:'/SQL_INJECTION.*ARGS:threadvisit/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Woltlab Burning Board Lite SQL Injection Attempt -- thread.php threadvisit ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004015) ET WEB_SPECIFIC WordPress SQL Injection Attempt -- admin-ajax.php cookie +SecRule REQUEST_URI_RAW "(?i:\/wp\-admin\/admin\-ajax\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004015,rev:4,msg:'ET WEB_SPECIFIC WordPress SQL Injection Attempt -- admin-ajax.php cookie ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Wordpress'" +SecRule &TX:'/SQL_INJECTION.*ARGS:cookie/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC WordPress SQL Injection Attempt -- admin-ajax.php cookie ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004407) ET WEB_SPECIFIC WordPress SQL Injection Attempt -- admin-functions.php +SecRule REQUEST_URI_RAW "(?i:\/wp\-admin\/admin\-functions\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004407,rev:4,msg:'ET WEB_SPECIFIC WordPress SQL Injection Attempt -- admin-functions.php ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Wordpress'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\(.+SELECT)" + +# (sid 2004658) ET WEB_SPECIFIC Wordpress 2.2 SQL Injection Attempt -- xmlrpc.php +SecRule REQUEST_URI_RAW "(?i:\/xmlrpc\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004658,rev:4,msg:'ET WEB_SPECIFIC Wordpress 2.2 SQL Injection Attempt -- xmlrpc.php ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Wordpress'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\(.+SELECT)" + +# (sid 2005661) ET WEB_SPECIFIC WordPress SQL Injection Attempt -- wp-trackback.php +SecRule REQUEST_URI_RAW "(?i:\/wp\-trackback\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005661,rev:4,msg:'ET WEB_SPECIFIC WordPress SQL Injection Attempt -- wp-trackback.php ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Wordpress'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\(.+SELECT)" + +# (sid 2005869) ET WEB_SPECIFIC WordPress SQL Injection Attempt -- wp-trackback.php +SecRule REQUEST_URI_RAW "(?i:\/wp\-trackback\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005869,rev:4,msg:'ET WEB_SPECIFIC WordPress SQL Injection Attempt -- wp-trackback.php ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Wordpress'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\(.+SELECT)" + +# (sid 2004347) ET WEB_SPECIFIC X-Ice News System SQL Injection Attempt -- devami.asp id +SecRule REQUEST_URI_RAW "(?i:\/devami\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004347,rev:4,msg:'ET WEB_SPECIFIC X-Ice News System SQL Injection Attempt -- devami.asp id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_X-Ice_News'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC X-Ice News System SQL Injection Attempt -- devami.asp id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005121) ET WEB_SPECIFIC X-dev xNews SQL Injection Attempt -- class.news.php id +SecRule REQUEST_URI_RAW "(?i:\/classes\/class\.news\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005121,rev:4,msg:'ET WEB_SPECIFIC X-dev xNews SQL Injection Attempt -- class.news.php id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_X-dev'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC X-dev xNews SQL Injection Attempt -- class.news.php id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005127) ET WEB_SPECIFIC X-dev xNews SQL Injection Attempt -- class.news.php from +SecRule REQUEST_URI_RAW "(?i:\/classes\/class\.news\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005127,rev:4,msg:'ET WEB_SPECIFIC X-dev xNews SQL Injection Attempt -- class.news.php from ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_X-dev'" +SecRule &TX:'/SQL_INJECTION.*ARGS:from/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC X-dev xNews SQL Injection Attempt -- class.news.php from ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005133) ET WEB_SPECIFIC X-dev xNews SQL Injection Attempt -- class.news.php q +SecRule REQUEST_URI_RAW "(?i:\/classes\/class\.news\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005133,rev:4,msg:'ET WEB_SPECIFIC X-dev xNews SQL Injection Attempt -- class.news.php q ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_X-dev'" +SecRule &TX:'/SQL_INJECTION.*ARGS:q/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC X-dev xNews SQL Injection Attempt -- class.news.php q ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004861) ET WEB_SPECIFIC XLAtunes SQL Injection Attempt -- view.php album +SecRule REQUEST_URI_RAW "(?i:\/view\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004861,rev:4,msg:'ET WEB_SPECIFIC XLAtunes SQL Injection Attempt -- view.php album ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_XLAtunes'" +SecRule &TX:'/SQL_INJECTION.*ARGS:album/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC XLAtunes SQL Injection Attempt -- view.php album ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005382) ET WEB_SPECIFIC Xoops SQL Injection Attempt -- group.php id +SecRule REQUEST_URI_RAW "(?i:\/kernel\/group\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005382,rev:4,msg:'ET WEB_SPECIFIC Xoops SQL Injection Attempt -- group.php id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Xoops'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Xoops SQL Injection Attempt -- group.php id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005388) ET WEB_SPECIFIC Xoops SQL Injection Attempt -- table_broken.php lid +SecRule REQUEST_URI_RAW "(?i:\/class\/table_broken\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005388,rev:4,msg:'ET WEB_SPECIFIC Xoops SQL Injection Attempt -- table_broken.php lid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Xoops'" +SecRule &TX:'/SQL_INJECTION.*ARGS:lid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Xoops SQL Injection Attempt -- table_broken.php lid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006490) ET WEB_SPECIFIC Xoops SQL Injection Attempt -- print.php id +SecRule REQUEST_URI_RAW "(?i:\/print\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006490,rev:4,msg:'ET WEB_SPECIFIC Xoops SQL Injection Attempt -- print.php id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Xoops'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Xoops SQL Injection Attempt -- print.php id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006217) ET WEB_SPECIFIC Xt-News SQL Injection Attempt -- show_news.php id_news +SecRule REQUEST_URI_RAW "(?i:\/show_news\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006217,rev:4,msg:'ET WEB_SPECIFIC Xt-News SQL Injection Attempt -- show_news.php id_news ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Xt-News'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id_news/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Xt-News SQL Injection Attempt -- show_news.php id_news ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005613) ET WEB_SPECIFIC Xtreme ASP Photo Gallery SQL Injection Attempt -- displaypic.asp sortorder +SecRule REQUEST_URI_RAW "(?i:\/displaypic\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005613,rev:4,msg:'ET WEB_SPECIFIC Xtreme ASP Photo Gallery SQL Injection Attempt -- displaypic.asp sortorder ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Xtreme'" +SecRule &TX:'/SQL_INJECTION.*ARGS:sortorder/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Xtreme ASP Photo Gallery SQL Injection Attempt -- displaypic.asp sortorder ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004807) ET WEB_SPECIFIC Mathis Dirksen-Thedens ZephyrSoft Toolbox Address Book Continued (ABC) SQL Injection Attempt -- functions.php id +SecRule REQUEST_URI_RAW "(?i:\/functions\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004807,rev:4,msg:'ET WEB_SPECIFIC Mathis Dirksen-Thedens ZephyrSoft Toolbox Address Book Continued (ABC) SQL Injection Attempt -- functions.php id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_ZephyrSoft'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Mathis Dirksen-Thedens ZephyrSoft Toolbox Address Book Continued (ABC) SQL Injection Attempt -- functions.php id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005196) ET WEB_SPECIFIC Zindizayn Okul Web Sistemi SQL Injection Attempt -- mezungiris.asp id +SecRule REQUEST_URI_RAW "(?i:\/mezungiris\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005196,rev:4,msg:'ET WEB_SPECIFIC Zindizayn Okul Web Sistemi SQL Injection Attempt -- mezungiris.asp id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Zindizayn'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Zindizayn Okul Web Sistemi SQL Injection Attempt -- mezungiris.asp id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005202) ET WEB_SPECIFIC Zindizayn Okul Web Sistemi SQL Injection Attempt -- mezungiris.asp pass +SecRule REQUEST_URI_RAW "(?i:\/mezungiris\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005202,rev:4,msg:'ET WEB_SPECIFIC Zindizayn Okul Web Sistemi SQL Injection Attempt -- mezungiris.asp pass ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Zindizayn'" +SecRule &TX:'/SQL_INJECTION.*ARGS:pass/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Zindizayn Okul Web Sistemi SQL Injection Attempt -- mezungiris.asp pass ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005208) ET WEB_SPECIFIC Zindizayn Okul Web Sistemi SQL Injection Attempt -- ogretmenkontrol.asp pass +SecRule REQUEST_URI_RAW "(?i:\/ogretmenkontrol\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005208,rev:4,msg:'ET WEB_SPECIFIC Zindizayn Okul Web Sistemi SQL Injection Attempt -- ogretmenkontrol.asp pass ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Zindizayn'" +SecRule &TX:'/SQL_INJECTION.*ARGS:pass/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Zindizayn Okul Web Sistemi SQL Injection Attempt -- ogretmenkontrol.asp pass ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005214) ET WEB_SPECIFIC Zindizayn Okul Web Sistemi SQL Injection Attempt -- ogretmenkontrol.asp id +SecRule REQUEST_URI_RAW "(?i:\/ogretmenkontrol\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005214,rev:4,msg:'ET WEB_SPECIFIC Zindizayn Okul Web Sistemi SQL Injection Attempt -- ogretmenkontrol.asp id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Zindizayn'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Zindizayn Okul Web Sistemi SQL Injection Attempt -- ogretmenkontrol.asp id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2003985) ET WEB_SPECIFIC Zomplog SQL Injection Attempt -- mp3playlist.php speler +SecRule REQUEST_URI_RAW "(?i:\/plugins\/mp3playlist\/mp3playlist\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2003985,rev:4,msg:'ET WEB_SPECIFIC Zomplog SQL Injection Attempt -- mp3playlist.php speler ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_Zomplog'" +SecRule &TX:'/SQL_INJECTION.*ARGS:speler/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC Zomplog SQL Injection Attempt -- mp3playlist.php speler ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005983) ET WEB_SPECIFIC aFAQ SQL Injection Attempt -- faqDsp.asp catcode +SecRule REQUEST_URI_RAW "(?i:\/faqDsp\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005983,rev:4,msg:'ET WEB_SPECIFIC aFAQ SQL Injection Attempt -- faqDsp.asp catcode ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_aFAQ'" +SecRule &TX:'/SQL_INJECTION.*ARGS:catcode/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC aFAQ SQL Injection Attempt -- faqDsp.asp catcode ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005328) ET WEB_SPECIFIC bbPress SQL Injection Attempt -- formatting-functions.php +SecRule REQUEST_URI_RAW "(?i:\/bb\-includes\/formatting\-functions\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005328,rev:4,msg:'ET WEB_SPECIFIC bbPress SQL Injection Attempt -- formatting-functions.php ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_bbPress'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\(.+SELECT)" + +# (sid 2005770) ET WEB_SPECIFIC bitweaver SQL Injection Attempt -- edition.php tk +SecRule REQUEST_URI_RAW "(?i:\/newsletters\/edition\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005770,rev:4,msg:'ET WEB_SPECIFIC bitweaver SQL Injection Attempt -- edition.php tk ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_bitweaver'" +SecRule &TX:'/SQL_INJECTION.*ARGS:tk/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC bitweaver SQL Injection Attempt -- edition.php tk ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006175) ET WEB_SPECIFIC chatwm SQL Injection Attempt -- SelGruFra.asp txtUse +SecRule REQUEST_URI_RAW "(?i:\/SelGruFra\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006175,rev:4,msg:'ET WEB_SPECIFIC chatwm SQL Injection Attempt -- SelGruFra.asp txtUse ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_chatwm'" +SecRule &TX:'/SQL_INJECTION.*ARGS:txtUse/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC chatwm SQL Injection Attempt -- SelGruFra.asp txtUse ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006181) ET WEB_SPECIFIC chatwm SQL Injection Attempt -- SelGruFra.asp txtPas +SecRule REQUEST_URI_RAW "(?i:\/SelGruFra\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006181,rev:4,msg:'ET WEB_SPECIFIC chatwm SQL Injection Attempt -- SelGruFra.asp txtPas ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_chatwm'" +SecRule &TX:'/SQL_INJECTION.*ARGS:txtPas/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC chatwm SQL Injection Attempt -- SelGruFra.asp txtPas ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004057) ET WEB_SPECIFIC cpCommerce SQL Injection Attempt -- category.php id_category +SecRule REQUEST_URI_RAW "(?i:\/category\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004057,rev:4,msg:'ET WEB_SPECIFIC cpCommerce SQL Injection Attempt -- category.php id_category ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_cpCommerce'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id_category/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC cpCommerce SQL Injection Attempt -- category.php id_category ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004105) ET WEB_SPECIFIC cpCommerce SQL Injection Attempt -- manufacturer.php id_manufacturer +SecRule REQUEST_URI_RAW "(?i:\/manufacturer\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004105,rev:4,msg:'ET WEB_SPECIFIC cpCommerce SQL Injection Attempt -- manufacturer.php id_manufacturer ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_cpCommerce'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id_manufacturer/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC cpCommerce SQL Injection Attempt -- manufacturer.php id_manufacturer ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005037) ET WEB_SPECIFIC dB Masters Curium CMS SQL Injection Attempt -- news.php c_id +SecRule REQUEST_URI_RAW "(?i:\/news\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005037,rev:4,msg:'ET WEB_SPECIFIC dB Masters Curium CMS SQL Injection Attempt -- news.php c_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_dB_Masters'" +SecRule &TX:'/SQL_INJECTION.*ARGS:c_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC dB Masters Curium CMS SQL Injection Attempt -- news.php c_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006955) ET WEB_SPECIFIC dev4u CMS SQL Injection Attempt -- index.php seite_id +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006955,rev:4,msg:'ET WEB_SPECIFIC dev4u CMS SQL Injection Attempt -- index.php seite_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_dev4u'" +SecRule &TX:'/SQL_INJECTION.*ARGS:seite_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC dev4u CMS SQL Injection Attempt -- index.php seite_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006961) ET WEB_SPECIFIC dev4u CMS SQL Injection Attempt -- index.php gruppe_id +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006961,rev:4,msg:'ET WEB_SPECIFIC dev4u CMS SQL Injection Attempt -- index.php gruppe_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_dev4u'" +SecRule &TX:'/SQL_INJECTION.*ARGS:gruppe_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC dev4u CMS SQL Injection Attempt -- index.php gruppe_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006967) ET WEB_SPECIFIC dev4u CMS SQL Injection Attempt -- index.php go_target +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006967,rev:4,msg:'ET WEB_SPECIFIC dev4u CMS SQL Injection Attempt -- index.php go_target ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_dev4u'" +SecRule &TX:'/SQL_INJECTION.*ARGS:go_target/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC dev4u CMS SQL Injection Attempt -- index.php go_target ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006619) ET WEB_SPECIFIC dol storye SQL Injection Attempt -- dettaglio.asp id_doc +SecRule REQUEST_URI_RAW "(?i:\/dettaglio\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006619,rev:4,msg:'ET WEB_SPECIFIC dol storye SQL Injection Attempt -- dettaglio.asp id_doc ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_dol_storye'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id_doc/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC dol storye SQL Injection Attempt -- dettaglio.asp id_doc ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006625) ET WEB_SPECIFIC dol storye SQL Injection Attempt -- dettaglio.asp id_aut +SecRule REQUEST_URI_RAW "(?i:\/dettaglio\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006625,rev:4,msg:'ET WEB_SPECIFIC dol storye SQL Injection Attempt -- dettaglio.asp id_aut ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_dol_storye'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id_aut/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC dol storye SQL Injection Attempt -- dettaglio.asp id_aut ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005929) ET WEB_SPECIFIC eNdonesia SQL Injection Attempt -- mod.php did +SecRule REQUEST_URI_RAW "(?i:\/mod\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005929,rev:4,msg:'ET WEB_SPECIFIC eNdonesia SQL Injection Attempt -- mod.php did ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_eNdonesia'" +SecRule &TX:'/SQL_INJECTION.*ARGS:did/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC eNdonesia SQL Injection Attempt -- mod.php did ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005935) ET WEB_SPECIFIC eNdonesia SQL Injection Attempt -- mod.php cid +SecRule REQUEST_URI_RAW "(?i:\/mod\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005935,rev:4,msg:'ET WEB_SPECIFIC eNdonesia SQL Injection Attempt -- mod.php cid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_eNdonesia'" +SecRule &TX:'/SQL_INJECTION.*ARGS:cid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC eNdonesia SQL Injection Attempt -- mod.php cid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007378) ET WEB_SPECIFIC fipsGallery SQL Injection Attempt -- index1.asp which +SecRule REQUEST_URI_RAW "(?i:\/index1\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007378,rev:3,msg:'ET WEB_SPECIFIC fipsGallery SQL Injection Attempt -- index1.asp which ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_fips'" +SecRule &TX:'/SQL_INJECTION.*ARGS:which/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC fipsGallery SQL Injection Attempt -- index1.asp which ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007384) ET WEB_SPECIFIC fipsForum SQL Injection Attempt -- default2.asp kat +SecRule REQUEST_URI_RAW "(?i:\/default2\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007384,rev:3,msg:'ET WEB_SPECIFIC fipsForum SQL Injection Attempt -- default2.asp kat ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_fips'" +SecRule &TX:'/SQL_INJECTION.*ARGS:kat/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC fipsForum SQL Injection Attempt -- default2.asp kat ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2007390) ET WEB_SPECIFIC fipsCMS SQL Injection Attempt -- index.asp fid +SecRule REQUEST_URI_RAW "(?i:\/index\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2007390,rev:3,msg:'ET WEB_SPECIFIC fipsCMS SQL Injection Attempt -- index.asp fid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_fips'" +SecRule &TX:'/SQL_INJECTION.*ARGS:fid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC fipsCMS SQL Injection Attempt -- index.asp fid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004112) ET WEB_SPECIFIC gCards SQL Injection Attempt -- getnewsitem.php newsid +SecRule REQUEST_URI_RAW "(?i:\/getnewsitem\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004112,rev:4,msg:'ET WEB_SPECIFIC gCards SQL Injection Attempt -- getnewsitem.php newsid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_gCards'" +SecRule &TX:'/SQL_INJECTION.*ARGS:newsid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC gCards SQL Injection Attempt -- getnewsitem.php newsid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005809) ET WEB_SPECIFIC iGeneric iG Shop SQL Injection Attempt -- display_review.php id +SecRule REQUEST_URI_RAW "(?i:\/display_review\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005809,rev:4,msg:'ET WEB_SPECIFIC iGeneric iG Shop SQL Injection Attempt -- display_review.php id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_iGeneric'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC iGeneric iG Shop SQL Injection Attempt -- display_review.php id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005815) ET WEB_SPECIFIC iGeneric iG Shop SQL Injection Attempt -- display_review.php user_login_cookie +SecRule REQUEST_URI_RAW "(?i:\/display_review\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005815,rev:4,msg:'ET WEB_SPECIFIC iGeneric iG Shop SQL Injection Attempt -- display_review.php user_login_cookie ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_iGeneric'" +SecRule &TX:'/SQL_INJECTION.*ARGS:user_login_cookie/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC iGeneric iG Shop SQL Injection Attempt -- display_review.php user_login_cookie ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005821) ET WEB_SPECIFIC iGeneric iG Shop SQL Injection Attempt -- compare_product.php id +SecRule REQUEST_URI_RAW "(?i:\/compare_product\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005821,rev:4,msg:'ET WEB_SPECIFIC iGeneric iG Shop SQL Injection Attempt -- compare_product.php id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_iGeneric'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC iGeneric iG Shop SQL Injection Attempt -- compare_product.php id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005827) ET WEB_SPECIFIC iGeneric iG Calendar SQL Injection Attempt -- user.php id +SecRule REQUEST_URI_RAW "(?i:\/user\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005827,rev:4,msg:'ET WEB_SPECIFIC iGeneric iG Calendar SQL Injection Attempt -- user.php id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_iGeneric'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC iGeneric iG Calendar SQL Injection Attempt -- user.php id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2006613) ET WEB_SPECIFIC iWare Professional SQL Injection Attempt -- index.php D +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2006613,rev:4,msg:'ET WEB_SPECIFIC iWare Professional SQL Injection Attempt -- index.php D ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_iWare_Pro'" +SecRule &TX:'/SQL_INJECTION.*ARGS:D/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC iWare Professional SQL Injection Attempt -- index.php D ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004844) ET WEB_SPECIFIC mcRefer SQL Injection Attempt -- install.php bgcolor +SecRule REQUEST_URI_RAW "(?i:\/install\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004844,rev:4,msg:'ET WEB_SPECIFIC mcRefer SQL Injection Attempt -- install.php bgcolor ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_mcRefer'" +SecRule &TX:'/SQL_INJECTION.*ARGS:bgcolor/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC mcRefer SQL Injection Attempt -- install.php bgcolor ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004472) ET WEB_SPECIFIC myBloggie SQL Injection Attempt -- index.php cat_id +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004472,rev:4,msg:'ET WEB_SPECIFIC myBloggie SQL Injection Attempt -- index.php cat_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_myBloggie'" +SecRule &TX:'/SQL_INJECTION.*ARGS:cat_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC myBloggie SQL Injection Attempt -- index.php cat_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004478) ET WEB_SPECIFIC myBloggie SQL Injection Attempt -- index.php year +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004478,rev:4,msg:'ET WEB_SPECIFIC myBloggie SQL Injection Attempt -- index.php year ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_myBloggie'" +SecRule &TX:'/SQL_INJECTION.*ARGS:year/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC myBloggie SQL Injection Attempt -- index.php year ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004009) ET WEB_SPECIFIC ol\'bookmarks SQL Injection Attempt -- index.php id +SecRule REQUEST_URI_RAW "(?i:\/read\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004009,rev:4,msg:'ET WEB_SPECIFIC ol\'bookmarks SQL Injection Attempt -- index.php id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_olboolmarks'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC ol\'bookmarks SQL Injection Attempt -- index.php id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004903) ET WEB_SPECIFIC phpCC SQL Injection Attempt -- nickpage.php npid +SecRule REQUEST_URI_RAW "(?i:\/nickpage\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004903,rev:4,msg:'ET WEB_SPECIFIC phpCC SQL Injection Attempt -- nickpage.php npid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_phpCC'" +SecRule &TX:'/SQL_INJECTION.*ARGS:npid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC phpCC SQL Injection Attempt -- nickpage.php npid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004174) ET WEB_SPECIFIC phpx SQL Injection Attempt -- gallery.php image_id +SecRule REQUEST_URI_RAW "(?i:\/gallery\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004174,rev:4,msg:'ET WEB_SPECIFIC phpx SQL Injection Attempt -- gallery.php image_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_phpx'" +SecRule &TX:'/SQL_INJECTION.*ARGS:image_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC phpx SQL Injection Attempt -- gallery.php image_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004180) ET WEB_SPECIFIC phpx SQL Injection Attempt -- gallery.php cat_id +SecRule REQUEST_URI_RAW "(?i:\/gallery\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004180,rev:4,msg:'ET WEB_SPECIFIC phpx SQL Injection Attempt -- gallery.php cat_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_phpx'" +SecRule &TX:'/SQL_INJECTION.*ARGS:cat_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC phpx SQL Injection Attempt -- gallery.php cat_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004186) ET WEB_SPECIFIC phpx SQL Injection Attempt -- news.php news_id +SecRule REQUEST_URI_RAW "(?i:\/news\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004186,rev:4,msg:'ET WEB_SPECIFIC phpx SQL Injection Attempt -- news.php news_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_phpx'" +SecRule &TX:'/SQL_INJECTION.*ARGS:news_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC phpx SQL Injection Attempt -- news.php news_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004192) ET WEB_SPECIFIC phpx SQL Injection Attempt -- print.php news_id +SecRule REQUEST_URI_RAW "(?i:\/print\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004192,rev:4,msg:'ET WEB_SPECIFIC phpx SQL Injection Attempt -- print.php news_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_phpx'" +SecRule &TX:'/SQL_INJECTION.*ARGS:news_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC phpx SQL Injection Attempt -- print.php news_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004198) ET WEB_SPECIFIC phpx SQL Injection Attempt -- news.php news_cat_id +SecRule REQUEST_URI_RAW "(?i:\/news\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004198,rev:4,msg:'ET WEB_SPECIFIC phpx SQL Injection Attempt -- news.php news_cat_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_phpx'" +SecRule &TX:'/SQL_INJECTION.*ARGS:news_cat_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC phpx SQL Injection Attempt -- news.php news_cat_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004204) ET WEB_SPECIFIC phpx SQL Injection Attempt -- forums.php cat_id +SecRule REQUEST_URI_RAW "(?i:\/forums\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004204,rev:4,msg:'ET WEB_SPECIFIC phpx SQL Injection Attempt -- forums.php cat_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_phpx'" +SecRule &TX:'/SQL_INJECTION.*ARGS:cat_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC phpx SQL Injection Attempt -- forums.php cat_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004210) ET WEB_SPECIFIC phpx SQL Injection Attempt -- forums.php topic_id +SecRule REQUEST_URI_RAW "(?i:\/forums\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004210,rev:4,msg:'ET WEB_SPECIFIC phpx SQL Injection Attempt -- forums.php topic_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_phpx'" +SecRule &TX:'/SQL_INJECTION.*ARGS:topic_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC phpx SQL Injection Attempt -- forums.php topic_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004216) ET WEB_SPECIFIC phpx SQL Injection Attempt -- forums.php post_id +SecRule REQUEST_URI_RAW "(?i:\/forums\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004216,rev:4,msg:'ET WEB_SPECIFIC phpx SQL Injection Attempt -- forums.php post_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_phpx'" +SecRule &TX:'/SQL_INJECTION.*ARGS:post_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC phpx SQL Injection Attempt -- forums.php post_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004222) ET WEB_SPECIFIC phpx SQL Injection Attempt -- users.php user_id +SecRule REQUEST_URI_RAW "(?i:\/users\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004222,rev:4,msg:'ET WEB_SPECIFIC phpx SQL Injection Attempt -- users.php user_id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_phpx'" +SecRule &TX:'/SQL_INJECTION.*ARGS:user_id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC phpx SQL Injection Attempt -- users.php user_id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2003786) ET WEB_SPECIFIC pnFlashGames SQL Injection Attempt -- index.php cid +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2003786,rev:4,msg:'ET WEB_SPECIFIC pnFlashGames SQL Injection Attempt -- index.php cid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_pnFlashGames'" +SecRule REQUEST_URI_RAW "@contains (" "chain" +SecRule &TX:'/SQL_INJECTION.*ARGS:cid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC pnFlashGames SQL Injection Attempt -- index.php cid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005667) ET WEB_SPECIFIC uniForum SQL Injection Attempt -- wbsearch.aspx +SecRule REQUEST_URI_RAW "(?i:\/wbsearch\.aspx)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005667,rev:4,msg:'ET WEB_SPECIFIC uniForum SQL Injection Attempt -- wbsearch.aspx ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_uniForm'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\(.+SELECT)" + +# (sid 2005352) ET WEB_SPECIFIC vBSupport SQL Injection Attempt -- vBSupport.php +SecRule REQUEST_URI_RAW "(?i:\/vBSupport\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005352,rev:4,msg:'ET WEB_SPECIFIC vBSupport SQL Injection Attempt -- vBSupport.php ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_vBSupport'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\(.+SELECT)" + +# (sid 2005358) ET WEB_SPECIFIC vSupport Integrated Ticket System SQL Injection Attempt -- vBSupport.php ticketid +SecRule REQUEST_URI_RAW "(?i:\/vBSupport\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005358,rev:4,msg:'ET WEB_SPECIFIC vSupport Integrated Ticket System SQL Injection Attempt -- vBSupport.php ticketid ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_vSupport'" +SecRule &TX:'/SQL_INJECTION.*ARGS:ticketid/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC vSupport Integrated Ticket System SQL Injection Attempt -- vBSupport.php ticketid ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004752) ET WEB_SPECIFIC webSPELL SQL Injection Attempt -- printview.php topic +SecRule REQUEST_URI_RAW "(?i:\/printview\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004752,rev:4,msg:'ET WEB_SPECIFIC webSPELL SQL Injection Attempt -- printview.php topic ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_webSPELL'" +SecRule &TX:'/SQL_INJECTION.*ARGS:topic/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC webSPELL SQL Injection Attempt -- printview.php topic ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2004885) ET WEB_SPECIFIC webSPELL SQL Injection Attempt -- index.php showonly +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2004885,rev:4,msg:'ET WEB_SPECIFIC webSPELL SQL Injection Attempt -- index.php showonly ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_webSPELL'" +SecRule &TX:'/SQL_INJECTION.*ARGS:showonly/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC webSPELL SQL Injection Attempt -- index.php showonly ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005243) ET WEB_SPECIFIC webSPELL SQL Injection Attempt -- gallery.php picID +SecRule REQUEST_URI_RAW "(?i:\/gallery\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005243,rev:4,msg:'ET WEB_SPECIFIC webSPELL SQL Injection Attempt -- gallery.php picID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_webSPELL'" +SecRule &TX:'/SQL_INJECTION.*ARGS:picID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC webSPELL SQL Injection Attempt -- gallery.php picID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005249) ET WEB_SPECIFIC webSPELL SQL Injection Attempt -- gallery.php id +SecRule REQUEST_URI_RAW "(?i:\/gallery\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005249,rev:4,msg:'ET WEB_SPECIFIC webSPELL SQL Injection Attempt -- gallery.php id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_webSPELL'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC webSPELL SQL Injection Attempt -- gallery.php id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005254) ET WEB_SPECIFIC webSPELL SQL Injection Attempt -- gallery.php galleryID +SecRule REQUEST_URI_RAW "(?i:\/gallery\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005254,rev:4,msg:'ET WEB_SPECIFIC webSPELL SQL Injection Attempt -- gallery.php galleryID ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_webSPELL'" +SecRule &TX:'/SQL_INJECTION.*ARGS:galleryID/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC webSPELL SQL Injection Attempt -- gallery.php galleryID ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +# (sid 2005162) ET WEB_SPECIFIC xNews SQL Injection Attempt -- xNews.php id +SecRule REQUEST_URI_RAW "(?i:\/xNews\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,ctl:auditLogParts=+E,nolog,auditlog,logdata:'%{TX.0}',id:sid2005162,rev:4,msg:'ET WEB_SPECIFIC xNews SQL Injection Attempt -- xNews.php id ',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB_SQL_INJECTION/WEB_xNews'" +SecRule &TX:'/SQL_INJECTION.*ARGS:id/' "@gt 0" "setvar:'tx.msg=ET WEB_SPECIFIC xNews SQL Injection Attempt -- xNews.php id ',setvar:tx.sqli_score=+1,setvar:tx.anomaly_score=+20,setvar:tx.%{rule.id}-SQL_INJECTION/SQL_INJECTION-%{matched_var_name}=%{matched_var}" + +SecMarker END_ET_SQLI_RULES diff --git a/rules/base_rules/modsecurity_crs_46_et_web_rules.conf b/rules/base_rules/modsecurity_crs_46_et_web_rules.conf new file mode 100644 index 0000000..8f80408 --- /dev/null +++ b/rules/base_rules/modsecurity_crs_46_et_web_rules.conf @@ -0,0 +1,601 @@ +SecRule REQUEST_FILENAME "!@pmFromFile modsecurity_46_et_web_rules.data" "phase:2,nolog,pass,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,skipAfter:END_SNORT_RULES" + +# (sid 2003897) ET WEB Adobe RoboHelp XSS Attempt whstart.js +SecRule REQUEST_URI_RAW "(?i:\/whstart\.js)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2003897,rev:4,msg:'ET WEB Adobe RoboHelp XSS Attempt whstart.js',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Adobe'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:<?(java|vb)?script>?.*<.+\/script>?)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Adobe RoboHelp XSS Attempt whstart.js',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2003898) ET WEB Adobe RoboHelp XSS Attempt whcsh_home.htm +SecRule REQUEST_URI_RAW "(?i:\/whcsh_home\.htm)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2003898,rev:4,msg:'ET WEB Adobe RoboHelp XSS Attempt whcsh_home.htm',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Adobe'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:<?(java|vb)?script>?.*<.+\/script>?)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Adobe RoboHelp XSS Attempt whcsh_home.htm',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2003899) ET WEB Adobe RoboHelp XSS Attempt wf_startpage.js +SecRule REQUEST_URI_RAW "(?i:\/wf_startpage\.js)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2003899,rev:4,msg:'ET WEB Adobe RoboHelp XSS Attempt wf_startpage.js',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Adobe'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:<?(java|vb)?script>?.*<.+\/script>?)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Adobe RoboHelp XSS Attempt wf_startpage.js',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2003900) ET WEB Adobe RoboHelp XSS Attempt wf_startqs.htm +SecRule REQUEST_URI_RAW "(?i:\/wf_startqs\.htm)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2003900,rev:4,msg:'ET WEB Adobe RoboHelp XSS Attempt wf_startqs.htm',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Adobe'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:<?(java|vb)?script>?.*<.+\/script>?)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Adobe RoboHelp XSS Attempt wf_startqs.htm',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2003901) ET WEB Adobe RoboHelp XSS Attempt WindowManager.dll +SecRule REQUEST_URI_RAW "(?i:\/WindowManager\.dll)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2003901,rev:4,msg:'ET WEB Adobe RoboHelp XSS Attempt WindowManager.dll',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Adobe'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:<?(java|vb)?script>?.*<.+\/script>?)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Adobe RoboHelp XSS Attempt WindowManager.dll',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2001945) ET WEB WebAPP Apage.CGI Remote Command Execution Attempt +SecRule REQUEST_URI_RAW "(?i:\/apage\.cgi)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2001945,rev:6,msg:'ET WEB WebAPP Apage.CGI Remote Command Execution Attempt',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Apache.cgi'" +SecRule ARGS:f "(?i:(\.\|.+\|))" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB WebAPP Apage.CGI Remote Command Execution Attempt',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2001669) ET WEB Proxy GET Request +SecRule REQUEST_URI_RAW "@contains GET http\://" "phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2001669,rev:6,msg:'ET WEB Proxy GET Request',tag:'bad-unknown',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Apache_Open_Proxy',ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Proxy GET Request',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2001670) ET WEB Proxy HEAD Request +SecRule REQUEST_URI_RAW "@contains HEAD http\://" "phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2001670,rev:7,msg:'ET WEB Proxy HEAD Request',tag:'bad-unknown',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Apache_Open_Proxy',ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Proxy HEAD Request',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2001674) ET WEB Proxy POST Request +SecRule REQUEST_URI_RAW "@contains POST http\://" "phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2001674,rev:6,msg:'ET WEB Proxy POST Request',tag:'bad-unknown',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Apache_Open_Proxy',ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Proxy POST Request',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2001675) ET WEB Proxy CONNECT Request +SecRule REQUEST_URI_RAW "@contains CONNECT " "phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2001675,rev:6,msg:'ET WEB Proxy CONNECT Request',tag:'bad-unknown',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Apache_Open_Proxy',ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Proxy CONNECT Request',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2003156) ET WEB Crewbox Proxy Scan +SecRule REQUEST_URI_RAW "(?i:\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2003156,rev:3,msg:'ET WEB Crewbox Proxy Scan',tag:'attempted-recon',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Apache_Open_Proxy'" +SecRule REQUEST_URI_RAW "@contains crewbox.by.ru/crew/" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Crewbox Proxy Scan',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2002900) ET WEB CGI AWstats Migrate Command Attempt +SecRule REQUEST_URI_RAW "(?i:\/awstats\.pl)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2002900,rev:3,msg:'ET WEB CGI AWstats Migrate Command Attempt',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Awstats'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:migrate\s*=\s*\|)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB CGI AWstats Migrate Command Attempt',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2002711) ET WEB includer.cgi Remote Command Execution Attempt +SecRule REQUEST_URI_RAW "@contains /includer.cgi?|7c|" "phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2002711,rev:5,msg:'ET WEB includer.cgi Remote Command Execution Attempt',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_CGI',ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB includer.cgi Remote Command Execution Attempt',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2002129) ET WEB Cacti Input Validation Attack +SecRule REQUEST_URI_RAW "@contains GET " "chain,phase:2,pass,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2002129,rev:7,msg:'ET WEB Cacti Input Validation Attack',tag:'web-application-activity',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Cacti'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:(config_settings|top_graph_header)\.php\?.*=(http|https)\:\/)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Cacti Input Validation Attack',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2002313) ET WEB Cacti graph_image.php Remote Command Execution Attempt +SecRule REQUEST_URI_RAW "(?i:\/graph_image\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2002313,rev:6,msg:'ET WEB Cacti graph_image.php Remote Command Execution Attempt',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Cacti'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:(graph_start=%0a.+%0a))" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Cacti graph_image.php Remote Command Execution Attempt',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2003334) ET WEB Cacti cmd.php Remote Arbitrary SQL Command Execution Attempt +SecRule REQUEST_URI_RAW "(?i:\/cmd\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2003334,rev:3,msg:'ET WEB Cacti cmd.php Remote Arbitrary SQL Command Execution Attempt',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Cacti'" +SecRule REQUEST_URI_RAW "@contains UNION" "chain" +SecRule REQUEST_URI_RAW "@contains SELECT" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Cacti cmd.php Remote Arbitrary SQL Command Execution Attempt',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2007889) ET WEB Cacti SQL Injection Vulnerability graph_view graph_list UNION SELECT +SecRule REQUEST_URI_RAW "(?i:graph_view\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2007889,rev:3,msg:'ET WEB Cacti SQL Injection Vulnerability graph_view graph_list UNION SELECT',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Cacti'" +SecRule ARGS:graph_list "(?i:.+UNION\s+SELECT)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Cacti SQL Injection Vulnerability graph_view graph_list UNION SELECT',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2007890) ET WEB Cacti SQL Injection Vulnerability graph_view graph_list INSERT +SecRule REQUEST_URI_RAW "(?i:graph_view\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2007890,rev:3,msg:'ET WEB Cacti SQL Injection Vulnerability graph_view graph_list INSERT',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Cacti'" +SecRule ARGS:graph_list "(?i:.+INSERT.+INTO)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Cacti SQL Injection Vulnerability graph_view graph_list INSERT',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2007891) ET WEB Cacti SQL Injection Vulnerability graph_view graph_list DELETE +SecRule REQUEST_URI_RAW "(?i:graph_view\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2007891,rev:3,msg:'ET WEB Cacti SQL Injection Vulnerability graph_view graph_list DELETE',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Cacti'" +SecRule ARGS:graph_list "(?i:.+DELETE.+FROM)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Cacti SQL Injection Vulnerability graph_view graph_list DELETE',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2007892) ET WEB Cacti SQL Injection Vulnerability graph_view graph_list UPDATE +SecRule REQUEST_URI_RAW "(?i:graph_view\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2007892,rev:3,msg:'ET WEB Cacti SQL Injection Vulnerability graph_view graph_list UPDATE',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Cacti'" +SecRule ARGS:graph_list "(?i:.+UPDATE.+SET)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Cacti SQL Injection Vulnerability graph_view graph_list UPDATE',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2007893) ET WEB Cacti SQL Injection Vulnerability tree.php leaf_id SELECT +SecRule REQUEST_URI_RAW "(?i:tree\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2007893,rev:3,msg:'ET WEB Cacti SQL Injection Vulnerability tree.php leaf_id SELECT',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Cacti'" +SecRule ARGS:leaf_id "(?i:.+SELECT.+FROM)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Cacti SQL Injection Vulnerability tree.php leaf_id SELECT',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2007894) ET WEB Cacti SQL Injection Vulnerability tree.php leaf_id UNION SELECT +SecRule REQUEST_URI_RAW "(?i:tree\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2007894,rev:3,msg:'ET WEB Cacti SQL Injection Vulnerability tree.php leaf_id UNION SELECT',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Cacti'" +SecRule ARGS:leaf_id "(?i:.+UNION\s+SELECT)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Cacti SQL Injection Vulnerability tree.php leaf_id UNION SELECT',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2007895) ET WEB Cacti SQL Injection Vulnerability tree.php leaf_id INSERT +SecRule REQUEST_URI_RAW "(?i:tree\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2007895,rev:3,msg:'ET WEB Cacti SQL Injection Vulnerability tree.php leaf_id INSERT',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Cacti'" +SecRule ARGS:leaf_id "(?i:.+INSERT.+INTO)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Cacti SQL Injection Vulnerability tree.php leaf_id INSERT',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2007896) ET WEB Cacti SQL Injection Vulnerability tree.php leaf_id DELETE +SecRule REQUEST_URI_RAW "(?i:tree\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2007896,rev:3,msg:'ET WEB Cacti SQL Injection Vulnerability tree.php leaf_id DELETE',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Cacti'" +SecRule ARGS:leaf_id "(?i:.+DELETE.+FROM)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Cacti SQL Injection Vulnerability tree.php leaf_id DELETE',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2007897) ET WEB Cacti SQL Injection Vulnerability tree.php leaf_id UPDATE +SecRule REQUEST_URI_RAW "(?i:tree\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2007897,rev:3,msg:'ET WEB Cacti SQL Injection Vulnerability tree.php leaf_id UPDATE',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Cacti'" +SecRule ARGS:leaf_id "(?i:.+UPDATE.+SET)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Cacti SQL Injection Vulnerability tree.php leaf_id UPDATE',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2004556) ET WEB Cisco CallManager XSS Attempt serverlist.asp pattern +SecRule REQUEST_URI_RAW "(?i:\/CCMAdmin\/serverlist\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2004556,rev:4,msg:'ET WEB Cisco CallManager XSS Attempt serverlist.asp pattern',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Cisco'" +SecRule ARGS:pattern "(?i:.*<?(java|vb)?script>?.*<.+\/script>?)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Cisco CallManager XSS Attempt serverlist.asp pattern',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2002376) ET WEB IBM Lotus Domino BaseTarget XSS attempt +SecRule REQUEST_URI_RAW "@contains OpenForm" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2002376,rev:7,msg:'ET WEB IBM Lotus Domino BaseTarget XSS attempt',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Domino_XSS'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:BaseTarget=.*?\x22)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB IBM Lotus Domino BaseTarget XSS attempt',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2002377) ET WEB IBM Lotus Domino Src XSS attempt +SecRule REQUEST_URI_RAW "@contains OpenFrameSet" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2002377,rev:6,msg:'ET WEB IBM Lotus Domino Src XSS attempt',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Domino_XSS'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:src=.*\x22><\/FRAMESET>.*<script>.*<\/script>)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB IBM Lotus Domino Src XSS attempt',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2009361) ET WEB cmd.exe In URI - Possible Command Execution Attempt +SecRule REQUEST_URI_RAW "(?i:\/cmd\.exe)" "phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2009361,rev:2,msg:'ET WEB cmd.exe In URI - Possible Command Execution Attempt',tag:'attempted-recon',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_General',ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB cmd.exe In URI - Possible Command Execution Attempt',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2009362) ET WEB /system32/ in Uri - Possible Protected Directory Access Attempt +SecRule REQUEST_URI_RAW "@contains /system32/" "phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2009362,rev:2,msg:'ET WEB /system32/ in Uri - Possible Protected Directory Access Attempt',tag:'attempted-recon',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_General',ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB /system32/ in Uri - Possible Protected Directory Access Attempt',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2009363) ET WEB Suspicious Chmod Usage in URI +SecRule QUERY_STRING|REQUEST_BODY "(?i:chmod.([r|w|x|1-7]))" "phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2009363,rev:2,msg:'ET WEB Suspicious Chmod Usage in URI',tag:'attempted-admin',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_General',ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Suspicious Chmod Usage in URI',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2008171) ET WEB HP OpenView Network Node Manager CGI Directory Traversal +SecRule REQUEST_URI_RAW "(?i:\/OpenView5\.exe)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2008171,rev:2,msg:'ET WEB HP OpenView Network Node Manager CGI Directory Traversal',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_HP_Openview'" +SecRule REQUEST_URI_RAW "@contains GET " "chain" +SecRule REQUEST_URI_RAW "@contains /OvCgi/" "chain" +SecRule QUERY_STRING|REQUEST_BODY "@contains Action=../../" "chain" +SecRule QUERY_STRING|REQUEST_BODY "@contains HTTP/1" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB HP OpenView Network Node Manager CGI Directory Traversal',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2002897) ET WEB Horde README access probe +SecRule REQUEST_URI_RAW "@contains /horde" "chain,phase:2,pass,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2002897,rev:5,msg:'ET WEB Horde README access probe',tag:'web-application-activity',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Horde'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\/horde((2|3|-3\.(0\.[1-9]|1\.0)))?\/{1,2}README)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Horde README access probe',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2001365) ET WEB-MISC Alternate Data Stream source view attempt +SecRule REQUEST_URI_RAW "@contains |3A 3A|$DATA" "phase:2,pass,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2001365,rev:8,msg:'ET WEB-MISC Alternate Data Stream source view attempt',tag:'web-application-activity',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_IIS_ADS_Source_Code_Exposure',ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB-MISC Alternate Data Stream source view attempt',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2001342) ET WEB IIS ASP.net Auth Bypass / Canonicalization +SecRule REQUEST_URI_RAW "(?i:\.aspx)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2001342,rev:21,msg:'ET WEB IIS ASP.net Auth Bypass / Canonicalization',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_IIS_Canonicalization_Bypass'" +SecRule QUERY_STRING|REQUEST_BODY "@contains GET" "chain" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\\x5C)" "chain" +SecRule QUERY_STRING|REQUEST_BODY "@contains aspx" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB IIS ASP.net Auth Bypass / Canonicalization',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2001343) ET WEB IIS ASP.net Auth Bypass / Canonicalization % 5 C +SecRule REQUEST_URI_RAW "(?i:\.aspx)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2001343,rev:19,msg:'ET WEB IIS ASP.net Auth Bypass / Canonicalization % 5 C',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_IIS_Canonicalization_Bypass'" +SecRule QUERY_STRING|REQUEST_BODY "@contains GET" "chain" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\\x5C)" "chain" +SecRule QUERY_STRING|REQUEST_BODY "@contains aspx" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB IIS ASP.net Auth Bypass / Canonicalization % 5 C',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2009510) ET WEB Sun Java System Web Server .jsp Source Code Disclosure Attempt +SecRule REQUEST_URI_RAW "@contains .jsp\:\:$DATA" "phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2009510,rev:2,msg:'ET WEB Sun Java System Web Server .jsp Source Code Disclosure Attempt',tag:'attempted-recon',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Java',ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Sun Java System Web Server .jsp Source Code Disclosure Attempt',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2001546) ET WEB-MISC LINK Method +SecRule QUERY_STRING|REQUEST_BODY "@contains LINK " "phase:2,pass,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2001546,rev:7,msg:'ET WEB-MISC LINK Method',tag:'web-application-activity',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_LINK_Method',ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB-MISC LINK Method',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2002777) ET WEB Light Weight Calendar 'date' Arbitrary Remote Code Execution +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2002777,rev:3,msg:'ET WEB Light Weight Calendar \'date\' Arbitrary Remote Code Execution',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Light_Weight_Calendar'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:date=\d{8}\)\;.+)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Light Weight Calendar \'date\' Arbitrary Remote Code Execution',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2001075) ET WEB-MISC cross site scripting attempt IMG onerror or onload +SecRule QUERY_STRING|REQUEST_BODY "@contains <IMG" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2001075,rev:5,msg:'ET WEB-MISC cross site scripting attempt IMG onerror or onload',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Misc_CSS'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\bonerror\b[\s]*=)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB-MISC cross site scripting attempt IMG onerror or onload',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2001077) ET WEB-MISC cross site scripting attempt STYLE + JAVASCRIPT +SecRule QUERY_STRING|REQUEST_BODY "@contains application/x-javascript" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2001077,rev:7,msg:'ET WEB-MISC cross site scripting attempt STYLE + JAVASCRIPT',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Misc_CSS'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:TYPE\s*=\s*['\x22]application\/x-javascript)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB-MISC cross site scripting attempt STYLE + JAVASCRIPT',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2001078) ET WEB-MISC cross site scripting attempt STYLE + JSCRIPT +SecRule QUERY_STRING|REQUEST_BODY "@contains text/jscript" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2001078,rev:7,msg:'ET WEB-MISC cross site scripting attempt STYLE + JSCRIPT',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Misc_CSS'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:TYPE\s*=\s*['\x22]text\/jscript)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB-MISC cross site scripting attempt STYLE + JSCRIPT',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2001079) ET WEB-MISC cross site scripting attempt STYLE + VBSCRIPT 1 +SecRule QUERY_STRING|REQUEST_BODY "@contains text/vbscript" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2001079,rev:8,msg:'ET WEB-MISC cross site scripting attempt STYLE + VBSCRIPT 1',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Misc_CSS'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:TYPE\s*=\s*['\x22]text\/vbscript)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB-MISC cross site scripting attempt STYLE + VBSCRIPT 1',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2001080) ET WEB-MISC cross site scripting attempt STYLE + VBSCRIPT 2 +SecRule QUERY_STRING|REQUEST_BODY "@contains application/x-vbscript" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2001080,rev:8,msg:'ET WEB-MISC cross site scripting attempt STYLE + VBSCRIPT 2',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Misc_CSS'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:TYPE\s*=\s*['\x22]application\/x-vbscript)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB-MISC cross site scripting attempt STYLE + VBSCRIPT 2',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2001081) ET WEB-MISC cross site scripting attempt STYLE + ECMACRIPT +SecRule QUERY_STRING|REQUEST_BODY "@contains text/ecmascript" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2001081,rev:7,msg:'ET WEB-MISC cross site scripting attempt STYLE + ECMACRIPT',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Misc_CSS'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:TYPE\s*=\s*['\x22]text\/ecmascript)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB-MISC cross site scripting attempt STYLE + ECMACRIPT',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2001082) ET WEB-MISC cross site scripting attempt STYLE + EXPRESSION 1 +SecRule QUERY_STRING|REQUEST_BODY "@contains expression" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2001082,rev:7,msg:'ET WEB-MISC cross site scripting attempt STYLE + EXPRESSION 1',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Misc_CSS'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:STYLE[\s]*=[\s]*[^>]expression[\s]*\()" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB-MISC cross site scripting attempt STYLE + EXPRESSION 1',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2001083) ET WEB-MISC cross site scripting attempt STYLE + EXPRESSION 2 +SecRule QUERY_STRING|REQUEST_BODY "@contains expression" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2001083,rev:7,msg:'ET WEB-MISC cross site scripting attempt STYLE + EXPRESSION 2',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Misc_CSS'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:[\s]*expression[\s]*\([^}]}[\s]*<\/STYLE>)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB-MISC cross site scripting attempt STYLE + EXPRESSION 2',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2001084) ET WEB-MISC cross site scripting attempt using XML +SecRule QUERY_STRING|REQUEST_BODY "@contains <XML" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2001084,rev:5,msg:'ET WEB-MISC cross site scripting attempt using XML',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Misc_CSS'" +SecRule QUERY_STRING|REQUEST_BODY "@contains <![CDATA[<]]>SCRIPT" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB-MISC cross site scripting attempt using XML',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2001085) ET WEB-MISC cross site scripting attempt executing hidden Javascript 1 +SecRule QUERY_STRING|REQUEST_BODY "@contains innerhtml" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2001085,rev:7,msg:'ET WEB-MISC cross site scripting attempt executing hidden Javascript 1',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Misc_CSS'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:eval[\s]*\([\s]*[^\.]\.innerHTML[\s]*\))" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB-MISC cross site scripting attempt executing hidden Javascript 1',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2001086) ET WEB-MISC cross site scripting attempt executing hidden Javascript 2 +SecRule QUERY_STRING|REQUEST_BODY "@contains window.execscript" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2001086,rev:7,msg:'ET WEB-MISC cross site scripting attempt executing hidden Javascript 2',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Misc_CSS'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:window.execScript[\s]*\()" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB-MISC cross site scripting attempt executing hidden Javascript 2',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2001087) ET WEB-MISC cross site scripting attempt to execute Javascript code +SecRule QUERY_STRING|REQUEST_BODY "@contains javascript" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2001087,rev:6,msg:'ET WEB-MISC cross site scripting attempt to execute Javascript code',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Misc_CSS'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:(((URL|SRC|HREF|LOWSRC)[\s]*=)|(url[\s]*[\(]))[\s]*['\x22]*javascript[\:])" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB-MISC cross site scripting attempt to execute Javascript code',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2001088) ET WEB-MISC cross site scripting attempt to execute VBScript code +SecRule QUERY_STRING|REQUEST_BODY "@contains vbscript" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2001088,rev:6,msg:'ET WEB-MISC cross site scripting attempt to execute VBScript code',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Misc_CSS'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:(((URL|SRC|HREF|LOWSRC)[\s]*=)|(url[\s]*[\(]))[\s]*['\x22]*vbscript[\:])" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB-MISC cross site scripting attempt to execute VBScript code',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2001089) ET WEB-MISC cross site scripting attempt to access SHELL\: +SecRule QUERY_STRING|REQUEST_BODY "@contains shell" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2001089,rev:6,msg:'ET WEB-MISC cross site scripting attempt to access SHELL:',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Misc_CSS'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:(((URL|SRC|HREF|LOWSRC)[\s]*=)|(url[\s]*[\(]))[\s]*['\x22]*shell[\:])" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB-MISC cross site scripting attempt to access SHELL:',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2001090) ET WEB-MISC cross site scripting stealth attempt to execute Javascript code +SecRule QUERY_STRING|REQUEST_BODY "@contains =" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2001090,rev:7,msg:'ET WEB-MISC cross site scripting stealth attempt to execute Javascript code',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Misc_CSS'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:(((URL|SRC|HREF|LOWSRC)[\s]*=)|(url[\s]*[\(]))[\s]*['\x22]*[\x09\x0a\x0b\x0c\x0d]*j[\x09\x0a\x0b\x0c\x0d]*a[\x09\x0a\x0b\x0c\x0d]*v[\x09\x0a\x0b\x0c\x0d]*a[\x09\x0a\x0b\x0c\x0d]*s[\x09\x0a\x0b\x0c\x0d]*c[\x09\x0a\x0b\x0c\x0d]*r[\x09\x0a\x0b\x0c\x0d]*i[\x09\x0a\x0b\x0c\x0d]*p[\x09\x0a\x0b\x0c\x0d]*t[\x09\x0a\x0b\x0c\x0d]*[\:])" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB-MISC cross site scripting stealth attempt to execute Javascript code',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2001091) ET WEB-MISC cross site scripting stealth attempt to execute VBScript code +SecRule QUERY_STRING|REQUEST_BODY "@contains =" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2001091,rev:7,msg:'ET WEB-MISC cross site scripting stealth attempt to execute VBScript code',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Misc_CSS'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:(((URL|SRC|HREF|LOWSRC)[\s]*=)|(url[\s]*[\(]))[\s]*['\x22]*[\x09\x0a\x0b\x0c\x0d]*v[\x09\x0a\x0b\x0c\x0d]*b[\x09\x0a\x0b\x0c\x0d]*s[\x09\x0a\x0b\x0c\x0d]*c[\x09\x0a\x0b\x0c\x0d]*r[\x09\x0a\x0b\x0c\x0d]*i[\x09\x0a\x0b\x0c\x0d]*p[\x09\x0a\x0b\x0c\x0d]*t[\x09\x0a\x0b\x0c\x0d]*[\:])" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB-MISC cross site scripting stealth attempt to execute VBScript code',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2001092) ET WEB-MISC cross site scripting stealth attempt to access SHELL\: +SecRule QUERY_STRING|REQUEST_BODY "(?i:(((URL|SRC|HREF|LOWSRC)[\s]*=)|(url[\s]*[\(]))[\s]*['\x22]*[\x09\x0a\x0b\x0c\x0d]*s[\x09\x0a\x0b\x0c\x0d]*h[\x09\x0a\x0b\x0c\x0d]*e[\x09\x0a\x0b\x0c\x0d]*l[\x09\x0a\x0b\x0c\x0d]*l[\x09\x0a\x0b\x0c\x0d]*[\:])" "phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2001092,rev:8,msg:'ET WEB-MISC cross site scripting stealth attempt to access SHELL:',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Misc_CSS',ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB-MISC cross site scripting stealth attempt to access SHELL:',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2002361) ET WEB Netquery Remote Command Execution Attempt +SecRule REQUEST_URI_RAW "(?i:\/nquser\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2002361,rev:4,msg:'ET WEB Netquery Remote Command Execution Attempt',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Netquery'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:(host=\|.+))" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Netquery Remote Command Execution Attempt',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2007936) ET WEB Netwin Webmail SurgeMail Mail Server Format String Vulnerability +SecRule REQUEST_URI_RAW "(?i:webmail\.exe)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2007936,rev:4,msg:'ET WEB Netwin Webmail SurgeMail Mail Server Format String Vulnerability',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Netwin'" +SecRule QUERY_STRING|REQUEST_BODY "@contains GET" "chain" +SecRule QUERY_STRING|REQUEST_BODY "(?i:[%n%s]{2,})" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Netwin Webmail SurgeMail Mail Server Format String Vulnerability',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2002997) ET WEB PHP Remote File Inclusion (monster list http) +SecRule REQUEST_URI_RAW "(?i:\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2002997,rev:4,msg:'ET WEB PHP Remote File Inclusion (monster list http)',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_PHP'" +SecRule REQUEST_URI_RAW "@contains http" "chain" +SecRule QUERY_STRING|REQUEST_BODY "(?i:(path|page|lib|dir|file|root|icon|lang(uage)?|folder|type|agenda|gallery|domain|calendar|settings|news|name|auth|prog|config|cfg|incl|ext|fad|mod|sbp|rf|id|df|[a-z](\[.*\])+)\s*=\s*https?)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB PHP Remote File Inclusion (monster list http)',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2003098) ET WEB PHP Remote File Inclusion (monster list ftp) +SecRule REQUEST_URI_RAW "(?i:\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2003098,rev:4,msg:'ET WEB PHP Remote File Inclusion (monster list ftp)',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_PHP'" +SecRule REQUEST_URI_RAW "@contains ftp\:" "chain" +SecRule QUERY_STRING|REQUEST_BODY "(?i:(path|page|lib|dir|file|root|icon|lang(uage)?|folder|type|agenda|gallery|domain|calendar|settings|news|name|auth|prog|config|cfg|incl|ext|fad|mod|sbp|rf|id|df|[a-z](\[.*\])+)\s*=\s*ftp)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB PHP Remote File Inclusion (monster list ftp)',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2003935) ET WEB PHP Remote File Inclusion (monster list php) +SecRule REQUEST_URI_RAW "(?i:\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2003935,rev:3,msg:'ET WEB PHP Remote File Inclusion (monster list php)',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_PHP'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:(path|page|lib|dir|file|root|icon|lang(uage)?|folder|type|agenda|gallery|domain|calendar|settings|news|name|auth|prog|config|cfg|incl|ext|fad|mod|sbp|rf|id|df|[a-z](\[.*\])+)\s*=\s*php)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB PHP Remote File Inclusion (monster list php)',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2002730) ET WEB PHPGedView Remote Script Code Execution attempt +SecRule REQUEST_URI_RAW "(?i:\/help_text_vars\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2002730,rev:6,msg:'ET WEB PHPGedView Remote Script Code Execution attempt',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_PHPGedView'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:PGV_BASE_DIRECTORY=(f|ht)tp\:\/)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB PHPGedView Remote Script Code Execution attempt',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2002314) ET WEB PHPOutsourcing Zorum prod.php Remote Command Execution Attempt +SecRule REQUEST_URI_RAW "(?i:\/prod\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2002314,rev:5,msg:'ET WEB PHPOutsourcing Zorum prod.php Remote Command Execution Attempt',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_PHPOutsourcing'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:(argv[1]=\|.+))" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB PHPOutsourcing Zorum prod.php Remote Command Execution Attempt',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2001344) ET WEB PHP EasyDynamicPages exploit +SecRule ARGS_NAMES "(?i:edp_relative_path)" "phase:2,pass,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2001344,rev:7,msg:'ET WEB PHP EasyDynamicPages exploit',tag:'web-application-activity',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_PHP_EasyDynamicPages_Exploit',ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB PHP EasyDynamicPages exploit',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2009336) ET WEB Possible Web Backdoor cfexec.cfm access +SecRule REQUEST_URI_RAW "(?i:\/cfexec\.cfm)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2009336,rev:2,msg:'ET WEB Possible Web Backdoor cfexec.cfm access',tag:'trojan-activity',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_PHP_Shells'" +SecRule REQUEST_URI_RAW "@contains GET " "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Possible Web Backdoor cfexec.cfm access',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2009337) ET WEB Possible Web Backdoor cmdasp.asp access +SecRule REQUEST_URI_RAW "(?i:\/cmdasp\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2009337,rev:2,msg:'ET WEB Possible Web Backdoor cmdasp.asp access',tag:'trojan-activity',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_PHP_Shells'" +SecRule REQUEST_URI_RAW "@contains GET " "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Possible Web Backdoor cmdasp.asp access',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2009338) ET WEB Possible Web Backdoor cmdasp.aspx access +SecRule REQUEST_URI_RAW "(?i:\/cmdasp\.aspx)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2009338,rev:2,msg:'ET WEB Possible Web Backdoor cmdasp.aspx access',tag:'trojan-activity',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_PHP_Shells'" +SecRule REQUEST_URI_RAW "@contains GET " "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Possible Web Backdoor cmdasp.aspx access',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2009339) ET WEB Possible Web Backdoor simple-backdoor.php access +SecRule REQUEST_URI_RAW "(?i:\/simple\-backdoor\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2009339,rev:2,msg:'ET WEB Possible Web Backdoor simple-backdoor.php access',tag:'trojan-activity',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_PHP_Shells'" +SecRule REQUEST_URI_RAW "@contains GET " "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Possible Web Backdoor simple-backdoor.php access',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2009340) ET WEB Possible Web Backdoor php-backdoor.php access +SecRule REQUEST_URI_RAW "(?i:\/php\-backdoor\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2009340,rev:2,msg:'ET WEB Possible Web Backdoor php-backdoor.php access',tag:'trojan-activity',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_PHP_Shells'" +SecRule REQUEST_URI_RAW "@contains GET " "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Possible Web Backdoor php-backdoor.php access',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2009341) ET WEB Possible Web Backdoor jsp-reverse.jsp access +SecRule REQUEST_URI_RAW "(?i:\/jsp\-reverse\.jsp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2009341,rev:2,msg:'ET WEB Possible Web Backdoor jsp-reverse.jsp access',tag:'trojan-activity',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_PHP_Shells'" +SecRule REQUEST_URI_RAW "@contains GET " "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Possible Web Backdoor jsp-reverse.jsp access',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2009342) ET WEB Possible Web Backdoor perlcmd.cgi access +SecRule REQUEST_URI_RAW "(?i:\/perlcmd\.cgi)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2009342,rev:2,msg:'ET WEB Possible Web Backdoor perlcmd.cgi access',tag:'trojan-activity',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_PHP_Shells'" +SecRule REQUEST_URI_RAW "@contains GET " "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Possible Web Backdoor perlcmd.cgi access',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2009343) ET WEB Possible Web Backdoor cmdjsp.jsp access +SecRule REQUEST_URI_RAW "(?i:\/cmdjsp\.jsp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2009343,rev:2,msg:'ET WEB Possible Web Backdoor cmdjsp.jsp access',tag:'trojan-activity',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_PHP_Shells'" +SecRule REQUEST_URI_RAW "@contains GET " "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Possible Web Backdoor cmdjsp.jsp access',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2009344) ET WEB Possible Web Backdoor cmd-asp-5.1.asp access +SecRule REQUEST_URI_RAW "(?i:\/cmd\-asp\-5\.1\.asp)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2009344,rev:2,msg:'ET WEB Possible Web Backdoor cmd-asp-5.1.asp access',tag:'trojan-activity',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_PHP_Shells'" +SecRule REQUEST_URI_RAW "@contains GET " "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Possible Web Backdoor cmd-asp-5.1.asp access',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2002972) ET WEB PHP ZeroBoard .htaccess upload +SecRule QUERY_STRING|REQUEST_BODY "@contains filename=" "chain,phase:2,pass,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2002972,rev:3,msg:'ET WEB PHP ZeroBoard .htaccess upload',tag:'web-application-activity',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_PHP_ZeroBoard'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:^\s*\.htaccess)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB PHP ZeroBoard .htaccess upload',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2001738) ET WEB PHP vBulletin Remote Command Execution Attempt +SecRule REQUEST_URI_RAW "(?i:forumdisplay\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2001738,rev:9,msg:'ET WEB PHP vBulletin Remote Command Execution Attempt',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_PHP_vBulletin'" +SecRule ARGS:comma "(?i:(\.system\(.+\)\.))" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB PHP vBulletin Remote Command Execution Attempt',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2002388) ET WEB vBulletin misc.php Template Name Arbitrary Code Execution +SecRule REQUEST_URI_RAW "(?i:\/misc\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2002388,rev:5,msg:'ET WEB vBulletin misc.php Template Name Arbitrary Code Execution',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_PHP_vBulletin'" +SecRule REQUEST_URI_RAW "@contains &template=.*{${" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB vBulletin misc.php Template Name Arbitrary Code Execution',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2002837) ET WEB PmWiki Globals Variables Overwrite Attempt +SecRule REQUEST_URI_RAW "(?i:\/pmwiki\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2002837,rev:3,msg:'ET WEB PmWiki Globals Variables Overwrite Attempt',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_PMWiki'" +SecRule QUERY_STRING|REQUEST_BODY "@contains GLOBALS[FarmD]=" "chain" +SecRule QUERY_STRING|REQUEST_BODY "(?i:GLOBALS\x5bFarmD\x5d\x3d)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB PmWiki Globals Variables Overwrite Attempt',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2008687) ET WEB PassWiki site_id Parameter Local File Inclusion +SecRule REQUEST_URI_RAW "(?i:\/passwiki\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2008687,rev:2,msg:'ET WEB PassWiki site_id Parameter Local File Inclusion',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_PassWiki'" +SecRule REQUEST_URI_RAW "@contains GET " "chain" +SecRule ARGS:site_id "(?i:(\.\.\/){1,})" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB PassWiki site_id Parameter Local File Inclusion',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2007871) ET WEB Philips VOIP841 Web Server Directory Traversal +SecRule REQUEST_URI_RAW "@contains GET " "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2007871,rev:2,msg:'ET WEB Philips VOIP841 Web Server Directory Traversal',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Philips_VOIP'" +SecRule REQUEST_URI_RAW "@contains /etc/passwd" "chain" +SecRule QUERY_STRING|REQUEST_BODY "(?i:(\.\.\/){1,})" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Philips VOIP841 Web Server Directory Traversal',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2002331) ET WEB Piranha default passwd attempt +SecRule REQUEST_URI_RAW "(?i:\/piranha\/secure\/control\.php3)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2002331,rev:3,msg:'ET WEB Piranha default passwd attempt',tag:'attempted-recon',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Piranha'" +SecRule QUERY_STRING|REQUEST_BODY "@contains Authorization\: Basic cGlyYW5oYTp" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Piranha default passwd attempt',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2008622) ET WEB Pritlog index.php filename File Disclosure +SecRule REQUEST_URI_RAW "@contains GET " "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2008622,rev:2,msg:'ET WEB Pritlog index.php filename File Disclosure',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Pritlog'" +SecRule REQUEST_URI_RAW "@contains /index.php?option=viewEntry" "chain" +SecRule ARGS:&filename "(?i:(\.\.\/){1,})" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Pritlog index.php filename File Disclosure',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2009152) ET WEB PHP Generic Remote File Include Attempt (HTTPS) +SecRule REQUEST_URI_RAW "(?i:\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2009152,rev:4,msg:'ET WEB PHP Generic Remote File Include Attempt (HTTPS)',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_RFI_Generic'" +SecRule REQUEST_URI_RAW "@contains =https\:/" "chain" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\x2Ephp\x3F.{0,300}\x3Dhttps\x3A\x2F[^\x3F\x26]+\x3F)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB PHP Generic Remote File Include Attempt (HTTPS)',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2009153) ET WEB PHP Generic Remote File Include Attempt (FTP) +SecRule REQUEST_URI_RAW "(?i:\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2009153,rev:4,msg:'ET WEB PHP Generic Remote File Include Attempt (FTP)',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_RFI_Generic'" +SecRule REQUEST_URI_RAW "@contains =ftp\:/" "chain" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\x2Ephp\x3F.{0,300}\x3Dftp\x3A\x2F[^\x3F\x26]+\x3F)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB PHP Generic Remote File Include Attempt (FTP)',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2009155) ET WEB PHP Generic Remote File Include Attempt (FTPS) +SecRule REQUEST_URI_RAW "(?i:\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2009155,rev:5,msg:'ET WEB PHP Generic Remote File Include Attempt (FTPS)',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_RFI_Generic'" +SecRule REQUEST_URI_RAW "@contains =ftps\:/" "chain" +SecRule QUERY_STRING|REQUEST_BODY "(?i:\x2Ephp\x3F.{0,300}\x3Dftp\x3A\x2F[^\x3F\x26]+\x3F)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB PHP Generic Remote File Include Attempt (FTPS)',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2002660) ET WEB RSA Web Auth Exploit Attempt - Long URL +SecRule REQUEST_URI_RAW "(?i:\?Redirect)" "chain,phase:2,pass,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2002660,rev:5,msg:'ET WEB RSA Web Auth Exploit Attempt - Long URL',tag:'web-application-activity',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_RSA'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:url=.{8000})" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB RSA Web Auth Exploit Attempt - Long URL',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2006443) ET WEB Possible SQL Injection Attempt DELETE FROM +SecRule REQUEST_URI_RAW "@contains DELETE " "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2006443,rev:6,msg:'ET WEB Possible SQL Injection Attempt DELETE FROM',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_SQL_Injection_Monster_List'" +SecRule REQUEST_URI_RAW "@contains FROM " "chain" +SecRule QUERY_STRING|REQUEST_BODY "(?i:DELETE.+FROM)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Possible SQL Injection Attempt DELETE FROM',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2006444) ET WEB Possible SQL Injection Attempt INSERT INTO +SecRule REQUEST_URI_RAW "@contains INSERT " "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2006444,rev:6,msg:'ET WEB Possible SQL Injection Attempt INSERT INTO',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_SQL_Injection_Monster_List'" +SecRule REQUEST_URI_RAW "@contains INTO " "chain" +SecRule QUERY_STRING|REQUEST_BODY "(?i:INSERT.+INTO)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Possible SQL Injection Attempt INSERT INTO',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2006445) ET WEB Possible SQL Injection Attempt SELECT FROM +SecRule REQUEST_URI_RAW "@contains SELECT " "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2006445,rev:6,msg:'ET WEB Possible SQL Injection Attempt SELECT FROM',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_SQL_Injection_Monster_List'" +SecRule REQUEST_URI_RAW "@contains FROM " "chain" +SecRule QUERY_STRING|REQUEST_BODY "(?i:SELECT.+FROM)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Possible SQL Injection Attempt SELECT FROM',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2006446) ET WEB Possible SQL Injection Attempt UNION SELECT +SecRule REQUEST_URI_RAW "@contains UNION " "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2006446,rev:6,msg:'ET WEB Possible SQL Injection Attempt UNION SELECT',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_SQL_Injection_Monster_List'" +SecRule REQUEST_URI_RAW "@contains SELECT " "chain" +SecRule QUERY_STRING|REQUEST_BODY "(?i:UNION\s+SELECT)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Possible SQL Injection Attempt UNION SELECT',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2006447) ET WEB Possible SQL Injection Attempt UPDATE SET +SecRule REQUEST_URI_RAW "@contains UPDATE " "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2006447,rev:7,msg:'ET WEB Possible SQL Injection Attempt UPDATE SET',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_SQL_Injection_Monster_List'" +SecRule REQUEST_URI_RAW "@contains SET " "chain" +SecRule QUERY_STRING|REQUEST_BODY "(?i:[&\?].*UPDATE.+SET)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Possible SQL Injection Attempt UPDATE SET',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2003903) ET WEB Microsoft SharePoint XSS Attempt default.aspx +SecRule REQUEST_URI_RAW "(?i:\/default\.aspx)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2003903,rev:5,msg:'ET WEB Microsoft SharePoint XSS Attempt default.aspx',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Sharepoint'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:<?(java|vb)?script>?.*<.+\/script>?)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Microsoft SharePoint XSS Attempt default.aspx',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2003904) ET WEB Microsoft SharePoint XSS Attempt index.php form[mail] +SecRule REQUEST_URI_RAW "(?i:\/contact\/contact\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2003904,rev:5,msg:'ET WEB Microsoft SharePoint XSS Attempt index.php form[mail]',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Sharepoint'" +SecRule ARGS:form[mail] "(?i:<?(java|vb)?script>?.*<.+\/script>?)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Microsoft SharePoint XSS Attempt index.php form[mail]',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2003705) ET WEB TellTarget CMS Remote Inclusion site_conf.php ordnertiefe +SecRule REQUEST_URI_RAW "(?i:\/site_conf\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2003705,rev:3,msg:'ET WEB TellTarget CMS Remote Inclusion site_conf.php ordnertiefe',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_TellTarget_CMS'" +SecRule ARGS_NAMES "(?i:ordnertiefe)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB TellTarget CMS Remote Inclusion site_conf.php ordnertiefe',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2003706) ET WEB TellTarget CMS Remote Inclusion class.csv.php tt_docroot +SecRule REQUEST_URI_RAW "(?i:\/class\.csv\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2003706,rev:3,msg:'ET WEB TellTarget CMS Remote Inclusion class.csv.php tt_docroot',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_TellTarget_CMS'" +SecRule ARGS_NAMES "(?i:tt_docroot)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB TellTarget CMS Remote Inclusion class.csv.php tt_docroot',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2003707) ET WEB TellTarget CMS Remote Inclusion produkte_nach_serie.php tt_docroot +SecRule REQUEST_URI_RAW "(?i:\/produkte_nach_serie\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2003707,rev:3,msg:'ET WEB TellTarget CMS Remote Inclusion produkte_nach_serie.php tt_docroot',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_TellTarget_CMS'" +SecRule ARGS_NAMES "(?i:tt_docroot)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB TellTarget CMS Remote Inclusion produkte_nach_serie.php tt_docroot',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2003708) ET WEB TellTarget CMS Remote Inclusion ref_kd_rubrik.php tt_docroot +SecRule REQUEST_URI_RAW "(?i:\/functionen\/ref_kd_rubrik\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2003708,rev:3,msg:'ET WEB TellTarget CMS Remote Inclusion ref_kd_rubrik.php tt_docroot',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_TellTarget_CMS'" +SecRule ARGS_NAMES "(?i:tt_docroot)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB TellTarget CMS Remote Inclusion ref_kd_rubrik.php tt_docroot',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2003709) ET WEB TellTarget CMS Remote Inclusion hg_referenz_jobgalerie.php tt_docroot +SecRule REQUEST_URI_RAW "(?i:\/hg_referenz_jobgalerie\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2003709,rev:3,msg:'ET WEB TellTarget CMS Remote Inclusion hg_referenz_jobgalerie.php tt_docroot',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_TellTarget_CMS'" +SecRule ARGS_NAMES "(?i:tt_docroot)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB TellTarget CMS Remote Inclusion hg_referenz_jobgalerie.php tt_docroot',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2003710) ET WEB TellTarget CMS Remote Inclusion surfer_anmeldung_NWL.php tt_docroot +SecRule REQUEST_URI_RAW "(?i:\/surfer_anmeldung_NWL\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2003710,rev:3,msg:'ET WEB TellTarget CMS Remote Inclusion surfer_anmeldung_NWL.php tt_docroot',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_TellTarget_CMS'" +SecRule ARGS_NAMES "(?i:tt_docroot)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB TellTarget CMS Remote Inclusion surfer_anmeldung_NWL.php tt_docroot',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2003711) ET WEB TellTarget CMS Remote Inclusion produkte_nach_serie_alle.php tt_docroot +SecRule REQUEST_URI_RAW "(?i:\/produkte_nach_serie_alle\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2003711,rev:3,msg:'ET WEB TellTarget CMS Remote Inclusion produkte_nach_serie_alle.php tt_docroot',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_TellTarget_CMS'" +SecRule ARGS_NAMES "(?i:tt_docroot)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB TellTarget CMS Remote Inclusion produkte_nach_serie_alle.php tt_docroot',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2003712) ET WEB TellTarget CMS Remote Inclusion surfer_aendern.php tt_docroot +SecRule REQUEST_URI_RAW "(?i:\/surfer_aendern\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2003712,rev:3,msg:'ET WEB TellTarget CMS Remote Inclusion surfer_aendern.php tt_docroot',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_TellTarget_CMS'" +SecRule ARGS_NAMES "(?i:tt_docroot)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB TellTarget CMS Remote Inclusion surfer_aendern.php tt_docroot',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2003715) ET WEB TellTarget CMS Remote Inclusion ref_kd_rubrik.php tt_docroot +SecRule REQUEST_URI_RAW "(?i:\/ref_kd_rubrik\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2003715,rev:3,msg:'ET WEB TellTarget CMS Remote Inclusion ref_kd_rubrik.php tt_docroot',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_TellTarget_CMS'" +SecRule ARGS_NAMES "(?i:tt_docroot)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB TellTarget CMS Remote Inclusion ref_kd_rubrik.php tt_docroot',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2003713) ET WEB TellTarget CMS Remote Inclusion referenz.php tt_docroot +SecRule REQUEST_URI_RAW "(?i:\/module\/referenz\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2003713,rev:3,msg:'ET WEB TellTarget CMS Remote Inclusion referenz.php tt_docroot',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_TellTarget_CMS'" +SecRule ARGS_NAMES "(?i:tt_docroot)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB TellTarget CMS Remote Inclusion referenz.php tt_docroot',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2003714) ET WEB TellTarget CMS Remote Inclusion lay.php tt_docroot +SecRule REQUEST_URI_RAW "(?i:\/standard\/1\/lay\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2003714,rev:3,msg:'ET WEB TellTarget CMS Remote Inclusion lay.php tt_docroot',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_TellTarget_CMS'" +SecRule ARGS_NAMES "(?i:tt_docroot)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB TellTarget CMS Remote Inclusion lay.php tt_docroot',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2003867) ET WEB TellTarget CMS Remote Inclusion 3_lay.php tt_docroot +SecRule REQUEST_URI_RAW "(?i:\/standard\/3\/lay\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2003867,rev:3,msg:'ET WEB TellTarget CMS Remote Inclusion 3_lay.php tt_docroot',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_TellTarget_CMS'" +SecRule ARGS_NAMES "(?i:tt_docroot)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB TellTarget CMS Remote Inclusion 3_lay.php tt_docroot',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2002662) ET WEB TWiki INCLUDE remote command execution attempt +SecRule QUERY_STRING|REQUEST_BODY "(?i:%INCLUDE\s*{.*rev=\x22\d+\|.+\x22.*}\s*%)" "phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2002662,rev:5,msg:'ET WEB TWiki INCLUDE remote command execution attempt',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Twiki',ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB TWiki INCLUDE remote command execution attempt',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2003085) ET WEB TWiki Configure Script TYPEOF Remote Command Execution Attempt +SecRule QUERY_STRING|REQUEST_BODY "(?i:&TYPEOF\:.+system\s*\()" "phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2003085,rev:4,msg:'ET WEB TWiki Configure Script TYPEOF Remote Command Execution Attempt',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Twiki',ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB TWiki Configure Script TYPEOF Remote Command Execution Attempt',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2003099) ET WEB-MISC Poison Null Byte +SecRule REQUEST_URI_RAW "@contains |00|" "phase:2,pass,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2003099,rev:4,msg:'ET WEB-MISC Poison Null Byte',tag:'web-application-activity',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_URI',ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB-MISC Poison Null Byte',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2002494) ET WEB Versatile Bulletin Board SQL Injection Attack +SecRule REQUEST_URI_RAW "(?i:\/index\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2002494,rev:5,msg:'ET WEB Versatile Bulletin Board SQL Injection Attack',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_VersatileBB'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:select=.+UNION\s+SELECT)" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB Versatile Bulletin Board SQL Injection Attack',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2002100) ET WEB WPS wps_shop.cgi Remote Command Execution Attempt +SecRule REQUEST_URI_RAW "(?i:\/wps_shop\.cgi)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2002100,rev:4,msg:'ET WEB WPS wps_shop.cgi Remote Command Execution Attempt',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_WPS'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:(art=\|.+\|))" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB WPS wps_shop.cgi Remote Command Execution Attempt',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2002844) ET WEB WebDAV search overflow +SecRule QUERY_STRING|REQUEST_BODY "@contains SEARCH " "phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2002844,rev:4,msg:'ET WEB WebDAV search overflow',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Webdav',ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB WebDAV search overflow',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2004574) ET WEB WikyBlog XSS Attempt sessionRegister.php +SecRule REQUEST_URI_RAW "(?i:\/include\/sessionRegister\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2004574,rev:4,msg:'ET WEB WikyBlog XSS Attempt sessionRegister.php',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_WikyBlog'" +SecRule REQUEST_URI_RAW "@contains | 3C |" "chain" +SecRule REQUEST_URI_RAW "@contains SCRIPT" "chain" +SecRule REQUEST_URI_RAW "@contains | 3E |" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB WikyBlog XSS Attempt sessionRegister.php',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2007872) ET WEB WinIPDS Directory Traversal Vulnerabilities GET +SecRule REQUEST_URI_RAW "@contains GET " "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2007872,rev:2,msg:'ET WEB WinIPDS Directory Traversal Vulnerabilities GET',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_WinIPDS'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:(\.\.[\\/]){1,}.+\.(com|exe|bat|dll|cab|ini))" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB WinIPDS Directory Traversal Vulnerabilities GET',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2007873) ET WEB WinIPDS Directory Traversal Vulnerabilities POST +SecRule REQUEST_URI_RAW "@contains POST " "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2007873,rev:3,msg:'ET WEB WinIPDS Directory Traversal Vulnerabilities POST',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_WinIPDS'" +SecRule QUERY_STRING|REQUEST_BODY "(?i:(\.\.[\\/]){1,}.+\.(com|exe|bat|dll|cab|ini))" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB WinIPDS Directory Traversal Vulnerabilities POST',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2008553) ET WEB WordPress Random Password Generation Insufficient Entropy Attack +SecRule REQUEST_URI_RAW "(?i:\/wp\-login\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2008553,rev:2,msg:'ET WEB WordPress Random Password Generation Insufficient Entropy Attack',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_Wordpress'" +SecRule REQUEST_URI_RAW "@contains POST " "chain" +SecRule ARGS:action "(?i:\w+(%20){60,})" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB WordPress Random Password Generation Insufficient Entropy Attack',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2002408) ET WEB phpMyAdmin Suspicious Activity +SecRule REQUEST_URI_RAW "(?i:\/grab_globals\.lib\.php)" "chain,phase:2,pass,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2002408,rev:7,msg:'ET WEB phpMyAdmin Suspicious Activity',tag:'web-application-activity',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_phpMyAdmin'" +SecRule REQUEST_URI_RAW "@contains POST " "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB phpMyAdmin Suspicious Activity',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2002409) ET WEB phpMyAdmin Local File Inclusion (2.6.4-pl1) +SecRule QUERY_STRING|REQUEST_BODY "@contains [redirect]" "phase:2,pass,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2002409,rev:5,msg:'ET WEB phpMyAdmin Local File Inclusion (2.6.4-pl1)',tag:'web-application-activity',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_phpMyAdmin',ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB phpMyAdmin Local File Inclusion (2.6.4-pl1)',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2002667) ET WEB sumthin scan +SecRule REQUEST_URI_RAW "@contains GET /sumthin HTTP/1." "phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2002667,rev:3,msg:'ET WEB sumthin scan',tag:'attempted-recon',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_sumthin',ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB sumthin scan',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +# (sid 2003167) ET WEB tikiwiki featured link XSS attempt +SecRule REQUEST_URI_RAW "(?i:\/tiki\-featured_link\.php)" "chain,phase:2,block,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:normalisePathWin,capture,nolog,auditlog,logdata:'%{TX.0}',id:sid2003167,rev:4,msg:'ET WEB tikiwiki featured link XSS attempt',tag:'web-application-attack',tag:'url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/WEB/WEB_tikiwiki'" +SecRule ARGS_NAMES "(?i:type)" "chain" +SecRule REQUEST_URI_RAW "@contains /iframe>" "ctl:auditLogParts=+E,setvar:'tx.msg=ET WEB tikiwiki featured link XSS attempt',setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}-WEB_ATTACK-%{matched_var_name}=%{matched_var}'" + + +SecMarker END_SNORT_RULES diff --git a/rules/base_rules/modsecurity_crs_47_common_exceptions.conf b/rules/base_rules/modsecurity_crs_47_common_exceptions.conf new file mode 100644 index 0000000..d4f5bf3 --- /dev/null +++ b/rules/base_rules/modsecurity_crs_47_common_exceptions.conf @@ -0,0 +1,28 @@ +# --------------------------------------------------------------- +# Core ModSecurity Rule Set ver.2.0.3 +# Copyright (C) 2006-2009 Breach Security Inc. All rights reserved. +# +# The ModSecuirty Core Rule Set is distributed under GPL version 2 +# Please see the enclosed LICENCE file for full details. +# --------------------------------------------------------------- + + +# This file is used as an exception mechanism to remove common false positives +# that may be encountered. +# +# Exception for Apache SSL pinger +# +SecRule REQUEST_LINE "^GET /$" "chain,phase:2,t:none,pass,nolog" + SecRule REMOTE_ADDR "^(127\.0\.0\.|\:\:)1$" "chain,t:none" + SecRule TX:'/PROTOCOL_VIOLATION\\\/MISSING_HEADER/' ".*" "chain,setvar:tx.missing_header=+1,setvar:tx.missing_header_%{tx.missing_header}=%{matched_var_name}" + SecRule TX:'/MISSING_HEADER_/' "TX\:(.*)" "capture,t:none,setvar:!tx.%{tx.1}" + +# +# Exception for Apache internal dummy connection +# +SecRule REQUEST_LINE "^(GET /|OPTIONS \*) HTTP/1.0$" "chain,phase:2,t:none,pass,nolog" + SecRule REMOTE_ADDR "^(127\.0\.0\.|\:\:)1$" "chain,t:none" + SecRule REQUEST_HEADERS:User-Agent "^Apache.*\(internal dummy connection\)$" "t:none,t:none,chain" + SecRule TX:'/PROTOCOL_VIOLATION\\\/MISSING_HEADER/' ".*" "chain,setvar:tx.missing_header=+1,setvar:tx.missing_header_%{tx.missing_header}=%{matched_var_name}" + SecRule TX:'/MISSING_HEADER_/' "TX\:(.*)" "capture,t:none,setvar:!tx.%{tx.1}" + diff --git a/rules/base_rules/modsecurity_crs_48_local_exceptions.conf b/rules/base_rules/modsecurity_crs_48_local_exceptions.conf new file mode 100644 index 0000000..5667e0d --- /dev/null +++ b/rules/base_rules/modsecurity_crs_48_local_exceptions.conf @@ -0,0 +1,58 @@ +# --------------------------------------------------------------- +# Core ModSecurity Rule Set ver.2.0.3 +# Copyright (C) 2006-2009 Breach Security Inc. All rights reserved. +# +# The ModSecuirty Core Rule Set is distributed under GPL version 2 +# Please see the enclosed LICENCE file for full details. +# --------------------------------------------------------------- + + +# This file is used to allow custom checks and exclusions for the transactional +# variable rules. Place rules in this file so that you may influence what happens +# in the 49 - Enforcement File. + +# In previous ModSecurity rules, the TARGET list would have to be updated in +# order to exclude a specific paramater like this - +# +# SecRule ARGS_NAMES|ARGS|!ARGS:foo +# +# With the new transactional variable rules, parameter exceptions can now +# be handled AFTER the initial inspection as the rules now use setvars to +# capture meta-data with each rule match. They use this syntax - +# +# setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{matched_var} +# +# When the transactional rules trigger, they will set a TX variable similar to this +# for an SQL Injection attack - +# +# Set variable "tx.950001-WEB_ATTACK/SQL_INJECTION-ARGS:comments" to "1' or select * from users where username = admin ". +# +# With this data now available, the user can implement flexible exceptions. +# +# Exception example - exclude a parameter +# +# In this example, we are inspecting +# the TX collections to see if there is a current variable that has matched +# for the 950001 SQL Injection rule ID and for the "comments" parameter. If +# so, then we are going to remove the collection entirely by using the +# setvar:!tx. syntax. By doing this, the TX collection is removed before final +# inspection at the end of phase 2 in the enforcement file. +# +#SecRule TX:'/^950001.*ARGS:comments/' ".*" "chain,phase:2,t:none,nolog,pass" +# SecRule MATCHED_VAR_NAME "TX\:(.*)" "capture,t:none,setvar:!tx.%{tx.1},setvar:tx.anomaly_score=-20" + +# +# This is an example exclusion for the entire SQL Injection category of rules +# +#SecRule TX:'/SQL_INJECTION/' ".*" "phase:2,t:none,nolog,pass,chain,setvar:tx.sql_injection=+1,setvar:tx.sql_injection_%{tx.sql_injection}=%{matched_var_name}" +# SecRule TX:'/^SQL_INJECTION_/' "TX\:(.*)" "capture,t:none,setvar:!tx.%{tx.1},setvar:tx.anomaly_score=-20" + +# +# This is an example exclusion that combines the URL and parameter and removes +# a specific SQL Injection ID only if the parameter foo payload matches +# +#SecRule REQUEST_FILENAME "@streq /path/to/file.php" "chain,phase:2,t:none,nolog,pass" +# SecRule TX:'/^950001.*ARGS:foo/' "@streq Item 1=1" "chain,t:none" +# SecRule MATCHED_VAR_NAME "TX\:(.*)" "capture,t:none,setvar:!tx.%{tx.1},setvar:tx.anomaly_score=-20" + + diff --git a/rules/base_rules/modsecurity_crs_49_enforcement.conf b/rules/base_rules/modsecurity_crs_49_enforcement.conf new file mode 100644 index 0000000..41bddeb --- /dev/null +++ b/rules/base_rules/modsecurity_crs_49_enforcement.conf @@ -0,0 +1,45 @@ +# --------------------------------------------------------------- +# Core ModSecurity Rule Set ver.2.0.3 +# Copyright (C) 2006-2009 Breach Security Inc. All rights reserved. +# +# The ModSecuirty Core Rule Set is distributed under GPL version 2 +# Please see the enclosed LICENCE file for full details. +# --------------------------------------------------------------- + + + +# Uncomment the anomaly sections you wish to use. +# You should set the score to the proper threshold you would prefer. If kept at "@gt 0" +# it will work similarly to previous Mod CRS rules and will create an event in the error_log +# file if there are any rules that match. If you would like to lessen the number of events +# generated in the error_log file, you should increase the anomaly score threshold to +# something like "@gt 20". This would only generate an event in the error_log file if +# there are multiple lower severity rule matches or if any 1 higher severity item matches. +# +# You should also set the desired disruptive action (deny, redirect, etc...). +# + +# Alert and Deny on High Anomaly Scores +# +SecRule TX:ANOMALY_SCORE "@ge 20" \ + "phase:2,t:none,nolog,auditlog,deny,msg:'Anomaly Score Exceeded (score %{TX.ANOMALY_SCORE}): %{tx.msg}',setvar:tx.inbound_tx_msg=%{tx.msg}" + +# Alert on any anomalies +# +#SecRule TX:ANOMALY_SCORE "@ge 0" \ +# "phase:2,t:none,nolog,auditlog,pass,msg:'Anomaly Score Exceeded (score %{TX.ANOMALY_SCORE}): %{tx.msg}',setvar:tx.inbound_tx_msg=%{tx.msg}" + +# Alert on SQL Injection anomalies +# +#SecRule TX:SQLI_SCORE "@gt 0" \ +# "phase:2,t:none,log,deny,msg:'SQL Injection Detected (score %{TX.SQLI_SCORE}): %{tx.msg}'" + +# Alert on XSS anomalies +# +#SecRule TX:XSS_SCORE "!@eq 0" \ +# "phase:2,t:none,log,deny,msg:'XSS Detected (score %{TX.XSS_SCORE}): %{tx.msg}'" + +# Alert on Protocol Policy anomalies +# +#SecRule TX:PROTOCOL_VIOLATION_SCORE "!@eq 0" \ +# "phase:2,t:none,log,deny,msg:'Protocol Violations Detected (score %{TX.PROTOCOL_VIOLATION_SCORE}): %{tx.msg}'" diff --git a/rules/base_rules/modsecurity_crs_50_outbound.conf b/rules/base_rules/modsecurity_crs_50_outbound.conf new file mode 100644 index 0000000..1298236 --- /dev/null +++ b/rules/base_rules/modsecurity_crs_50_outbound.conf @@ -0,0 +1,306 @@ +# --------------------------------------------------------------- +# Core ModSecurity Rule Set ver.2.0.3 +# Copyright (C) 2006-2009 Breach Security Inc. All rights reserved. +# +# The ModSecuirty Core Rule Set is distributed under GPL version 2 +# Please see the enclosed LICENCE file for full details. +# --------------------------------------------------------------- + + +# +# NOTE By default the status code sent is 501, which implies that the web +# server does not support the required operation. This is a non standard +# of this status code which normally refers to unsupported HTTP methods. +# It is used in order to confuse automated clients and scanners. + + +# Zope Information Leakage +SecRule RESPONSE_BODY "<h2>Site Error<\/h2>.{0,20}<p>An error was encountered while publishing this resource\." \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'Zope Information Leakage',id:'970007',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" + +# CF Information Leakage +SecRule RESPONSE_BODY "\bThe error occurred in\b.{0,100}: line\b.{0,1000}\bColdFusion\b.*?\bStack Trace \(click to expand\)\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'Cold Fusion Information Leakage',id:'970008',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" + +# PHP Information Leakage +SecRule RESPONSE_BODY "<b>Warning<\/b>.{0,100}?:.{0,1000}?\bon line\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'PHP Information Leakage',id:'970009',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" + +# ISA server existence revealed +SecRule RESPONSE_BODY "\b403 Forbidden\b.*?\bInternet Security and Acceleration Server\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'ISA server existence revealed',id:'970010',tag:'MISCONFIGURATION',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-MISCONFIGURATION-%{matched_var_name}=%{matched_var}" + +# Microsoft Office document properties leakage +SecRule RESPONSE_BODY "<o:documentproperties>" \ + "phase:4,t:none,nolog,auditlog,msg:'Microsoft Office document properties leakage',id:'970012',tag:'LEAKAGE/INFO',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/INFO-%{matched_var_name}=%{matched_var}" + + +SecRule RESPONSE_BODY "\<\%" "phase:4,chain,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'ASP/JSP source code leakage',id:'970903',tag:'LEAKAGE/SOURCE_CODE',severity:'3'" +SecRule RESPONSE_BODY "!(?:\b(?:(?:i(?:nterplay|hdr|d3)|m(?:ovi|thd)|r(?:ar!|iff)|(?:ex|jf)if|f(?:lv|ws)|varg|cws)\b|gif)|B(?:%pdf|\.ra)\b)" "t:none,setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" + + +# CF source code leakage +SecRule RESPONSE_BODY "<cf" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'Cold Fusion source code leakage',id:'970016',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" + +# IIS default location +SecRule RESPONSE_BODY "[a-z]:\\\\inetpub\b" \ + "phase:4,t:none,t:lowercase,ctl:auditLogParts=+E,nolog,auditlog,msg:'IIS installed in default location',id:'970018',severity:'3',chain" +SecRule &GLOBAL:alerted_970018_iisDefLoc "@eq 0" "setvar:global.alerted_970018_iisDefLoc,setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15" + +# The application is not available +SecRule RESPONSE_STATUS "^5\d{2}$" "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'The application is not available',id:'970901',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-AVAILABILITY/APP_NOT_AVAIL-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "(?:Microsoft OLE DB Provider for SQL Server(?:<\/font>.{1,20}?error '800(?:04005|40e31)'.{1,40}?Timeout expired| \(0x80040e31\)<br>Timeout expired<br>)|<h1>internal server error<\/h1>.*?<h2>part of the server has crashed or it has a configuration error\.<\/h2>|cannot connect to the server: timed out)" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'The application is not available',id:'970118',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-AVAILABILITY/APP_NOT_AVAIL-%{matched_var_name}=%{matched_var}" + +# Weblogic information disclosure +SecRule RESPONSE_STATUS "^500$" "phase:4,chain,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'WebLogic information disclosure',id:'970021',severity:'3'" +SecRule RESPONSE_BODY "<title>JSP compile error<\/title>" "t:none,setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" + +# File or Directory Names Leakage +SecRule RESPONSE_BODY "href\s?=[\s\"\']*[A-Za-z]\:\x5c([^\"\']+)" "phase:4,chain,capture,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'File or Directory Names Leakage',id:'970011',tag:'LEAKAGE/INFO',severity:'3'" +SecRule TX:1 "!program files\x5cmicrosoft office\x5c(?:office|templates)" "t:none,t:lowercase,setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}LEAKAGE/INFO-%{matched_var_name}=%{matched_var}" + +# +# IFrame Injection +# +SecRule RESPONSE_BODY "!@pm iframe" \ + "phase:2,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:lowercase,pass,nolog,skipAfter:END_IFRAME_CHECK" +SecRule RESPONSE_BODY "<\W*iframe[^>]+?\b(?:width|height)\b\W*?=\W*?[\"']?[^\"'1-9]*?(?:(?:20|1?\d(?:\.\d*)?)(?![\d%.])|[0-3](?:\.\d*)?%)" \ + "t:replaceComments,phase:4,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'Possibly malicious iframe tag in output',id:'981000',tag:'MALICIOUS_IFRAME',severity:'4',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-MALICIOUS_IFRAME-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "<\W*iframe[^>]+?\bstyle\W*?=\W*?[\"']?\W*?\bdisplay\b\W*?:\W*?\bnone\b" \ + "t:replaceComments,phase:4,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'Possibly malicious iframe tag in output',id:'981001',tag:'MALICIOUS_IFRAME',severity:'4',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-MALICIOUS_IFRAME-%{matched_var_name}=%{matched_var}" +SecMarker END_IFRAME_CHECK + +# +# Run PM check against response body data before running any RegEx Checks +# If nothing matches, then we skip the remainder of phase:4 +# +SecRule RESPONSE_BODY "!@pmFromFile modsecurity_50_outbound.data" \ + "phase:4,t:none,t:urlDecodeUni,t:htmlEntityDecode,nolog,allow" + +# ASP/JSP source code leakage +SecRule RESPONSE_BODY "\bwscript\.shell\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'ASP/JSP source code leakage',id:'971379',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "<jsp:" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'ASP/JSP source code leakage',id:'971300',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\.addheader\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'ASP/JSP source code leakage',id:'971360',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bserver\.execute\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'ASP/JSP source code leakage',id:'971373',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bserver\.mappath\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'ASP/JSP source code leakage',id:'971375',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bresponse\.binarywrite\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'ASP/JSP source code leakage',id:'971369',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bserver\.createobject\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'ASP/JSP source code leakage',id:'971372',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\.createtextfile\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'ASP/JSP source code leakage',id:'971361',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bwscript\.network\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'ASP/JSP source code leakage',id:'971378',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bvbscript\.encode\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'ASP/JSP source code leakage',id:'971377',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bserver\.htmlencode\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'ASP/JSP source code leakage',id:'971374',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bjavax\.servlet" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'ASP/JSP source code leakage',id:'971301',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bscripting\.filesystemobject\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'ASP/JSP source code leakage',id:'971371',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bserver\.urlencode\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'ASP/JSP source code leakage',id:'971376',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\.getfile\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'ASP/JSP source code leakage',id:'971362',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\.loadfromfile\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'ASP/JSP source code leakage',id:'971363',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bresponse\.write\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'ASP/JSP source code leakage',id:'971370',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" + +# PHP source code leakage +SecRule RESPONSE_BODY "\bproc_open\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'PHP source code leakage',id:'958976',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bgzread\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'PHP source code leakage',id:'958972',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bftp_nb_fget\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'PHP source code leakage',id:'958963',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bftp_nb_get\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'PHP source code leakage',id:'958965',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bfscanf\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'PHP source code leakage',id:'958959',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\breadfile\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'PHP source code leakage',id:'958978',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bfgetss\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'PHP source code leakage',id:'958955',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\$_post\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'PHP source code leakage',id:'958941',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bsession_start\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'PHP source code leakage',id:'958982',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\breaddir\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'PHP source code leakage',id:'958977',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bgzwrite\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'PHP source code leakage',id:'958973',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bscandir\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'PHP source code leakage',id:'958981',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bftp_get\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'PHP source code leakage',id:'958962',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bfread\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'PHP source code leakage',id:'958958',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\breadgzfile\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'PHP source code leakage',id:'958979',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bftp_put\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'PHP source code leakage',id:'958967',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bfwrite\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'PHP source code leakage',id:'958968',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bgzencode\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'PHP source code leakage',id:'958970',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bfopen\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'PHP source code leakage',id:'958957',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\$_session\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'PHP source code leakage',id:'958942',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bftp_nb_fput\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'PHP source code leakage',id:'958964',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bftp_fput\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'PHP source code leakage',id:'958961',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bgzcompress\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'PHP source code leakage',id:'958969',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bbzopen\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'PHP source code leakage',id:'958946',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bgzopen\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'PHP source code leakage',id:'958971',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bfgetc\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'PHP source code leakage',id:'958953',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bmove_uploaded_file\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'PHP source code leakage',id:'958975',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bftp_nb_put\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'PHP source code leakage',id:'958966',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\$_get\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'PHP source code leakage',id:'958940',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bfgets\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'PHP source code leakage',id:'958954',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bftp_fget\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'PHP source code leakage',id:'958960',tag:'LEAKAGE/SOURCE_CODE',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" + +SecRule RESPONSE_BODY "<\?(?!xml)" \ + "phase:4,chain,t:none,ctl:auditLogParts=+E,nolog,auditlog,msg:'PHP source code leakage',id:'970902',tag:'LEAKAGE/SOURCE_CODE',severity:'3'" +SecRule RESPONSE_BODY "!(?:\b(?:(?:i(?:nterplay|hdr|d3)|m(?:ovi|thd)|r(?:ar!|iff)|(?:ex|jf)if|f(?:lv|ws)|varg|cws)\b|gif)|B(?:%pdf|\.ra)\b)" "t:none,setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/SOURCE_CODE-%{matched_var_name}=%{matched_var}" + +# Statistics pages revealed +SecRule RESPONSE_BODY "\bThis summary was generated by.{0,100}?webcruncher\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:404,msg:'Statistics Information Leakage',id:'971019',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/INFO-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bThese statistics were produced by PeLAB\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:404,msg:'Statistics Information Leakage',id:'971011',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/INFO-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bThis summary was generated by.{0,100}?analog\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:404,msg:'Statistics Information Leakage',id:'971020',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/INFO-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bThis summary was generated by.{0,100}?Jware\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:404,msg:'Statistics Information Leakage',id:'971018',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/INFO-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bThis summary was generated by.{0,100}?wwwstat\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:404,msg:'Statistics Information Leakage',id:'971014',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/INFO-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bThis analysis was produced by.{0,100}?calamaris\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:404,msg:'Statistics Information Leakage',id:'971022',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/INFO-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bThis report was generated by WebLog\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:404,msg:'Statistics Information Leakage',id:'971013',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/INFO-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\b[gG]enerated by.{0,100}?[Ww]ebalizer\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:404,msg:'Statistics Information Leakage',id:'971024',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/INFO-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bThese statistics were produced by getstats\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:404,msg:'Statistics Information Leakage',id:'971010',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/INFO-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bThis analysis was produced by.{0,100}?EasyStat\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:404,msg:'Statistics Information Leakage',id:'971023',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/INFO-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bThis analysis was produced by.{0,100}?analog\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:404,msg:'Statistics Information Leakage',id:'971021',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/INFO-%{matched_var_name}=%{matched_var}" + + +# SQL Errors leakage +SecRule RESPONSE_BODY "\bCould not find server \'\w+\' in sysservers\. execute sp_addlinkedserver\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'SQL Information Leakage',id:'971154',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bSyntax error converting the \w+ value .*? to a column of data type\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'SQL Information Leakage',id:'971153',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bORA-\d{5}\: " \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'SQL Information Leakage',id:'971198',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bUnclosed quotation mark before the character string\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'SQL Information Leakage',id:'971092',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\[Microsoft\]\[ODBC " \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'SQL Information Leakage',id:'971197',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\berror \'800a01b8\'" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'SQL Information Leakage',id:'971069',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bYou have an error in your SQL syntax near \'" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'SQL Information Leakage',id:'971094',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bmicrosoft jet database engine error \'8" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'SQL Information Leakage',id:'971072',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bselect list because it is not contained in an aggregate function and there is no GROUP BY clause\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'SQL Information Leakage',id:'971086',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bUnable to connect to PostgreSQL server\:" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'SQL Information Leakage',id:'971091',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bPostgreSQL query failed\:" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'SQL Information Leakage',id:'971068',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bsupplied argument is not a valid MS SQL\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'SQL Information Leakage',id:'971158',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bsupplied argument is not a valid Oracle\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'SQL Information Leakage',id:'971157',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bWarning: mysql_connect\(\)\:" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'SQL Information Leakage',id:'971093',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bsupplied argument is not a valid ODBC\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'SQL Information Leakage',id:'971159',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bMicrosoft OLE DB Provider for .{0,30} [eE]rror '" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'SQL Information Leakage',id:'971076',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bSQL Server does not exist or access denied\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'SQL Information Leakage',id:'971096',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bEither BOF or EOF is True, or the current record has been deleted; the operation\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'SQL Information Leakage',id:'971099',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bcannot take a \w+ data type as an argument\." \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'SQL Information Leakage',id:'971060',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bselect list because it is not contained in either an aggregate function or the GROUP BY clause\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'SQL Information Leakage',id:'971087',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bThe column prefix .{0,50}? does not match with a table name or alias name used in the query\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'SQL Information Leakage',id:'971155',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bsupplied argument is not a valid PostgreSQL result\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'SQL Information Leakage',id:'971088',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bYou have an error in your SQL syntax;" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'SQL Information Leakage',id:'971150',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bsupplied argument is not a valid MySQL\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'SQL Information Leakage',id:'971156',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bEither BOF or EOF is True, or the current record has been deleted. Requested\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'SQL Information Leakage',id:'971067',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bincorrect syntax near (?:\'|the\b|\@\@error\b)" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'SQL Information Leakage',id:'971152',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" + + +# IIS Errors leakage +SecRule RESPONSE_BODY "\<b\>Version Information\:\<\/b\>(?: |\s)Microsoft \.NET Framework Version\:" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'IIS Information Leakage',id:'971123',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY ">error \'ASP\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'IIS Information Leakage',id:'971111',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\berror \'800" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'IIS Information Leakage',id:'971116',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\<b\>Version Information\:\<\/b\>(?: |\s)ASP\.NET Version\:" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'IIS Information Leakage',id:'971124',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bA trappable error occurred in an external object\. The script cannot continue running\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'IIS Information Leakage',id:'971122',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bMicrosoft VBScript runtime Error\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'IIS Information Leakage',id:'971125',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bMicrosoft VBScript compilation \(0x8\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'IIS Information Leakage',id:'971121',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "/[Ee]rror[Mm]essage\.aspx\?[Ee]rror\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'IIS Information Leakage',id:'971113',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bMicrosoft VBScript runtime \(0x8\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'IIS Information Leakage',id:'971126',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bObject required\: \'" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'IIS Information Leakage',id:'971112',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bADODB\.Command\b.{0,100}?\bApplication uses a value of the wrong type for the current operation\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'IIS Information Leakage',id:'971115',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "/[Ee]rror[Mm]essage\.asp\?[Ee]rror\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'IIS Information Leakage',id:'971127',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bADODB\.Command\b.{0,100}?\berror\'" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'IIS Information Leakage',id:'971114',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bMicrosoft VBScript compilation error\b" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'IIS Information Leakage',id:'971119',tag:'LEAKAGE/ERRORS',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "\bServer Error in.{0,50}?\bApplication\b" \ + "phase:4,chain,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:500,msg:'IIS Information Leakage',id:'970904',tag:'LEAKAGE/ERRORS',severity:'3'" +SecRule RESPONSE_STATUS "!^404$" "t:none,setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/ERRORS-%{matched_var_name}=%{matched_var}" + +# Directory Listing +SecRule RESPONSE_BODY ">[To Parent Directory]</[Aa]><br>" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:403,msg:'Directory Listing',id:'971202',tag:'LEAKAGE/INFO',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/INFO-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "<TITLE>Index of.*?<H1>Index of" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:403,msg:'Directory Listing',id:'971201',tag:'LEAKAGE/INFO',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/INFO-%{matched_var_name}=%{matched_var}" +SecRule RESPONSE_BODY "<title>Index of.*?<h1>Index of" \ + "phase:4,t:none,ctl:auditLogParts=+E,block,nolog,auditlog,status:403,msg:'Directory Listing',id:'971200',tag:'LEAKAGE/INFO',severity:'3',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:tx.%{rule.id}-LEAKAGE/INFO-%{matched_var_name}=%{matched_var}" + diff --git a/rules/base_rules/modsecurity_crs_60_correlation.conf b/rules/base_rules/modsecurity_crs_60_correlation.conf new file mode 100644 index 0000000..7993cc1 --- /dev/null +++ b/rules/base_rules/modsecurity_crs_60_correlation.conf @@ -0,0 +1,43 @@ +# --------------------------------------------------------------- +# Core ModSecurity Rule Set ver.2.0.3 +# Copyright (C) 2006-2009 Breach Security Inc. All rights reserved. +# +# The ModSecuirty Core Rule Set is distributed under GPL version 2 +# Please see the enclosed LICENCE file for full details. +# --------------------------------------------------------------- + + + +# You should set the score to the proper threshold you would prefer. If kept at "@gt 0" +# it will work similarly to previous Mod CRS rules and will create an event in the error_log +# file if there are any rules that match. If you would like to lessen the number of events +# generated in the error_log file, you should increase the anomaly score threshold to +# something like "@gt 20". This would only generate an event in the error_log file if +# there are multiple lower severity rule matches or if any 1 higher severity item matches. +# +# You should also set the desired disruptive action (deny, redirect, etc...). +# + +# Correlated Successful Attack +# +SecRule &TX:'/LEAKAGE\\\/ERRORS/' "@ge 1" \ + "chain,phase:5,t:none,log,pass,severity:'0',msg:'Correlated Successful Attack Identified: Inbound Attack (%{tx.inbound_tx_msg}) + Outbound Data Leakage (%{tx.msg}) - (Transactional Anomaly Score: %{TX.ANOMALY_SCORE})'" + SecRule &TX:'/WEB_ATTACK/' "@ge 1" "t:none,skipAfter:END_CORRELATION" + +# Correlated Attack Attempt +# +SecRule &TX:'/AVAILABILITY\\\/APP_NOT_AVAIL/' "@ge 1" \ + "chain,phase:5,t:none,log,pass,severity:'1',msg:'Correlated Attack Attempt Identified: Inbound Attack (%{tx.inbound_tx_msg}) + Outbound Application Error (%{tx.msg}) - (Transactional Anomaly Score %{TX.ANOMALY_SCORE})'" + SecRule &TX:'/WEB_ATTACK/' "@ge 1" "t:none,skipAfter:END_CORRELATION" + +# Alert on High Anomaly Scores +# +#SecRule TX:ANOMALY_SCORE "@ge 40" \ +# "phase:5,t:none,log,noauditlog,pass,msg:'Transactional Anomaly Score (score %{TX.ANOMALY_SCORE}): %{tx.msg}'" + +# Alert on any anomalies +# +SecRule TX:ANOMALY_SCORE "@ge 5" \ + "phase:5,t:none,log,noauditlog,pass,msg:'Transactional Anomaly Score (score %{TX.ANOMALY_SCORE}): %{tx.msg}'" + +SecMarker END_CORRELATION diff --git a/rules/modsecurity_crs_10_config.conf b/rules/modsecurity_crs_10_config.conf new file mode 100644 index 0000000..73c1d75 --- /dev/null +++ b/rules/modsecurity_crs_10_config.conf @@ -0,0 +1,276 @@ +# --------------------------------------------------------------- +# Core ModSecurity Rule Set ver.2.0.3 +# Copyright (C) 2006-2009 Breach Security Inc. All rights reserved. +# +# The ModSecuirty Core Rule Set is distributed under GPL version 2 +# Please see the enclosed LICENCE file for full details. +# --------------------------------------------------------------- + + +# The directives within this file can be included within +# Virtual Host containers. +# +# Configuration contained in this file should be customized +# for your specific requirements before deployment. +# +# Next to each rule there is a description of what it does. Each +# location where customization is needed is marked with "TODO". It +# is recommended that you: +# +# 1) Keep a copy of the original file. This will allow you to use +# the "diff" command to quickly see the changes. It will also +# make upgrades to future rule sets easier. +# +# 2) Document your changes thoroughly. +# +# You are advised to start with ModSecurity in detection mode only. +# Switch to protection when you are comfortable with your rule set. +# For maximum protection monitor your logs on daily basis (or +# better). +# + +# TODO You may want to provide an error friendly message to your +# users when you start rejecting requests. You can do this using +# the Apache ErrorDocument directive. You should also add +# mod_unique_id to your configuration and display the unique +# request ID on the error page. This would allow your users to +# report the request ID back to you so that you can investigate +# the false positive (if that's what it is). A nice error page +# usually reduces the impact of false positives on the users. +# +# The drawback of this user friendly approach is that it is +# easier for the attackers to figure out there is an web +# application firewall protecting the application. +# +# ErrorDocument 403 /path/to/error_document.php +# +# For more information see +# http://httpd.apache.org/docs-2.0/custom-error.html + + +## -- Configuration ---------------------------------------------------------- + +# Turn ModSecurity on ("On"), set to monitoring only +# ("DetectionOnly") or turn off ("Off"). +# +SecRuleEngine On + +# Define which part of the HTTP transaction to inspect. +# +# Inspecting request body (SecRequestBodyAccess) should probably be always set +# to "on". Only very high volume sites that never use POST requests might want +# to set it to "off" to optimize performance. +# +# Inspecting response body is useful for monitoring for information leaks, +# or for signs of intrusion. However, it does require all responses to be +# buffered in memory. For most sites this should not be a problem, but special +# care must be taken to avoid buffering file downloads (through +# MIME type selection, as shown below). +# +# TODO If you decide to enable output filtering make sure to +# review the list of scanned MIME types. If pages of the types specified +# for outbound inspection are smaller than 512K in you application +# (which is usually the case) you may reduce the SecResponseBodyLimit +# to protect from potential denial of service attacks. +# +SecRequestBodyAccess On +SecResponseBodyAccess On +SecResponseBodyMimeType (null) text/html text/plain text/xml +SecResponseBodyLimit 524288 + +# The following directive will not block large response bodies, but rather will +# only inspect data up to the size SecResponseBodyLimit setting. +SecResponseBodyLimitAction ProcessPartial + +# Initiate XML Processor in case of xml content-type +# +# TODO Uncomment this rule if you wish to parse +# text/xml requests using the XML parser. Note +# that this may cause considerable overhead in processing +# text/xml requests. +#SecRule REQUEST_HEADERS:Content-Type "text/xml" \ +#"phase:1,pass,nolog,ctl:requestBodyProcessor=XML" + + +# What to do when an error is encountered. +# +# The default is to log the error and let the request go through. +# This is a reasonable setting to start with because you do not +# want to reject legitimate requests with an untuned rule set. +# +# The following line's settings will be inherited by rules that +# either do not specify an action at all, or if they use the +# "block" action. This will also allow the rules to use +# Anomaly Scoring (must use the +# modsecurity_crs_49_anomaly_scoring.conf file). +# +SecDefaultAction "phase:2,pass" + +# If, after monitoring the performance of the rule set after a +# sufficient period, you determine the rules never (or rarely +# trigger on legitimate requests) you can change to something +# else, such as "log,deny,status:403". You can also leave the +# default setting here as is, but use per rule action configuration +# to only configure some rules to reject requests, leaving most +# of them to work in detection mode. +# +#SecDefaultAction "phase:2,deny" + +## -- File uploads configuration ----------------------------------------------- +# Temporary file storage path. +# +# TODO Change the temporary folder setting to a path where only +# the web server has access. +# +SecUploadDir /tmp + +# Whether or not to keep the stored files. +# +# In most cases you don't want to keep the uploaded files (especially +# when there is a lot of them). It may be useful to change the setting +# to "RelevantOnly", in which case the files uploaded in suspicious +# requests will be stored. +# +SecUploadKeepFiles Off + +# Inspect uploaded files. +# +# TODO If there is a danger of attack through uploaded files then it +# is possible to configure an external script to inspect each file +# before it is seen by the application. An example script is +# included with ModSecurity (/util/modsec-clamscan.pl). +# +# Inspecting uploaded files is especially important in a hosting, +# community or blogging environments where uploading files is permitted. +# +# NOTE the t:none action is required in order not to process the files names +# passed to the script based on previously defined actions in a +# SecDefaultAction directive. +# +# SecRule FILES_TMPNAMES "@inspectFile /opt/apache/bin/inspect_script.pl" \ +# "t:none" + +## -- Logging ---------------------------------------------------------------- + +# Whether to log requests to the ModSecurity audit log. +# +# By default, only requests that trigger a ModSecurity events (as detected +# by) or a serer error are logged ("RelevantOnly"). This is a reasonable +# setting. Full logging can be set by using # "on". If the system is used +# for protection only and no logging is desired (not reccomended) logging can +# be turned of using "off" +# +# NOTE It is also possible to configure forensic logging on the +# per request basis using the "auditlog" and "noauditlog" rule +# actions. +# +# TODO The default rule set logs requests that generate a 404 "file not found" +# response. These events are interesting, but may log a lot of information. +# you may consider removing it by setting SecAuditLogRelevantStatus +# to "^(?:5|4\d[^4])". +# +SecAuditEngine RelevantOnly +SecAuditLogRelevantStatus "^(?:5|4(?!04))" + +# Log files structure +# +# You can select to log all events to a single log file (set SecAuditLogType to +# "Serial") or to log each request to a separate file (set it to "Concurrent"). +# The former is usually easier to use, but if full logging is required or if +# the protected system supports a large transaction volume the later may +# be a better option. +# +# TODO Set the SecAuditLog (for "Serial" logging) or SecAuditLogStorageDir (for +# "Concurrent" logging). +# +# TODO If you change from "Serial" to "Concurrent" uncomment the +# SecAuditLogStorageDir directive and make sure the direcory specified +# exists and has write permissions for the Apache user. + +SecAuditLogType Serial +SecAuditLog logs/modsec_audit.log +# SecAuditLogStorageDir logs/modsec_audit + +# Select what portions of the request to log +# +# Modify the string by adding any of the letter below to it: +# A - audit log header (mandatory) +# B - request headers +# C - request body (present only if the request body exists and ModSecurity is +# configured to intercept it) +# E - intermediary response body (present only if ModSecurity is configured to +# intercept response bodies, and if the audit log engine is configured to +# record it). Intermediary response body is the same as the actual response +# body unless ModSecurity intercepts the intermediary response body, in +# which case the actual response body will contain the error message +# (either the Apache default error message, or the ErrorDocument page). +# F - final response headers (excluding the Date and Server headers, which are +# always added by Apache in the late stage of content delivery). +# H - audit log trailer +# I - This part is a replacement for part C. It will log the same data as C in +# all cases except when multipart/form-data encoding in used. In this case +# it will log a fake application/x-www-form-urlencoded body that contains +# the information about parameters but not about the files. This is handy +# if you don't want to have (often large) files stored in your audit logs. +# Z - final boundary, signifies the end of the entry (mandatory) + +SecAuditLogParts "ABIFHKZ" + +# Create a separate log to monitor performance. +# +# TODO Performance monitoring only works with Apache 2.x. You need +# to add mod_unique_id and mod_logio to your configuration. Then +# uncomment the following two lines. +# +# LogFormat "%V %h %t %{UNIQUE_ID}e \"%r\" %>s %X | %I %O | %<{mod_security-time1}n %<{mod_security-time2}n %<{mod_security-time3}n %D" mperformance +# CustomLog logs/modsec_performance.log mperformance + +# Custom application access log. +# +# TODO You should consider creating a custom access log. It could contain +# the performance metrics from above, but should also record the +# session ID for every request. That would make it possible to +# list all requests performed as part of a session. +# +# One custom log should be used per application but if you want +# multiple applications to share one log file make sure each +# line includes a unique application ID (unless the hostname is +# sufficient for differentiation). + +## -- Tuning and debugging + +# This section include tuning and debugging directives that usually require no +# modifications unless + + +# Selects the cookie format that will be used in the current configuration +# context. +# +# Possible values are: +# 0 - use version 0 (Netscape) cookies. This is what most applications use. +# It is the default value. +# 1 - use version 1 cookies. + +SecCookieFormat 0 + +# Maximum size of the request body to keep in memory +# +# A higher value requires more server memory while a lower number would slow +# the server due to additional disk access. By default the limit is 128 KB: +SecRequestBodyInMemoryLimit 131072 + + +# Whether to send ModSecurity messages to a separate debug log. +# +# Debug messages are very useful for, well, debugging. The default +# setting here copies (they always appear in the Apache error log) +# only the most important messages (errors and warnings). +# +# NOTE Debug logging is generally very slow. You should never +# use values greater than "3" in production. +# +SecDebugLog logs/modsec_debug.log +SecDebugLogLevel 3 + +# Configures the directory where temporary files will be created. +SecTmpDir /tmp diff --git a/rules/modsecurity_crs_10_global_config.conf b/rules/modsecurity_crs_10_global_config.conf new file mode 100644 index 0000000..3b51c9c --- /dev/null +++ b/rules/modsecurity_crs_10_global_config.conf @@ -0,0 +1,64 @@ +# --------------------------------------------------------------- +# Core ModSecurity Rule Set ver.2.0.3 +# Copyright (C) 2006-2009 Breach Security Inc. All rights reserved. +# +# The ModSecuirty Core Rule Set is distributed under GPL version 2 +# Please see the enclosed LICENCE file for full details. +# --------------------------------------------------------------- + + +# Configuration contained in this file should be included +# in the MAIN Apache config section as these directives +# can not be included within Virtual Host containers. +# + +# Set web server identification string +# +# If you want to spoof another web server type, you can specify it like this - +# +# SecServerSignature "Microsoft-IIS/6.0" +# or +# SecServerSignature "Sun-ONE-Web-Server/6.1" +# +# Spoofing the Server token data is considered by some to be "Security by Obscurity" +# and that may be true when it is the *only* security measure taken. There is +# a security benefit, however, with changing this data and that is to help +# protect against automated banner-grabbing tools, exploit code and worms that +# decide to send the attack payload based on the target platform data in the +# Server token. +# +# For this directive to work, you need to set Apache ServerTokens +# to Full (this is the default option) +# +# The default setting is to server a blank Server banner +SecServerSignature " " + +# Add ruleset identity to the logs +# +SecComponentSignature "core ruleset/2.0.3" + +# Parameters separator +# +# Specifies which character to use as separator for +# application/x-www-form-urlencoded content. +# Defaults to "&". Applications are sometimes (very rarely) written to use +# a semicolon (";"). +# +# NOTE Changing the value for this directive has significant influence on how +# ModSecurity works. Make the change only if you are absolutely sure it +# is required. +SecArgumentSeparator "&" + +# Path where persistent data (e.g. IP address data, session data, etc) is to +# be stored. Must be writable by the web server user. +# +# TODO It is advisable to create a directory structure for ModSecurity such as +# /var/log/msa and create sub directories for SecDataDir, SecTmpDir, +# SecUploadDir, SecAuditLog and SecAuditLogStorageDir +# underneath it and set the permission for read and write only by the +# Apache user. + +SecDataDir /tmp + +# Create both Global and IP collections for rules to use +SecAction "phase:1,t:none,pass,nolog,initcol:global=global,initcol:ip=%{remote_addr}" diff --git a/rules/optional_rules/modsecurity_crs_20_protocol_violations.conf b/rules/optional_rules/modsecurity_crs_20_protocol_violations.conf new file mode 100644 index 0000000..1dc22de --- /dev/null +++ b/rules/optional_rules/modsecurity_crs_20_protocol_violations.conf @@ -0,0 +1,92 @@ +# --------------------------------------------------------------- +# Core ModSecurity Rule Set ver.1.6.1 +# Copyright (C) 2006-2007 Breach Security Inc. All rights reserved. +# +# The ModSecuirty Core Rule Set is distributed under GPL version 2 +# Please see the enclosed LICENCE file for full details. +# --------------------------------------------------------------- + + +# +# TODO in some cases a valid client (usually automated) generates requests that +# violates the HTTP protocol. Create exceptions for those clients, but try +# to limit the exception to a source IP or other additional properties of +# the request such as URL and not allow the violation generally. +# +# + +# Validate request line +# +SecRule REQUEST_LINE "!^(?:(?:[a-z]{3,10}\s+(?:\w{3,7}?://[\w\-\./]*(?::\d+)?)?/[^?#]*(?:\?[^#\s]*)?(?:#[\S]*)?|connect (?:\d{1,3}\.){3}\d{1,3}\.?(?::\d+)?|options \*)\s+[\w\./]+|get /[^?#]*(?:\?[^#\s]*)?(?:#[\S]*)?)$" \ + "t:none,t:lowercase,phase:2,deny,log,auditlog,status:400,msg:'Invalid HTTP Request Line',id:'960911',severity:'2'" + + +# HTTP Request Smuggling +# +SecRule REQUEST_HEADERS:'/(Content-Length|Transfer-Encoding)/' "," "phase:2,t:none,deny,log,auditlog,status:400,msg:'HTTP Request Smuggling Attack.',id:'950012',tag:'WEB_ATTACK/REQUEST_SMUGGLING',severity:'1'" + +# Block request with malformed content. +# ModSecurity will not inspect these, but the server application might do so +# +SecRule REQBODY_PROCESSOR_ERROR "!@eq 0" "t:none,phase:2,deny,log,auditlog,status:400,msg:'Request Body Parsing Failed. %{REQBODY_PROCESSOR_ERROR_MSG}',id:'960912',severity:'2'" + + +# Accept only digits in content length +# +SecRule REQUEST_HEADERS:Content-Length "!^\d+$" "phase:2,t:none,deny,log,auditlog,status:400,msg:'Content-Length HTTP header is not numeric', severity:'2',id:'960016',tag:'PROTOCOL_VIOLATION/INVALID_HREQ'" + +# Do not accept GET or HEAD requests with bodies +# HTTP standard allows GET requests to have a body but this +# feature is not used in real life. Attackers could try to force +# a request body on an unsuspecting web applications. +# +SecRule REQUEST_METHOD "^(?:GET|HEAD)$" "chain,phase:2,t:none,deny,log,auditlog,status:400,msg:'GET or HEAD requests with bodies', severity:'2',id:'960011',tag:'PROTOCOL_VIOLATION/EVASION'" +SecRule REQUEST_HEADERS:Content-Length "!^0?$" t:none + +# Require Content-Length to be provided with every POST request. +# +SecRule REQUEST_METHOD "^POST$" "chain,phase:2,t:none,deny,log,auditlog,status:400,msg:'POST request must have a Content-Length header',id:'960012',tag:'PROTOCOL_VIOLATION/EVASION',severity:'4'" +SecRule &REQUEST_HEADERS:Content-Length "@eq 0" t:none + +# Don't accept transfer encodings we know we don't know how to handle +# +# NOTE ModSecurity does not support chunked transfer encodings at +# this time. You MUST reject all such requests. +# +SecRule REQUEST_HEADERS:Transfer-Encoding "!^$" "phase:2,t:none,deny,log,auditlog,status:501,msg:'ModSecurity does not support transfer encodings',id:'960013',tag:'PROTOCOL_VIOLATION/EVASION',severity:'3'" + +# Check encodings +SecRule REQUEST_BODY|REQUEST_URI|XML:/* "\%(?!$|\W|[0-9a-fA-F]{2}|u[0-9a-fA-F]{4})" \ + "chain,phase:2,t:none,deny,log,auditlog,status:400,msg:'URL Encoding Abuse Attack Attempt',id:'950107',tag:'PROTOCOL_VIOLATION/EVASION',severity:'4'" +SecRule REQUEST_BODY|REQUEST_URI|XML:/* "@validateUrlEncoding" + +# Check UTF enconding +# Uncomment this rule if your system uses UTF encoding. +#SecRule REQUEST_FILENAME|ARGS|ARGS_NAMES|REQUEST_HEADERS|XML:/*|!REQUEST_HEADERS:Referer "@validateUtf8Encoding" "phase:2,t:none,deny,log,auditlog,status:400,msg:'UTF8 Encoding Abuse Attack Attempt',id:'950801',tag:'PROTOCOL_VIOLATION/EVASION',severity:'4'" + +# Disallow use of full-width unicode +SecRule REQUEST_FILENAME|ARGS|ARGS_NAMES|REQUEST_HEADERS|XML:/*|!REQUEST_HEADERS:Referer "\%u[fF]{2}[0-9a-fA-F]{2}" \ + "t:none,phase:2,deny,log,auditlog,status:400,msg:'Unicode Full/Half Width Abuse Attack Attempt',id:'950116',severity:'4'" + +# Proxy access attempt +# NOTE Apache blocks such access by default if not set as a proxy. The rule is +# included in case Apache proxy is misconfigured. +SecRule REQUEST_URI_RAW ^\w+:/ "phase:2,t:none,deny,log,auditlog,status:400,msg:'Proxy access attempt', severity:'2',id:'960014',tag:'PROTOCOL_VIOLATION/PROXY_ACCESS'" + +# +# Restrict type of characters sent +# +# NOTE In order to be broad and support localized applications this rule +# only validates that NULL Is not used. +# +# The strict policy version also validates that protocol and application +# generated fields are limited to printable ASCII. +# +# TODO If your application use the range 32-126 for parameters. +# +SecRule REQUEST_FILENAME|REQUEST_HEADERS_NAMES|REQUEST_HEADERS|!REQUEST_HEADERS:Referer \ + "@validateByteRange 32-126" \ + "phase:2,deny,log,auditlog,status:400,msg:'Invalid character in request',id:'960018',tag:'PROTOCOL_VIOLATION/EVASION',severity:'4',t:none,t:urlDecodeUni" + +SecRule ARGS|ARGS_NAMES|REQUEST_HEADERS:Referer "@validateByteRange 1-255" \ + "phase:2,deny,log,auditlog,status:400,msg:'Invalid character in request',id:'960901',tag:'PROTOCOL_VIOLATION/EVASION',severity:'4',t:none,t:urlDecodeUni" diff --git a/rules/optional_rules/modsecurity_crs_21_protocol_anomalies.conf b/rules/optional_rules/modsecurity_crs_21_protocol_anomalies.conf new file mode 100644 index 0000000..92bc2ff --- /dev/null +++ b/rules/optional_rules/modsecurity_crs_21_protocol_anomalies.conf @@ -0,0 +1,67 @@ +# --------------------------------------------------------------- +# Core ModSecurity Rule Set ver.1.6.1 +# Copyright (C) 2006-2007 Breach Security Inc. All rights reserved. +# +# The ModSecuirty Core Rule Set is distributed under GPL version 2 +# Please see the enclosed LICENCE file for full details. +# --------------------------------------------------------------- + + +# +# TODO in some cases a valid client (usually automated) generates requests that +# violates the HTTP protocol. Create exceptions for those clients, but try +# to limit the exception to a source IP or other additional properties of +# the request such as URL and not allow the violation generally. +# + +# Do not accept requests without common headers. +# Implies either an attacker or a legitimate automation client. +# +# Exception for Apache SSL pinger + +SecRule REQUEST_LINE "^GET /$" "chain,phase:2,t:none,pass,nolog,ctl:ruleRemoveById=960019,ctl:ruleRemoveById=960008,ctl:ruleRemoveById=960015,ctl:ruleRemoveById=960009,id:'999210',severity:'5'" +SecRule REMOTE_ADDR "^127\.0\.0\.1$" t:none + +# Exception for Apache internal dummy connection +SecRule REQUEST_LINE "^GET / HTTP/1.0$" "chain,phase:2,t:none,pass,nolog,ctl:ruleRemoveById=960019,ctl:ruleRemoveById=960008,ctl:ruleRemoveById=960015,ctl:ruleRemoveById=960009,id:'999211',severity:'5'" +SecRule REMOTE_ADDR "^127\.0\.0\.1$" "chain,t:none" +SecRule REQUEST_HEADERS:User-Agent "^Apache.*\(internal dummy connection\)$" "t:none" + + +# Detect HTTP/0.9 Requests +SecRule REQUEST_PROTOCOL ^http/0.9$ "t:none,t:lowercase,phase:2,deny,log,auditlog,status:400,msg:'HTTP/0.9 Request Detected',id:'960019',severity:'4'" + +SecRule &REQUEST_HEADERS:Host "@eq 0" \ + "skip:1,phase:2,t:none,deny,log,auditlog,status:400,msg:'Request Missing a Host Header',id:'960008',tag:'PROTOCOL_VIOLATION/MISSING_HEADER',severity:'4'" +SecRule REQUEST_HEADERS:Host "^$" \ + "phase:2,t:none,deny,log,auditlog,status:400,msg:'Request Missing a Host Header',id:'960008',tag:'PROTOCOL_VIOLATION/MISSING_HEADER',severity:'4'" + + +SecRule &REQUEST_HEADERS:Accept "@eq 0" \ + "chain,phase:2,skip:1,t:none,deny,log,auditlog,status:400,msg:'Request Missing an Accept Header', severity:'2',id:'960015',tag:'PROTOCOL_VIOLATION/MISSING_HEADER'" +SecRule REQUEST_METHOD "!^OPTIONS$" "t:none" +SecRule REQUEST_HEADERS:Accept "^$" \ + "chain,phase:2,t:none,deny,log,auditlog,status:400,msg:'Request Missing an Accept Header', severity:'2',id:'960015',tag:'PROTOCOL_VIOLATION/MISSING_HEADER'" +SecRule REQUEST_METHOD "!^OPTIONS$" "t:none" + +SecRule &REQUEST_HEADERS:User-Agent "@eq 0" \ + "skip:1,phase:2,t:none,deny,log,auditlog,status:400,msg:'Request Missing a User Agent Header',id:'960009',tag:'PROTOCOL_VIOLATION/MISSING_HEADER',severity:'4'" +SecRule REQUEST_HEADERS:User-Agent "^$" \ + "t:none,deny,log,auditlog,status:400,msg:'Request Missing a User Agent Header',id:'960009',tag:'PROTOCOL_VIOLATION/MISSING_HEADER',severity:'4'" + + +SecRule &REQUEST_HEADERS:Content-Type "@eq 0" \ + "chain,phase:2,t:none,deny,log,auditlog,status:400,msg:'Request Containing Content, but Missing Content-Type header',id:'960904',severity:'4'" +SecRule REQUEST_HEADERS:Content-Length "!^0$" "t:none" + + +# Check that the host header is not an IP address +# +SecRule REQUEST_HEADERS:Host "^[\d\.]+$" "phase:2,t:none,deny,log,auditlog,status:400,msg:'Host header is a numeric IP address', severity:'2',id:'960017',tag:'PROTOCOL_VIOLATION/IP_HOST'" + + +# Log a security event when the request is rejected by apache +# +SecRule RESPONSE_STATUS ^400$ "t:none,phase:5,chain,log,auditlog,pass,msg:'Invalid request',id:'960913',severity:'2'" +SecRule WEBSERVER_ERROR_LOG !ModSecurity "t:none" + diff --git a/rules/optional_rules/modsecurity_crs_40_generic_attacks.conf b/rules/optional_rules/modsecurity_crs_40_generic_attacks.conf new file mode 100644 index 0000000..0db150f --- /dev/null +++ b/rules/optional_rules/modsecurity_crs_40_generic_attacks.conf @@ -0,0 +1,214 @@ +# --------------------------------------------------------------- +# Core ModSecurity Rule Set ver.1.6.1 +# Copyright (C) 2006-2007 Breach Security Inc. All rights reserved. +# +# The ModSecuirty Core Rule Set is distributed under GPL version 2 +# Please see the enclosed LICENCE file for full details. +# --------------------------------------------------------------- + + +# +# TODO While some of the pattern groups such as command injection are usually +# safe of false positives, other pattern groups such as SQL injection and +# XSS may require setting exceptions and therefore are set to log only by +# default. +# +# Start ModSecurity in monitoring only mode and check whether your +# application requires exceptions for a specific URL, Pattern or source IP +# before moving to blocking mode. + +# +# Session fixation +# +SecRule REQUEST_FILENAME|ARGS|ARGS_NAMES|REQUEST_HEADERS|XML:/*|!REQUEST_HEADERS:Referer "@pm set-cookie .cookie" \ + "phase:2,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,pass,nolog,skip:1" +SecAction phase:2,pass,nolog,skipAfter:959009 +SecRule REQUEST_FILENAME|ARGS|ARGS_NAMES "(?:\.cookie\b.*?;\W*?(?:expires|domain)\W*?=|\bhttp-equiv\W+set-cookie\b)" \ + "phase:2,t:none,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,capture,ctl:auditLogParts=+E,deny,log,auditlog,status:501,msg:'Session Fixation',id:'950009',tag:'WEB_ATTACK/SESSION_FIXATION',logdata:'%{TX.0}',severity:'2'" +SecRule REQUEST_HEADERS|XML:/*|!REQUEST_HEADERS:Referer "(?:\.cookie\b.*?;\W*?(?:expires|domain)\W*?=|\bhttp-equiv\W+set-cookie\b)" \ + "phase:2,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,capture,ctl:auditLogParts=+E,deny,log,auditlog,status:501,msg:'Session Fixation',id:'959009',tag:'WEB_ATTACK/SESSION_FIXATION',logdata:'%{TX.0}',severity:'2'" + + +# +# Blind SQL injection +# +SecRule REQUEST_FILENAME|ARGS|ARGS_NAMES|REQUEST_HEADERS|XML:/*|!REQUEST_HEADERS:Referer "@pm sys.user_triggers sys.user_objects @@spid msysaces instr sys.user_views sys.tab charindex sys.user_catalog constraint_type locate select msysobjects attnotnull sys.user_tables sys.user_tab_columns sys.user_constraints waitfor mysql.user sys.all_tables msysrelationships msyscolumns msysqueries" \ + "phase:2,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:lowercase,t:replaceComments,t:compressWhiteSpace,pass,nolog,skip:1" +SecAction phase:2,pass,nolog,skipAfter:959007 +SecRule REQUEST_FILENAME|ARGS|ARGS_NAMES "(?:\b(?:(?:s(?:ys\.(?:user_(?:(?:t(?:ab(?:_column|le)|rigger)|object|view)s|c(?:onstraints|atalog))|all_tables|tab)|elect\b.{0,40}\b(?:substring|ascii|user))|m(?:sys(?:(?:queri|ac)e|relationship|column|object)s|ysql\.user)|c(?:onstraint_type|harindex)|waitfor\b\W*?\bdelay|attnotnull)\b|(?:locate|instr)\W+\()|\@\@spid\b)" \ + "phase:2,capture,t:none,t:htmlEntityDecode,t:lowercase,t:replaceComments,t:compressWhiteSpace,ctl:auditLogParts=+E,deny,log,auditlog,status:501,msg:'Blind SQL Injection Attack',id:'950007',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2'" +SecRule REQUEST_HEADERS|XML:/*|!REQUEST_HEADERS:Referer "(?:\b(?:(?:s(?:ys\.(?:user_(?:(?:t(?:ab(?:_column|le)|rigger)|object|view)s|c(?:onstraints|atalog))|all_tables|tab)|elect\b.{0,40}\b(?:substring|ascii|user))|m(?:sys(?:(?:queri|ac)e|relationship|column|object)s|ysql\.user)|c(?:onstraint_type|harindex)|waitfor\b\W*?\bdelay|attnotnull)\b|(?:locate|instr)\W+\()|\@\@spid\b)" \ + "phase:2,capture,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:lowercase,t:replaceComments,t:compressWhiteSpace,ctl:auditLogParts=+E,deny,log,auditlog,status:501,msg:'Blind SQL Injection Attack',id:'959007',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2'" + +#SecRule REQUEST_FILENAME|ARGS|ARGS_NAMES "\b(?:benchmark|encode)\b" \ +# "phase:2,chain,t:none,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,deny,log,auditlog,status:501,msg:'Blind SQL Injection Attack',id:'950903',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2'" +#SecRule REQUEST_FILENAME|ARGS|ARGS_NAMES "t:none,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,(?:[\\\(\)\%#]|--)" +#SecRule REQUEST_HEADERS|XML:/*|!REQUEST_HEADERS:Referer "t:none,t:urlDecodeUni,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,\b(?:benchmark|encode)\b" \ +# "phase:2,chain,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,deny,log,auditlog,status:501,msg:'Blind SQL Injection Attack',id:'959903',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2'" +#SecRule REQUEST_HEADERS|XML:/*|!REQUEST_HEADERS:Referer "(?:[\\\(\)\%#]|--)" t:none + +SecRule REQUEST_FILENAME|ARGS|REQUEST_HEADERS|XML:/*|!REQUEST_HEADERS:Referer "@pm substr xtype textpos all_objects rownum sysfilegroups sysprocesses user_group sysobjects user_tables systables pg_attribute user_users user_password column_id attrelid user_tab_columns table_name pg_class user_constraints user_objects object_type dba_users sysconstraints mb_users column_name atttypid object_id substring syscat user_ind_columns sysibm syscolumns sysdba object_name" \ + "phase:2,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,pass,nolog,skip:1" +SecAction phase:2,pass,nolog,skipAfter:959904 +SecRule REQUEST_FILENAME|ARGS "\b(?:(?:s(?:ys(?:(?:(?:process|tabl)e|filegroup|object)s|c(?:o(?:nstraint|lumn)s|at)|dba|ibm)|ubstr(?:ing)?)|user_(?:(?:(?:constrain|objec)t|tab(?:_column|le)|ind_column|user)s|password|group)|a(?:tt(?:rel|typ)id|ll_objects)|object_(?:(?:nam|typ)e|id)|pg_(?:attribute|class)|column_(?:name|id)|(?:dba|mb)_users|xtype\W+\bchar|rownum)\b|t(?:able_name\b|extpos\W+\())" \ + "phase:2,capture,t:none,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,deny,log,auditlog,status:501,msg:'Blind SQL Injection Attack',id:'950904',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2'" +SecRule REQUEST_HEADERS|XML:/*|!REQUEST_HEADERS:Referer "\b(?:(?:s(?:ys(?:(?:(?:process|tabl)e|filegroup|object)s|c(?:o(?:nstraint|lumn)s|at)|dba|ibm)|ubstr(?:ing)?)|user_(?:(?:(?:constrain|objec)t|tab(?:_column|le)|ind_column|user)s|password|group)|a(?:tt(?:rel|typ)id|ll_objects)|object_(?:(?:nam|typ)e|id)|pg_(?:attribute|class)|column_(?:name|id)|(?:dba|mb)_users|xtype\W+\bchar|rownum)\b|t(?:able_name\b|extpos\W+\())" \ + "phase:2,capture,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,deny,log,auditlog,status:501,msg:'Blind SQL Injection Attack',id:'959904',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2'" + + +# +# SQL injection +# +SecRule REQUEST_FILENAME|ARGS|ARGS_NAMES|REQUEST_HEADERS|XML:/*|!REQUEST_HEADERS:Referer "@pm insert xp_enumdsn infile openrowset nvarchar autonomous_transaction print data_type or outfile inner shutdown tbcreator @@version xp_filelist sp_prepare sql_longvarchar xp_regenumkeys xp_loginconfig xp_dirtree ifnull sp_addextendedproc xp_regaddmultistring delete sp_sqlexec and sp_oacreate sp_execute cast xp_ntsec xp_regdeletekey drop varchar xp_execresultset having utl_file xp_regenumvalues xp_terminate xp_availablemedia xp_regdeletevalue dumpfile isnull sql_variant select 'sa' xp_regremovemultistring xp_makecab 'msdasql' xp_cmdshell openquery sp_executesql 'sqloledb' dbms_java 'dbo' utl_http sp_makewebtask benchmark xp_regread xp_regwrite" \ + "phase:2,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,pass,nolog,skip:1" +SecAction phase:2,pass,nolog,id:999501,skipAfter:959001 +SecRule REQUEST_FILENAME|ARGS|ARGS_NAMES "(?:\b(?:(?:s(?:elect\b(?:.{1,100}?\b(?:(?:length|count|top)\b.{1,100}?\bfrom|from\b.{1,100}?\bwhere)|.*?\b(?:d(?:ump\b.*\bfrom|ata_type)|(?:to_(?:numbe|cha)|inst)r))|p_(?:(?:addextendedpro|sqlexe)c|(?:oacreat|prepar)e|execute(?:sql)?|makewebtask)|ql_(?:longvarchar|variant))|xp_(?:reg(?:re(?:movemultistring|ad)|delete(?:value|key)|enum(?:value|key)s|addmultistring|write)|e(?:xecresultset|numdsn)|(?:terminat|dirtre)e|availablemedia|loginconfig|cmdshell|filelist|makecab|ntsec)|u(?:nion\b.{1,100}?\bselect|tl_(?:file|http))|group\b.*\bby\b.{1,100}?\bhaving|d(?:elete\b\W*?\bfrom|bms_java)|load\b\W*?\bdata\b.*\binfile|(?:n?varcha|tbcreato)r)\b|i(?:n(?:to\b\W*?\b(?:dump|out)file|sert\b\W*?\binto|ner\b\W*?\bjoin)\b|(?:f(?:\b\W*?\(\W*?\bbenchmark|null\b)|snull\b)\W*?\()|a(?:nd\b ?(?:\d{1,10}|[\'\"][^=]{1,10}[\'\"]) ?[=<>]+|utonomous_transaction\b)|o(?:r\b ?(?:\d{1,10}|[\'\"][^=]{1,10}[\'\"]) ?[=<>]+|pen(?:rowset|query)\b)|having\b ?(?:\d{1,10}|[\'\"][^=]{1,10}[\'\"]) ?[=<>]+|print\b\W*?\@\@|cast\b\W*?\()|(?:;\W*?\b(?:shutdown|drop)|\@\@version)\b|'(?:s(?:qloledb|a)|msdasql|dbo)')" \ + "phase:2,capture,t:none,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,deny,log,auditlog,status:501,msg:'SQL Injection Attack',id:'950001',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2'" +SecRule REQUEST_HEADERS|XML:/*|!REQUEST_HEADERS:Referer "(?:\b(?:(?:s(?:elect\b(?:.{1,100}?\b(?:(?:length|count|top)\b.{1,100}?\bfrom|from\b.{1,100}?\bwhere)|.*?\b(?:d(?:ump\b.*\bfrom|ata_type)|(?:to_(?:numbe|cha)|inst)r))|p_(?:(?:addextendedpro|sqlexe)c|(?:oacreat|prepar)e|execute(?:sql)?|makewebtask)|ql_(?:longvarchar|variant))|xp_(?:reg(?:re(?:movemultistring|ad)|delete(?:value|key)|enum(?:value|key)s|addmultistring|write)|e(?:xecresultset|numdsn)|(?:terminat|dirtre)e|availablemedia|loginconfig|cmdshell|filelist|makecab|ntsec)|u(?:nion\b.{1,100}?\bselect|tl_(?:file|http))|group\b.*\bby\b.{1,100}?\bhaving|d(?:elete\b\W*?\bfrom|bms_java)|load\b\W*?\bdata\b.*\binfile|(?:n?varcha|tbcreato)r)\b|i(?:n(?:to\b\W*?\b(?:dump|out)file|sert\b\W*?\binto|ner\b\W*?\bjoin)\b|(?:f(?:\b\W*?\(\W*?\bbenchmark|null\b)|snull\b)\W*?\()|a(?:nd\b ?(?:\d{1,10}|[\'\"][^=]{1,10}[\'\"]) ?[=<>]+|utonomous_transaction\b)|o(?:r\b ?(?:\d{1,10}|[\'\"][^=]{1,10}[\'\"]) ?[=<>]+|pen(?:rowset|query)\b)|having\b ?(?:\d{1,10}|[\'\"][^=]{1,10}[\'\"]) ?[=<>]+|print\b\W*?\@\@|cast\b\W*?\()|(?:;\W*?\b(?:shutdown|drop)|\@\@version)\b|'(?:s(?:qloledb|a)|msdasql|dbo)')" \ + "phase:2,capture,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,deny,log,auditlog,status:501,msg:'SQL Injection Attack',id:'959001',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2'" +SecRule REQUEST_FILENAME|ARGS|ARGS_NAMES "\b(\d+) ?= ?\1\b|[\'\"](\w+)[\'\"] ?= ?[\'\"]\2\b" \ + "phase:2,capture,t:none,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,deny,log,auditlog,status:501,msg:'SQL Injection Attack',id:'950901',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2'" +SecRule REQUEST_HEADERS|XML:/*|!REQUEST_HEADERS:Referer "\b(\d+) ?= ?\1\b|[\'\"](\w+)[\'\"] ?= ?[\'\"]\2\b" \ + "phase:2,capture,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,deny,log,auditlog,status:501,msg:'SQL Injection Attack',id:'959901',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2'" + +#SecRule REQUEST_FILENAME|ARGS|ARGS_NAMES "\b(?:rel(?:(?:nam|typ)e|kind)|a(?:ttn(?:ame|um)|scii)|c(?:o(?:nver|un)t|ha?r)|s(?:hutdown|elect)|to_(?:numbe|cha)r|u(?:pdate|nion)|d(?:elete|rop)|group\b\W*\bby|having|insert|length|where)\b" \ +# "phase:2,chain,capture,t:none,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,deny,log,auditlog,status:501,msg:'SQL Injection Attack',id:'950905',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2'" +#SecRule REQUEST_FILENAME|ARGS|ARGS_NAMES "(?:[\\\(\)\%#]|--)" "t:none,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase" +#SecRule REQUEST_HEADERS|XML:/*|!REQUEST_HEADERS:Referer "\b(?:rel(?:(?:nam|typ)e|kind)|a(?:ttn(?:ame|um)|scii)|c(?:o(?:nver|un)t|ha?r)|s(?:hutdown|elect)|to_(?:numbe|cha)r|u(?:pdate|nion)|d(?:elete|rop)|group\b\W*\bby|having|insert|length|where)\b" \ +# "phase:2,chain,capture,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,deny,log,auditlog,status:501,msg:'SQL Injection Attack',id:'959905',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2'" +#SecRule REQUEST_HEADERS|XML:/*|!REQUEST_HEADERS:Referer "(?:[\\\(\)\%#]|--)" "t:none,t:urlDecodeUni,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase" + +SecRule REQUEST_FILENAME|ARGS|REQUEST_HEADERS|XML:/*|!REQUEST_HEADERS:Referer "@pm user_objects object_type substr all_objects mb_users column_name rownum atttypid substring object_id user_group user_tables pg_attribute user_users column_id user_password attrelid object_name table_name pg_class" \ + "phase:2,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,pass,nolog,skip:1" +SecAction phase:2,pass,nolog,skipAfter:959906 +SecRule REQUEST_FILENAME|ARGS "\b(?:user_(?:(?:object|table|user)s|password|group)|a(?:tt(?:rel|typ)id|ll_objects)|object_(?:(?:nam|typ)e|id)|pg_(?:attribute|class)|column_(?:name|id)|substr(?:ing)?|table_name|mb_users|rownum)\b" \ + "phase:2,capture,t:none,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,deny,log,auditlog,status:501,msg:'SQL Injection Attack',id:'950906',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2'" +SecRule REQUEST_HEADERS|XML:/*|!REQUEST_HEADERS:Referer "\b(?:user_(?:(?:object|table|user)s|password|group)|a(?:tt(?:rel|typ)id|ll_objects)|object_(?:(?:nam|typ)e|id)|pg_(?:attribute|class)|column_(?:name|id)|substr(?:ing)?|table_name|mb_users|rownum)\b" \ + "phase:2,capture,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,deny,log,auditlog,status:501,msg:'SQL Injection Attack',id:'959906',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2'" + +SecRule REQUEST_FILENAME|ARGS|ARGS_NAMES|!REQUEST_HEADERS:via "\b(?:coalesce\b|root\@)" \ + "phase:2,capture,t:none,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,deny,log,auditlog,status:501,msg:'SQL Injection Attack',id:'950908',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2'" +SecRule REQUEST_HEADERS|XML:/*|!REQUEST_HEADERS:Referer|!REQUEST_HEADERS:via "\b(?:coalesce\b|root\@)" \ + "phase:2,capture,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,deny,log,auditlog,status:501,msg:'SQL Injection Attack',id:'959908',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:'2'" + + +# +# XSS +# +SecRule REQUEST_FILENAME|ARGS|ARGS_NAMES|REQUEST_HEADERS|XML:/*|!REQUEST_HEADERS:Referer "@pm jscript onsubmit copyparentfolder javascript meta onmove onkeydown onchange onkeyup activexobject expression onmouseup ecmascript onmouseover vbscript: <![cdata[ http: settimeout onabort shell: .innerhtml onmousedown onkeypress asfunction: onclick .fromcharcode background-image: .cookie ondragdrop onblur x-javascript mocha: onfocus javascript: getparentfolder lowsrc onresize @import alert onselect script onmouseout onmousemove background application .execscript livescript: getspecialfolder vbscript iframe .addimport onunload createtextrange onload <input" \ + "phase:2,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,pass,nolog,skip:1" +SecAction phase:2,pass,nolog,skipAfter:959004 +SecRule REQUEST_FILENAME|ARGS|ARGS_NAMES "(?:\b(?:(?:type\b\W*?\b(?:text\b\W*?\b(?:j(?:ava)?|ecma|vb)|application\b\W*?\bx-(?:java|vb))script|c(?:opyparentfolder|reatetextrange)|get(?:special|parent)folder|iframe\b.{0,100}?\bsrc)\b|on(?:(?:mo(?:use(?:o(?:ver|ut)|down|move|up)|ve)|key(?:press|down|up)|c(?:hange|lick)|s(?:elec|ubmi)t|(?:un)?load|dragdrop|resize|focus|blur)\b\W*?=|abort\b)|(?:l(?:owsrc\b\W*?\b(?:(?:java|vb)script|shell|http)|ivescript)|(?:href|url)\b\W*?\b(?:(?:java|vb)script|shell)|background-image|mocha):|s(?:(?:tyle\b\W*=.*\bexpression\b\W*|ettimeout\b\W*?)\(|rc\b\W*?\b(?:(?:java|vb)script|shell|http):)|a(?:ctivexobject\b|lert\b\W*?\(|sfunction:))|<(?:(?:body\b.*?\b(?:backgroun|onloa)d|input\b.*?\btype\b\W*?\bimage)\b| ?(?:(?:script|meta)\b|iframe)|!\[cdata\[)|(?:\.(?:(?:execscrip|addimpor)t|(?:fromcharcod|cooki)e|innerhtml)|\@import)\b)" \ + "phase:2,capture,t:none,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,deny,log,auditlog,status:501,msg:'Cross-site Scripting (XSS) Attack',id:'950004',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2'" +SecRule REQUEST_HEADERS|XML:/*|!REQUEST_HEADERS:Referer "(?:\b(?:(?:type\b\W*?\b(?:text\b\W*?\b(?:j(?:ava)?|ecma|vb)|application\b\W*?\bx-(?:java|vb))script|c(?:opyparentfolder|reatetextrange)|get(?:special|parent)folder|iframe\b.{0,100}?\bsrc)\b|on(?:(?:mo(?:use(?:o(?:ver|ut)|down|move|up)|ve)|key(?:press|down|up)|c(?:hange|lick)|s(?:elec|ubmi)t|(?:un)?load|dragdrop|resize|focus|blur)\b\W*?=|abort\b)|(?:l(?:owsrc\b\W*?\b(?:(?:java|vb)script|shell|http)|ivescript)|(?:href|url)\b\W*?\b(?:(?:java|vb)script|shell)|background-image|mocha):|s(?:(?:tyle\b\W*=.*\bexpression\b\W*|ettimeout\b\W*?)\(|rc\b\W*?\b(?:(?:java|vb)script|shell|http):)|a(?:ctivexobject\b|lert\b\W*?\(|sfunction:))|<(?:(?:body\b.*?\b(?:backgroun|onloa)d|input\b.*?\btype\b\W*?\bimage)\b| ?(?:(?:script|meta)\b|iframe)|!\[cdata\[)|(?:\.(?:(?:execscrip|addimpor)t|(?:fromcharcod|cooki)e|innerhtml)|\@import)\b)" \ + "phase:2,capture,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,deny,log,auditlog,status:501,msg:'Cross-site Scripting (XSS) Attack',id:'959004',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}',severity:'2'" + + +# +# File Injection +# +SecRule REQUEST_FILENAME|ARGS|ARGS_NAMES|REQUEST_HEADERS|XML:/* "@pm .www_acl .htpasswd .htaccess boot.ini httpd.conf /etc/ .htgroup global.asa .wwwacl" \ + "phase:2,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:lowercase,pass,nolog,skip:1" +SecAction phase:2,pass,nolog,skipAfter:959005 +SecRule REQUEST_FILENAME|ARGS|ARGS_NAMES "(?:\b(?:\.(?:ht(?:access|passwd|group)|www_?acl)|global\.asa|httpd\.conf|boot\.ini)\b|\/etc\/)" \ + "phase:2,capture,t:none,t:htmlEntityDecode,t:lowercase,ctl:auditLogParts=+E,deny,log,auditlog,status:501,msg:'Remote File Access Attempt',id:'950005',tag:'WEB_ATTACK/FILE_INJECTION',logdata:'%{TX.0}',severity:'2'" +SecRule REQUEST_HEADERS|XML:/* "(?:\b(?:\.(?:ht(?:access|passwd|group)|www_?acl)|global\.asa|httpd\.conf|boot\.ini)\b|\/etc\/)" \ + "phase:2,capture,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:lowercase,ctl:auditLogParts=+E,deny,log,auditlog,status:501,msg:'Remote File Access Attempt',id:'959005',tag:'WEB_ATTACK/FILE_INJECTION',logdata:'%{TX.0}',severity:'2'" + + +# +# Command access +# +SecRule REQUEST_FILENAME "\b(?:n(?:map|et|c)|w(?:guest|sh)|cmd(?:32)?|telnet|rcmd|ftp)\.exe\b" \ + "phase:2,capture,t:none,t:htmlEntityDecode,t:lowercase,ctl:auditLogParts=+E,deny,log,auditlog,status:501,msg:'System Command Access',id:'950002',tag:'WEB_ATTACK/FILE_INJECTION',logdata:'%{TX.0}',severity:'2'" + + +# +# Command injection +# +SecRule ARGS "@pm uname wguest.exe /perl /nasm rcmd.exe nc tclsh /xterm finger tftp chown /echo nmap.exe ping /passwd /chsh ps /uname telnet.exe /ftp ls tclsh8 lsof /ping echo cmd.exe /kill python traceroute /ps perl passwd wsh.exe /rm /cpp chgrp /telnet localgroup kill /chgrp /finger nasm /ls nc.exe id /chmod /nc /g++ /id /chown cmd /nmap chsh /gcc net.exe /python /lsof ftp.exe ftp xterm mail /mail tracert nmap rm cd chmod cpp telnet cmd32.exe gcc g++" \ + "phase:2,t:none,t:htmlEntityDecode,t:lowercase,pass,nolog,skip:1" +SecAction phase:2,pass,nolog,skipAfter:950006 +SecRule ARGS "(?:\b(?:(?:n(?:et(?:\b\W+?\blocalgroup|\.exe)|(?:map|c)\.exe)|t(?:racer(?:oute|t)|elnet\.exe|clsh8?|ftp)|(?:w(?:guest|sh)|rcmd|ftp)\.exe|echo\b\W*?\by+)\b|c(?:md(?:(?:32)?\.exe\b|\b\W*?\/c)|d(?:\b\W*?[\\\/]|\W*?\.\.)|hmod.{0,40}?\+.{0,3}x))|[\;\|\`]\W*?\b(?:(?:c(?:h(?:grp|mod|own|sh)|md|pp)|p(?:asswd|ython|erl|ing|s)|n(?:asm|map|c)|f(?:inger|tp)|(?:kil|mai)l|(?:xte)?rm|ls(?:of)?|telnet|uname|echo|id)\b|g(?:\+\+|cc\b))|\/(?:c(?:h(?:grp|mod|own|sh)|pp)|p(?:asswd|ython|erl|ing|s)|n(?:asm|map|c)|f(?:inger|tp)|(?:kil|mai)l|g(?:\+\+|cc)|(?:xte)?rm|ls(?:of)?|telnet|uname|echo|id)(?:[\'\"\|\;\`\-\s]|$))" \ + "phase:2,capture,t:none,t:htmlEntityDecode,t:lowercase,ctl:auditLogParts=+E,deny,log,auditlog,status:501,msg:'System Command Injection',id:'950006',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2'" +SecRule REQUEST_HEADERS|XML:/*|!REQUEST_HEADERS:'/^(Cookie|Referer|X-OS-Prefs)$/'|REQUEST_COOKIES|REQUEST_COOKIES_NAMES \ + "@pm uname wguest.exe /perl /nasm rcmd.exe nc tclsh /xterm finger tftp chown /echo nmap.exe ping /passwd /chsh ps /uname telnet.exe /ftp ls tclsh8 lsof /ping echo cmd.exe /kill python traceroute /ps perl passwd wsh.exe /rm /cpp chgrp /telnet localgroup kill /chgrp /finger nasm /ls nc.exe id /chmod /nc /g++ /id /chown cmd /nmap chsh /gcc net.exe /python /lsof ftp.exe ftp xterm mail /mail tracert nmap rm cd chmod cpp telnet cmd32.exe gcc g++" \ + "phase:2,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:lowercase,pass,nolog,skip:1" +SecAction pass,nolog,skipAfter:959006 +SecRule REQUEST_HEADERS|XML:/*|!REQUEST_HEADERS:'/^(Cookie|Referer|X-OS-Prefs)$/'|REQUEST_COOKIES|REQUEST_COOKIES_NAMES \ + "(?:\b(?:(?:n(?:et(?:\b\W+?\blocalgroup|\.exe)|(?:map|c)\.exe)|t(?:racer(?:oute|t)|elnet\.exe|clsh8?|ftp)|(?:w(?:guest|sh)|rcmd|ftp)\.exe|echo\b\W*?\by+)\b|c(?:md(?:(?:32)?\.exe\b|\b\W*?\/c)|d(?:\b\W*?[\\\/]|\W*?\.\.)|hmod.{0,40}?\+.{0,3}x))|[\;\|\`]\W*?\b(?:(?:c(?:h(?:grp|mod|own|sh)|md|pp)|p(?:asswd|ython|erl|ing|s)|n(?:asm|map|c)|f(?:inger|tp)|(?:kil|mai)l|(?:xte)?rm|ls(?:of)?|telnet|uname|echo|id)\b|g(?:\+\+|cc\b))|\/(?:c(?:h(?:grp|mod|own|sh)|pp)|p(?:asswd|ython|erl|ing|s)|n(?:asm|map|c)|f(?:inger|tp)|(?:kil|mai)l|g(?:\+\+|cc)|(?:xte)?rm|ls(?:of)?|telnet|uname|echo|id)(?:[\'\"\|\;\`\-\s]|$))" \ + "phase:2,capture,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:lowercase,ctl:auditLogParts=+E,deny,log,auditlog,status:501,msg:'System Command Injection',id:'959006',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2'" + +SecRule ARGS \ + "(?:(?:[\;\|\`]\W*?\bcc|\bwget)\b|\/cc(?:[\'\"\|\;\`\-\s]|$))" \ + "phase:2,capture,t:none,t:htmlEntityDecode,t:lowercase,ctl:auditLogParts=+E,deny,log,auditlog,status:501,msg:'System Command Injection',id:'950907',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2'" +SecRule "REQUEST_HEADERS|XML:/*|!REQUEST_HEADERS:'/^(Cookie|Referer|X-OS-Prefs|User-Agent)$/'|REQUEST_COOKIES|REQUEST_COOKIES_NAMES" \ + "(?:(?:[\;\|\`]\W*?\bcc|\bwget)\b|\/cc(?:[\'\"\|\;\`\-\s]|$))" \ + "phase:2,capture,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:lowercase,ctl:auditLogParts=+E,deny,log,auditlog,status:501,msg:'System Command Injection',id:'959907',tag:'WEB_ATTACK/COMMAND_INJECTION',logdata:'%{TX.0}',severity:'2'" + + +# +# Coldfusion injection +# +SecRule REQUEST_FILENAME|ARGS|ARGS_NAMES "\bcf(?:usion_(?:d(?:bconnections_flush|ecrypt)|set(?:tings_refresh|odbcini)|getodbc(?:dsn|ini)|verifymail|encrypt)|_(?:(?:iscoldfusiondatasourc|getdatasourceusernam)e|setdatasource(?:password|username))|newinternal(?:adminsecurit|registr)y|admin_registry_(?:delete|set)|internaldebug)\b" \ + "phase:2,capture,t:none,t:htmlEntityDecode,t:lowercase,ctl:auditLogParts=+E,deny,log,auditlog,status:501,msg:'Injection of Undocumented ColdFusion Tags',id:'950008',tag:'WEB_ATTACK/CF_INJECTION',logdata:'%{TX.0}',severity:'2'" +SecRule REQUEST_HEADERS|XML:/* "\bcf(?:usion_(?:d(?:bconnections_flush|ecrypt)|set(?:tings_refresh|odbcini)|getodbc(?:dsn|ini)|verifymail|encrypt)|_(?:(?:iscoldfusiondatasourc|getdatasourceusernam)e|setdatasource(?:password|username))|newinternal(?:adminsecurit|registr)y|admin_registry_(?:delete|set)|internaldebug)\b" \ + "phase:2,capture,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:lowercase,ctl:auditLogParts=+E,deny,log,auditlog,status:501,msg:'Injection of Undocumented ColdFusion Tags',id:'959008',tag:'WEB_ATTACK/CF_INJECTION',logdata:'%{TX.0}',severity:'2'" + + +# +# LDAP injection +# +SecRule REQUEST_FILENAME|ARGS|ARGS_NAMES "(?:\((?:\W*?(?:objectc(?:ategory|lass)|homedirectory|[gu]idnumber|cn)\b\W*?=|[^\w\x80-\xFF]*?[\!\&\|][^\w\x80-\xFF]*?\()|\)[^\w\x80-\xFF]*?\([^\w\x80-\xFF]*?[\!\&\|])" \ + "phase:2,capture,t:none,t:htmlEntityDecode,t:lowercase,ctl:auditLogParts=+E,deny,log,auditlog,status:501,msg:'LDAP Injection Attack',id:'950010',tag:'WEB_ATTACK/LDAP_INJECTION',logdata:'%{TX.0}',severity:'2'" +SecRule REQUEST_HEADERS|XML:/*|!REQUEST_HEADERS:Referer "(?:\((?:\W*?(?:objectc(?:ategory|lass)|homedirectory|[gu]idnumber|cn)\b\W*?=|[^\w\x80-\xFF]*?[\!\&\|][^\w\x80-\xFF]*?\()|\)[^\w\x80-\xFF]*?\([^\w\x80-\xFF]*?[\!\&\|])" \ + "phase:2,capture,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:lowercase,ctl:auditLogParts=+E,deny,log,auditlog,status:501,msg:'LDAP Injection Attack',id:'959010',tag:'WEB_ATTACK/LDAP_INJECTION',logdata:'%{TX.0}',severity:'2'" + + +# +# SSI injection +# +SecRule REQUEST_FILENAME|ARGS|ARGS_NAMES "<!--\W*?#\W*?(?:e(?:cho|xec)|printenv|include|cmd)" \ + "phase:2,capture,t:none,t:htmlEntityDecode,t:lowercase,ctl:auditLogParts=+E,deny,log,auditlog,status:501,msg:'SSI injection Attack',id:'950011',tag:'WEB_ATTACK/SSI_INJECTION',logdata:'%{TX.0}',severity:'2'" +SecRule REQUEST_HEADERS|XML:/* "<!--\W*?#\W*?(?:e(?:cho|xec)|printenv|include|cmd)" \ + "phase:2,capture,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:lowercase,ctl:auditLogParts=+E,deny,log,auditlog,status:501,msg:'SSI injection Attack',id:'959011',tag:'WEB_ATTACK/SSI_INJECTION',logdata:'%{TX.0}',severity:'2'" + + +# +# PHP injection +# +SecRule REQUEST_FILENAME|ARGS|ARGS_NAMES|REQUEST_HEADERS|XML:/* "@pm <?fgets move_uploaded_file $_session readfile ftp_put ftp_fget gzencode ftp_nb_put bzopen readdir $_post fopen gzread ftp_nb_fput ftp_nb_fget ftp_get $_get scandir fscanf readgzfile fread proc_open fgetc fgetss ftp_fput ftp_nb_get session_start fwrite gzwrite gzopen gzcompress" \ + "phase:2,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:lowercase,pass,nolog,skip:1" +SecAction pass,nolog,skipAfter:959013 +SecRule REQUEST_FILENAME|ARGS|ARGS_NAMES "(?:(?:\b(?:f(?:tp_(?:nb_)?f?(?:ge|pu)t|get(?:s?s|c)|scanf|write|open|read)|gz(?:(?:encod|writ)e|compress|open|read)|s(?:ession_start|candir)|read(?:(?:gz)?file|dir)|move_uploaded_file|(?:proc_|bz)open)|\$_(?:(?:pos|ge)t|session))\b|<\?(?!xml))" \ + "phase:2,capture,t:none,t:htmlEntityDecode,t:lowercase,ctl:auditLogParts=+E,deny,log,auditlog,status:501,msg:'PHP Injection Attack',id:'950013',tag:'WEB_ATTACK/PHP_INJECTION',tag:'WEB_ATTACK/HTTP_RESPONSSE_SPLITTING',logdata:'%{TX.0}',severity:'2'" +SecRule REQUEST_HEADERS|XML:/* "(?:(?:\b(?:f(?:tp_(?:nb_)?f?(?:ge|pu)t|get(?:s?s|c)|scanf|write|open|read)|gz(?:(?:encod|writ)e|compress|open|read)|s(?:ession_start|candir)|read(?:(?:gz)?file|dir)|move_uploaded_file|(?:proc_|bz)open)|\$_(?:(?:pos|ge)t|session))\b|<\?(?!xml))" \ + "phase:2,capture,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:lowercase,ctl:auditLogParts=+E,deny,log,auditlog,status:501,msg:'PHP Injection Attack',id:'959013',tag:'WEB_ATTACK/PHP_INJECTION',tag:'WEB_ATTACK/HTTP_RESPONSSE_SPLITTING',logdata:'%{TX.0}',severity:'2'" + + +# +# UPDF XSS +# +SecRule REQUEST_FILENAME|ARGS|ARGS_NAMES "http:\/\/[\w\.]+?\/.*?\.pdf\b[^\x0d\x0a]*#" \ + "phase:2,capture,t:none,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,deny,log,auditlog,status:501,msg:'Persistent Universal PDF XSS attack',id:'950018',tag:'WEB_ATTACK/UPDF_XSS',severity:'2'" +SecRule REQUEST_HEADERS|XML:/* "http:\/\/[\w\.]+?\/.*?\.pdf\b[^\x0d\x0a]*#" \ + "phase:2,capture,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,deny,log,auditlog,status:501,msg:'Persistent Universal PDF XSS attack',id:'959018',tag:'WEB_ATTACK/UPDF_XSS',severity:'2'" + + +# +# Email Injection +# +SecRule REQUEST_FILENAME|ARGS|ARGS_NAMES "[\n\r]\s*\b(?:to|b?cc)\b\s*:.*?\@" \ + "phase:2,t:none,t:htmlEntityDecode,t:lowercase,capture,ctl:auditLogParts=+E,deny,log,auditlog,status:501,msg:'Email Injection Attack',id:'950019',logdata:'%{TX.0}',severity:'2'" +SecRule REQUEST_HEADERS|XML:/* "[\n\r]\s*\b(?:to|b?cc)\b\s*:.*?\@" \ + "phase:2,t:none,t:urlDecode,t:htmlEntityDecode,t:lowercase,capture,ctl:auditLogParts=+E,deny,log,auditlog,status:501,msg:'Email Injection Attack',id:'959019',logdata:'%{TX.0}',severity:'2'" + + +# +# HTTP Response Splitting +# +SecRule REQUEST_URI|REQUEST_HEADERS|REQUEST_HEADERS_NAMES "%0[ad]" \ + "phase:2,t:none,t:lowercase,capture,ctl:auditLogParts=+E,deny,log,auditlog,status:400,msg:'HTTP Response Splitting Attack',id:'950910',logdata:'%{TX.0}',severity:'1'" +SecRule REQUEST_FILENAME|ARGS|ARGS_NAMES|XML:/* "(?:\bhttp\/(?:0\.9|1\.[01])|<(?:html|meta)\b)" \ + "phase:2,capture,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:lowercase,ctl:auditLogParts=+E,deny,log,auditlog,status:400,msg:'HTTP Response Splitting Attack',id:'950911',logdata:'%{TX.0}',severity:'1'" + diff --git a/rules/optional_rules/modsecurity_crs_42_comment_spam.conf b/rules/optional_rules/modsecurity_crs_42_comment_spam.conf new file mode 100644 index 0000000..026a1b8 --- /dev/null +++ b/rules/optional_rules/modsecurity_crs_42_comment_spam.conf @@ -0,0 +1,42 @@ +# --------------------------------------------------------------- +# Core ModSecurity Rule Set ver.2.0.3 +# Copyright (C) 2006-2009 Breach Security Inc. All rights reserved. +# +# The ModSecuirty Core Rule Set is distributed under GPL version 2 +# Please see the enclosed LICENCE file for full details. +# --------------------------------------------------------------- + + +# +# Comment spam is an attack against blogs, guestbooks, wikis and other types of +# interactive web sites that accept and display hyperlinks submitted by +# visitors. The spammers automatically post specially crafted random comments +# which include links that point to the spammer's web site. The links +# artificially increas the site's search engine ranking and may make the site +# more noticable in search results. +# + +SecRule &IP:SPAMMER "@eq 0" "chain,phase:1,t:none,block,nolog,auditlog,msg:'RBL Match for SPAM Source',tag:'AUTOMATION/MALICIOUS',severity:'2',skipAfter:END_RBL_CHECK" + SecRule REMOTE_ADDR "@rbl sbl-xbl.spamhaus.org" \ + "t:none,setvar:'tx.msg=%{rule.msg}',setvar:tx.automation_score=+1,setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}=%{matched_var_name}=%{matched_var}',setvar:ip.spammer=1,expirevar:ip.spammer=86400" + +SecRule IP:SPAMMER "@eq 1" "phase:1,t:none,block,nolog,auditlog,msg:'RBL Match for SPAM Source',tag:'AUTOMATION/MALICIOUS',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.automation_score=+1,setvar:tx.anomaly_score=+20,setvar:'tx.%{rule.id}=%{matched_var_name}=%{matched_var}'" + +SecMarker END_RBL_CHECK + +SecRule REQUEST_HEADERS:User-Agent "^(?:m(?:o(?:zilla\/4\.0\+?\(|vable type)|i(?:crosoft url|ssigua)|j12bot\/v1\.0\.8|sie)|e(?:mail(?:collector| ?siphon)|collector)|(?:blogsearchbot-marti|super happy fu)n|i(?:nternet explorer|sc systems irc)|ja(?:karta commons|va(?:\/| )1\.)|c(?:ore-project\/|herrypicker)|p(?:sycheclone|ussycat|ycurl)|(?:grub crawl|omniexplor)er|a(?:utoemailspider|dwords)|w(?:innie poh|ordpress)|nut(?:scrape/|chcvs)|8484 boston project|user(?:[- ]agent:)?|l(?:ibwww-perl|wp)|di(?:amond|gger)|trackback\/|httpproxy|<sc)" \ + "phase:2,t:none,t:lowercase,block,nolog,auditlog,status:404,msg:'Common SPAM/Email Harvester crawler',id:'958297',tag:'AUTOMATION/MALICIOUS',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.automation_score=+1,setvar:tx.anomaly_score=+10,setvar:'tx.%{rule.id}=%{matched_var_name}=%{matched_var}'" + +# Prequalifier. Look for <http> first +SecRule ARGS|ARGS_NAMES "\bhttp:" "phase:2,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,skip:1,pass,nolog,id:'999010',severity:'6'" + +SecAction phase:2,pass,nolog,skipAfter:END_COMMENT_SPAM + + # Look for 2 ways of posting a link + SecRule ARGS|ARGS_NAMES "\[url\b" "phase:2,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,chain,ctl:auditLogParts=+E,block,nolog,auditlog,status:400,msg:'Comment Spam',id:'950923',severity:'2'" + SecRule ARGS|ARGS_NAMES "\<a" "t:none,t:urlDecodeUni,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,setvar:'tx.msg=%{rule.msg}',setvar:tx.automation_score=+1,setvar:tx.anomaly_score=+10,setvar:'tx.%{rule.id}=%{matched_var_name}=%{matched_var}'" + + # Look for too many links in an argument (Prone to FPs) + SecRule ARGS|ARGS_NAMES "(http:\/.*?){4}" "phase:2,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,nolog,auditlog,status:400,msg:'Comment Spam',id:'950020',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.automation_score=+1,setvar:tx.anomaly_score=+10,setvar:'tx.%{rule.id}=%{matched_var_name}=%{matched_var}'" + +SecMarker END_COMMENT_SPAM diff --git a/rules/optional_rules/modsecurity_crs_42_tight_security.conf b/rules/optional_rules/modsecurity_crs_42_tight_security.conf new file mode 100644 index 0000000..0a72bd9 --- /dev/null +++ b/rules/optional_rules/modsecurity_crs_42_tight_security.conf @@ -0,0 +1,27 @@ +# --------------------------------------------------------------- +# Core ModSecurity Rule Set ver.2.0.3 +# Copyright (C) 2006-2009 Breach Security Inc. All rights reserved. +# +# The ModSecuirty Core Rule Set is distributed under GPL version 2 +# Please see the enclosed LICENCE file for full details. +# --------------------------------------------------------------- + + +# +# This ruleset file contains rules that are highly prone to FPs +# +# When installing this ruleset, you are advised to activate ModSecurity +# in DetectionOnly, and verify that this ruleset doesn't intercept too +# many legit requests. +# + +# +# Directory Traversal +# +SecRule REQUEST_URI "(?:\x5c|(?:%(?:c(?:0%(?:9v|af)|1%1c)|2(?:5(?:2f|5c)|f)|u221[56]|1u|5c)|\/))(?:%(?:u2024|2e)|\.){2}(?:\x5c|(?:%(?:c(?:0%(?:9v|af)|1%1c)|2(?:5(?:2f|5c)|f)|u221[56]|1u|5c)|\/))" \ + "phase:1,t:none,t:lowercase,capture,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'Path Traversal Attack',id:'950103',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:'tx.%{rule.id}=%{matched_var_name}=%{matched_var}'" + +# Weaker signature +#SecRule REQUEST_FILENAME "\.\.[/\x5c]" "phase:1,t:none,t:urlDecodeUni,capture,ctl:auditLogParts=+E,block,nolog,auditlog,status:501,msg:'Path Traversal Attack',id:'950103',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+15,setvar:'tx.%{rule.id}=%{matched_var_name}=%{matched_var}'" + + diff --git a/rules/optional_rules/modsecurity_crs_55_marketing.conf b/rules/optional_rules/modsecurity_crs_55_marketing.conf new file mode 100644 index 0000000..4fbf594 --- /dev/null +++ b/rules/optional_rules/modsecurity_crs_55_marketing.conf @@ -0,0 +1,21 @@ +# --------------------------------------------------------------- +# Core ModSecurity Rule Set ver.2.0.3 +# Copyright (C) 2006-2009 Breach Security Inc. All rights reserved. +# +# The ModSecuirty Core Rule Set is distributed under GPL version 2 +# Please see the enclosed LICENCE file for full details. +# --------------------------------------------------------------- + + +# These rules do not have a security importance, but shows other benefits of +# monitoring and logging HTTP transactions. +# -- + +SecRule REQUEST_HEADERS:User-Agent "msn(?:bot|ptc)" \ + "phase:2,t:none,t:lowercase,nolog,auditlog,msg:'MSN robot activity',id:'910008',severity:'6'" + +SecRule REQUEST_HEADERS:User-Agent "\byahoo(?:-(?:mmcrawler|blogs)|! slurp)\b" \ + "phase:2,t:none,t:lowercase,nolog,auditlog,msg:'Yahoo robot activity',id:'910007',severity:'6'" + +SecRule REQUEST_HEADERS:User-Agent "(?:(?:gsa-crawler \(enterprise; s4-e9lj2b82fjjaa; me\@mycompany\.com|adsbot-google \(\+http:\/\/www\.google\.com\/adsbot\.html)\)|\b(?:google(?:-sitemaps|bot)|mediapartners-google)\b)" \ + "phase:2,t:none,t:lowercase,nolog,auditlog,msg:'Google robot activity',id:'910006',severity:'6'" diff --git a/rules/util/httpd-guardian.pl b/rules/util/httpd-guardian.pl new file mode 100755 index 0000000..aa684d6 --- /dev/null +++ b/rules/util/httpd-guardian.pl @@ -0,0 +1,518 @@ +#!/usr/bin/perl -w +# +# httpd-guardian - detect DoS attacks by monitoring requests +# Apache Security, http://www.apachesecurity.net +# Copyright (C) 2005 Ivan Ristic <ivanr@webkreator.com> +# +# $Id: httpd-guardian,v 1.6 2005/12/04 11:30:35 ivanr Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 2. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +# This script is designed to monitor all web server requests through +# the piped logging mechanism. It keeps track of the number of requests +# sent from each IP address. Request speed is calculated at 1 minute and +# 5 minute intervals. Once a threshold is reached, httpd-guardian can +# either emit a warning or execute a script to block the IP address. +# +# Error message will be sent to stderr, which means they will end up +# in the Apache error log. +# +# Usage (in httpd.conf) +# --------------------- +# +# Without mod_security, Apache 1.x: +# +# LogFormat "%V %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\" %{UNIQUE_ID}e \"-\" %T 0 \"%{modsec_message}i\" 0" guardian +# CustomLog "|/path/to/httpd-guardian" guardian +# +# or without mod_security, Apache 2.x: +# +# LogFormat "%V %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\" %{UNIQUE_ID}e \"-\" %T %D \"%{modsec_message}i\" 0" guardian +# CustomLog "|/path/to/httpd-guardian" guardian +# +# or with mod_security (better): +# +# SecGuardianLog "|/path/to/httpd-guardian" +# +# NOTE: In order for this script to be effective it must be able to +# see all requests coming to the web server. This will not happen +# if you are using per-virtual host logging. In such cases either +# use the ModSecurity 1.9 SecGuardianLog directive (which was designed +# for this very purpose). +# +# +# Usage (with Spread) +# ------------------- +# +# 1) First you need to make sure you have Spread running on the machine +# where you intend to run httpd-guardian on. +# +# 2) Then uncomment line "use Spread;" in this script, and change +# $USE_SPREAD to "1". +# +# 3) The default port for Spread is 3333. Change it if you want to +# and then start httpd-guardian. We will be looking for messages +# in the Spread group called "httpd-guardian". + +# TODO Add support to ignore certain log entries based on a +# regex applied script_name. +# +# TODO Warn about session hijacking. +# +# TODO Track ip addresses, sessions, and individual users. +# +# TODO Detect status code anomalies. +# +# TODO Track accesses to specific pages. +# +# TODO Open proxy detection. +# +# TODO Check IP addresses with blacklists (e.g. +# http://www.spamhaus.org/XBL/). +# +# TODO Is there a point to keep per-vhost state? +# +# TODO Enhance the script to tail a log file - useful for test +# runs, in preparation for deployment. +# +# TODO Can we track connections as Apache creates and destroys them? +# +# TODO Command-line option to support multiple log formats. E.g. common, +# combined, vcombined, guardian. +# +# TODO Command-line option not to save state +# + +use strict; +use Time::Local; +# SPREAD UNCOMMENT +# use Spread; + + +# -- Configuration---------------------------------------------------------- + +my $USE_SPREAD = 0; +my $SPREAD_CLIENT_NAME = "httpd-guardian"; +my $SPREAD_DAEMON = "3333"; +my $SPREAD_GROUP_NAME = "httpd-guardian"; +my $SPREAD_TIMEOUT = 1; + +# If defined, execute this command when a threshold is reached +# block the IP address for one hour. +# $PROTECT_EXEC = "/sbin/blacklist block %s 3600"; +# $PROTECT_EXEC = "/sbin/samtool -block -ip %s -dur 3600 snortsam.example.com"; +#my $PROTECT_EXEC; + +# For testing only: +my $PROTECT_EXEC = "/usr/bin/logger Possible DoS Attack from %s"; + +# Max. speed allowed, in requests per +# second, measured over an 1-minute period +#my $THRESHOLD_1MIN = 2; # 120 requests in a minute + +# For testing only: +my $THRESHOLD_1MIN = 0.01; + +# Max. speed allowed, in requests per +# second, measured over a 5-minute period +my $THRESHOLD_5MIN = 1; # 360 requests in 5 minutes + +# If defined, httpd-guardian will make a copy +# of the data it receives from Apache +# $COPY_LOG = ""; +my $COPY_LOG; + +# Remove IP address data after a 10-minute inactivity +my $STALE_INTERVAL = 400; + +# Where to save state (at this point only useful +# for monitoring what the script does) +my $SAVE_STATE_FILE = "/tmp/httpd-guardian.state"; + +# How often to save state (in seconds). +my $SAVE_STATE_INTERVAL = 10; + +my $DEBUG = 0; + + +# ----------------------------------------------------------------- + +my %months = ( + "Jan" => 0, + "Feb" => 1, + "Mar" => 2, + "Apr" => 3, + "May" => 4, + "Jun" => 5, + "Jul" => 6, + "Aug" => 7, + "Sep" => 8, + "Oct" => 9, + "Nov" => 10, + "Dec" => 11 +); + +# -- log parsing regular expression + + +# 127.0.0.1 192.168.2.11 - - [05/Jul/2005:16:56:54 +0100] +# "GET /favicon.ico HTTP/1.1" 404 285 "-" +# "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.8) Gecko/20050511 Firefox/1.0.4" +# - "-" 0 0 "-" 0 + +my $logline_regex = ""; + +# hostname +$logline_regex .= "^(\\S+)"; +# remote host, remote username, local username +$logline_regex .= "\\ (\\S+)\\ (\\S+)\\ (\\S+)"; +# date, time, and gmt offset +$logline_regex .= "\\ \\[([^:]+):(\\d+:\\d+:\\d+)\\ ([^\\]]+)\\]"; +# request method + request uri + protocol (as one field) +$logline_regex .= "\\ \"(.*)\""; +# status, bytes out +$logline_regex .= "\\ (\\d+)\\ (\\S+)"; +# referer, user_agent +$logline_regex .= "\\ \"(.*)\"\\ \"(.*)\""; +# uniqueid, session, duration, duration_msec +$logline_regex .= "\\ (\\S+)\\ \"(.*)\"\\ (\\d+)\\ (\\d+)"; +# modsec_message, modsec_rating +$logline_regex .= "\\ \"(.*)\"\\ (\\d+)"; + +# the rest (always keep this part of the regex) +$logline_regex .= "(.*)\$"; + +my $therequest_regex = "(\\S+)\\ (.*?)\\ (\\S+)"; + +# use strict +my %ipaddresses = (); +my %request; +my $current_time; +my $last_state_save; + +sub parse_logline { + $_ = shift; + + my %request = (); + $request{"invalid"} = 0; + + my @parsed_logline = /$logline_regex/x; + if (@parsed_logline == 0) { + return (0,0); + } + + ( + $request{"hostname"}, + $request{"remote_ip"}, + $request{"remote_username"}, + $request{"username"}, + $request{"date"}, + $request{"time"}, + $request{"gmt_offset"}, + $request{"the_request"}, + $request{"status"}, + $request{"bytes_out"}, + $request{"referer"}, + $request{"user_agent"}, + $request{"unique_id"}, + $request{"session_id"}, + $request{"duration"}, + $request{"duration_msec"}, + $request{"modsec_message"}, + $request{"modsec_rating"}, + $request{"the_rest"} + ) = @parsed_logline; + + if ($DEBUG == 2) { + print "\n"; + print "hostname = " . $request{"hostname"} . "\n"; + print "remote_ip = " . $request{"remote_ip"} . "\n"; + print "remote_username = " . $request{"remote_username"} . "\n"; + print "username = " . $request{"username"} . "\n"; + print "date = " . $request{"date"} . "\n"; + print "time = " . $request{"time"} . "\n"; + print "gmt_offset = " . $request{"gmt_offset"} . "\n"; + print "the_request = " . $request{"the_request"} . "\n"; + print "status = " . $request{"status"} . "\n"; + print "bytes_out = " . $request{"bytes_out"} . "\n"; + print "referer = " . $request{"referer"} . "\n"; + print "user_agent = " . $request{"user_agent"} . "\n"; + print "unique_id = " . $request{"unique_id"} . "\n"; + print "session_id = " . $request{"session_id"} . "\n"; + print "duration = " . $request{"duration"} . "\n"; + print "duration_msec = " . $request{"duration_msec"} . "\n"; + print "modsec_message = " . $request{"modsec_message"} . "\n"; + print "modsec_rating = " . $request{"modsec_rating"} . "\n"; + print "\n\n"; + } + + # parse the request line + $_ = $request{"the_request"}; + my @parsed_therequest = /$therequest_regex/x; + if (@parsed_therequest == 0) { + $request{"invalid"} = "1"; + $request{"request_method"} = ""; + $request{"request_uri"} = ""; + $request{"protocol"} = ""; + } else { + ( + $request{"request_method"}, + $request{"request_uri"}, + $request{"protocol"} + ) = @parsed_therequest; + } + + if ($request{"bytes_out"} eq "-") { + $request{"bytes_out"} = 0; + } + + # print "date=" . $request{"date"} . "\n"; + ( + $request{"time_mday"}, + $request{"time_mon"}, + $request{"time_year"} + ) = ( $request{"date"} =~ m/^(\d+)\/(\S+)\/(\d+)/x ); + + # print "time=" . $request{"time"} . "\n"; + ( + $request{"time_hour"}, + $request{"time_min"}, + $request{"time_sec"} + ) = ( $request{"time"} =~ m/(\d+):(\d+):(\d+)/x ); + + $request{"time_mon"} = $months{$request{"time_mon"}}; + + $request{"time_epoch"} = timelocal( + $request{"time_sec"}, + $request{"time_min"}, + $request{"time_hour"}, + $request{"time_mday"}, + $request{"time_mon"}, + $request{"time_year"} + ); + + # print %request; + + my $offset = index($request{"request_uri"}, "?"); + if ($offset != -1) { + $request{"script_name"} = substr($request{"request_uri"}, 0, $offset); + $request{"query_string"} = substr($request{"request_uri"}, $offset + 1); + } else { + $request{"script_name"} = $request{"request_uri"}; + $request{"query_string"} = ""; + } + + $request{"request_uri"} =~ s/\%([A-Fa-f0-9]{2})/pack('C', hex($1))/seg; + $request{"query_string"} =~ s/\%([A-Fa-f0-9]{2})/pack('C', hex($1))/seg; + + return %request; +} + +sub update_ip_address() { + my $ipd = $ipaddresses{$request{"remote_ip"}}; + if (defined($$ipd{"counter"})) { + $$ipd{"counter"} = $$ipd{"counter"} + 1; + + if ($DEBUG) { + print STDERR "httpd-guardian: Incrementing counter for " . $request{"remote_ip"} . " (" . $$ipd{"counter"} . ")\n"; + } + + my($exec) = 0; + + # check the 1 min counter + if ($current_time - $$ipd{"time_1min"} > 60) { + # check the counters + my $speed = ($$ipd{"counter"} - $$ipd{"counter_1min"}) / ($current_time - $$ipd{"time_1min"}); + if ($speed > $THRESHOLD_1MIN) { + print STDERR "httpd-guardian: IP address " . $ipaddresses{$request{"remote_ip"}} . " reached the 1 min threshold (speed = $speed req/sec, threshold = $THRESHOLD_1MIN req/sec)\n"; + $exec = 1; + } + + # reset the 1 min counter + $$ipd{"time_1min"} = $current_time; + $$ipd{"counter_1min"} = $$ipd{"counter"}; + } + + # check the 5 min counter + if ($current_time - $$ipd{"time_5min"} > 360) { + # check the counters + my $speed = ($$ipd{"counter"} - $$ipd{"counter_5min"}) / ($current_time - $$ipd{"time_5min"}); + if ($speed > $THRESHOLD_5MIN) { + print STDERR "httpd-guardian: IP address " . $request{"remote_ip"} . " reached the 5 min threshold (speed = $speed req/sec, threshold = $THRESHOLD_5MIN req/sec)\n"; + $exec = 1; + } + + # reset the 5 min counter + $$ipd{"time_5min"} = $current_time; + $$ipd{"counter_5min"} = $$ipd{"counter"}; + } + + if (($exec == 1)&&(defined($PROTECT_EXEC))) { + my $cmd = sprintf($PROTECT_EXEC, $request{"remote_ip"}); + print STDERR "httpd-guardian: Executing: $cmd\n"; + system($cmd); + } + + } else { + # start tracking this email address + my %ipd = (); + $ipd{"counter"} = 1; + $ipd{"counter_1min"} = 1; + $ipd{"time_1min"} = $current_time; + $ipd{"counter_5min"} = 1; + $ipd{"time_5min"} = $current_time; + $ipaddresses{$request{"remote_ip"}} = \%ipd; + } +} + +sub process_log_line { + update_ip_address(); +} + +sub remove_stale_data { + while(my($key, $value) = each(%ipaddresses)) { + if ($current_time - $$value{"time_1min"} > $STALE_INTERVAL) { + if ($DEBUG) { + print STDERR "httpd-guardian: Removing key $key\n"; + } + delete($ipaddresses{$key}); + } + } +} + +sub save_state { + if (!defined($SAVE_STATE_FILE)) { + return; + } + + if (!defined($last_state_save)) { + $last_state_save = 0; + } + + if ($current_time - $last_state_save > $SAVE_STATE_INTERVAL) { + open(FILE, ">$SAVE_STATE_FILE") || die("Failed to save state to $SAVE_STATE_FILE"); + print FILE "# $current_time\n"; + print FILE "# IP Address\x09Counter\x09\x091min (time)\x095min (time)\n"; + while(my($key, $value) = each(%ipaddresses)) { + print FILE ("$key" . "\x09" . $$value{"counter"} . "\x09\x09" . $$value{"counter_1min"} . " (" . $$value{"time_1min"} . ")\x09" . $$value{"counter_5min"} . " (" . $$value{"time_5min"} . ")\n"); + } + close(FILE); + $last_state_save = $current_time; + } +} + +# load state from $SAVE_STATE_FILE, store the data into $ipaddresses +sub load_state { + return unless ( defined $SAVE_STATE_FILE ); + return unless ( -e $SAVE_STATE_FILE && -r $SAVE_STATE_FILE ); + open my $fd, "<", $SAVE_STATE_FILE + or die "cannot open state file for reading : $SAVE_STATE_FILE : $!"; + while (<$fd>) { + s/^\s+//; + next if /^#/; + #-------------------------------------------------- + # # 1133599679 + # # IP Address Counter 1min (time) 5min (time) + # 211.19.48.12 396 396 (1133599679) 395 (1133599379) + #-------------------------------------------------- + my ($addr, $counter, $time1, $time5) = split /\t+/, $_; # TAB + my ($counter_1min, $time_1min) = split /\s+/, $time1; + my ($counter_5min, $time_5min) = split /\s+/, $time5; + $ipaddresses{$addr} = { + counter => $counter, + counter_1min => $counter_1min, + time_1min => chop_brace($time_1min), + counter_5min => $counter_5min, + time_5min => chop_brace($time_5min), + } + } + close $fd; +} + +# return strings between braces +sub chop_brace { + my $str = shift; + $str =~ /\((.*)\)/; + return $1; +} +sub process_line { + my $line = shift(@_); + + if (defined($COPY_LOG)) { + print COPY_LOG_FD $line; + } + + if ($DEBUG) { + print STDERR "httpd-guardian: Received: $line"; + } + + %request = parse_logline($line); + if (!defined($request{0})) { + # TODO verify IP address is in correct format + + # extract the time from the log line, to allow the + # script to be used for batch processing too + $current_time = $request{"time_epoch"}; + + remove_stale_data(); + process_log_line(); + save_state(); + } else { + print STDERR "Failed to parse line: " . $line; + } +} + +# ----------------------------------- + +load_state(); +if (defined($COPY_LOG)) { + open(COPY_LOG_FD, ">>$COPY_LOG") || die("Failed to open $COPY_LOG for writing"); + # enable autoflush on the file descriptor + $| = 1, select $_ for select COPY_LOG_FD; +} + +if ($USE_SPREAD) { + my($sperrno); + my %args; + + $args{"spread_name"} = $SPREAD_DAEMON; + $args{"private_name"} = $SPREAD_CLIENT_NAME; + + my($mbox, $privategroup) = Spread::connect(\%args); + if (!defined($mbox)) { + die "Failed to connect to Spread daemon: $sperrno\n"; + } + + Spread::join($mbox, $SPREAD_GROUP_NAME); + + for(;;) { + my($st, $s, $g, $mt, $e, $msg); + while(($st, $s, $g, $mt, $e, $msg) = Spread::receive($mbox, $SPREAD_TIMEOUT)) { + if ((defined($st))&&($st == 2)&&(defined($msg))) { + process_line($msg . "\n"); + } + } + } + +} else { + while(<STDIN>) { + process_line($_); + } +} + +if (defined($COPY_LOG)) { + close(COPY_LOG_FD); +} + diff --git a/rules/util/modsec-clamscan.pl b/rules/util/modsec-clamscan.pl new file mode 100755 index 0000000..dcf2cf6 --- /dev/null +++ b/rules/util/modsec-clamscan.pl @@ -0,0 +1,50 @@ +#!/usr/bin/perl +# +# modsec-clamscan.pl +# ModSecurity for Apache (http://www.modsecurity.org) +# Copyright (c) 2002-2007 Breach Security, Inc. (http://www.breach.com) +# +# This script is an interface between mod_security and its +# ability to intercept files being uploaded through the +# web server, and ClamAV + +# by default use the command-line version of ClamAV, +# which is slower but more likely to work out of the +# box +$CLAMSCAN = "/usr/bin/clamscan"; + +# using ClamAV in daemon mode is faster since the +# anti-virus engine is already running, but you also +# need to configure file permissions to allow ClamAV, +# usually running as a user other than the one Apache +# is running as, to access the files +# $CLAMSCAN = "/usr/bin/clamdscan"; + +if (@ARGV != 1) { + print "Usage: modsec-clamscan.pl <filename>\n"; + exit; +} + +my ($FILE) = @ARGV; + +$cmd = "$CLAMSCAN --stdout --disable-summary $FILE"; +$input = `$cmd`; +$input =~ m/^(.+)/; +$error_message = $1; + +$output = "0 Unable to parse clamscan output [$1]"; + +if ($error_message =~ m/: Empty file\.?$/) { + $output = "1 empty file"; +} +elsif ($error_message =~ m/: (.+) ERROR$/) { + $output = "0 clamscan: $1"; +} +elsif ($error_message =~ m/: (.+) FOUND$/) { + $output = "0 clamscan: $1"; +} +elsif ($error_message =~ m/: OK$/) { + $output = "1 clamscan: OK"; +} + +print "$output\n"; diff --git a/rules/util/runav.pl b/rules/util/runav.pl new file mode 100755 index 0000000..4cc245a --- /dev/null +++ b/rules/util/runav.pl @@ -0,0 +1,40 @@ +#!/usr/bin/perl +# +# runav.pl +# Copyright (c) 2007 Breach Security +# +# This script is an interface between ModSecurity and its +# ability to intercept files being uploaded through the +# web server, and ClamAV + + +$CLAMSCAN = "clamscan"; + +if ($#ARGV != 0) { + print "Usage: modsec-clamscan.pl <filename>\n"; + exit; +} + +my ($FILE) = shift @ARGV; + +$cmd = "$CLAMSCAN --stdout --disable-summary $FILE"; +$input = `$cmd`; +$input =~ m/^(.+)/; +$error_message = $1; + +$output = "0 Unable to parse clamscan output [$1]"; + +if ($error_message =~ m/: Empty file\.?$/) { + $output = "1 empty file"; +} +elsif ($error_message =~ m/: (.+) ERROR$/) { + $output = "0 clamscan: $1"; +} +elsif ($error_message =~ m/: (.+) FOUND$/) { + $output = "0 clamscan: $1"; +} +elsif ($error_message =~ m/: OK$/) { + $output = "1 clamscan: OK"; +} + +print "$output\n"; \ No newline at end of file diff --git a/tools/README b/tools/README new file mode 100644 index 0000000..cab5dd6 --- /dev/null +++ b/tools/README @@ -0,0 +1,6 @@ +These tools are built during the ModSecurity configure process run under the +apache2 directory. To use them you will first need to run configure under +the apache2 directory: + +./configure [any options] + diff --git a/tools/rules-updater-example.conf b/tools/rules-updater-example.conf new file mode 100644 index 0000000..4fa5fae --- /dev/null +++ b/tools/rules-updater-example.conf @@ -0,0 +1,23 @@ +# This is an example configuration to be used with ruleset-updator.pl -c + +# The repository URI. +RepositoryURI http://username:password@www.example.tld/repository/ + +# Where to download the rulesets to +LocalRepository /path/to/repository + +# Where to unpack the rulesets (if Unpack is true) +LocalRules /path/to/repository + +# What version (or version prefix) to use +#Version 1.5 + +# Should we unpack the ruleset to LocalRules? +Unpack True + +# Email update notifications +#NotifyEmail "modsec-admin@example.tld, someone@example.tld" +#NotifyEmailFrom "ModSec Rules Updater <modsec-updater@example.tld>" + +# Output lots of debugging info? +Debug False diff --git a/tools/rules-updater.pl.in b/tools/rules-updater.pl.in new file mode 100644 index 0000000..16b1363 --- /dev/null +++ b/tools/rules-updater.pl.in @@ -0,0 +1,454 @@ +#!@PERL@ +# +# Fetches the latest ModSecurity Ruleset +# + +use strict; +use Sys::Hostname; +use LWP::UserAgent (); +use LWP::Debug qw(-); +use URI (); +use HTTP::Date (); +use Cwd qw(getcwd); +use Getopt::Std; + +my $VERSION = "0.0.1"; +my($SCRIPT) = ($0 =~ m/([^\/\\]+)$/); +my $CRLFRE = qr/\015?\012/; +my $HOST = Sys::Hostname::hostname(); +my $UNZIP = [qw(unzip -a)]; +my $SENDMAIL = [qw(/usr/lib/sendmail -oi -t)]; +my $HAVE_GNUPG = 0; +my %PREFIX_MAP = ( + -dev => 0, + -rc => 1, + "" => 9, +); +my %GPG_TRUST = (); +my $REQUIRED_SIG_TRUST; + +eval "use GnuPG qw(:trust)"; +if ($@) { + warn "Could not load GnuPG module - cannot verify ruleset signatures\n"; +} +else { + $HAVE_GNUPG = 1; + %GPG_TRUST = ( + &TRUST_UNDEFINED => "not", + &TRUST_NEVER => "not", + &TRUST_MARGINAL => "marginally", + &TRUST_FULLY => "fully", + &TRUST_ULTIMATE => "ultimatly", + ); + $REQUIRED_SIG_TRUST = &TRUST_FULLY; +} + +################################################################################ +################################################################################ + +my @fetched = (); +my %opt = (); +getopts('c:r:p:s:v:t:e:f:EuS:D:R:U:F:ldh', \%opt); + +usage(1) if(defined $opt{h}); +usage(1) if(@ARGV > 1); + +# Make sure we have an action +if (! grep { defined } @opt{qw(S D R U F l)}) { + usage(1, "Action required."); +} + +# Merge config with commandline opts +if ($opt{c}) { + %opt = parse_config($opt{c}, \%opt); +} + +LWP::Debug::level("+") if ($opt{d}); + +# Make the version into a regex +if (defined $opt{v}) { + my($a,$b,$c,$d) = ($opt{v} =~ m/^(\d+)\.?(\d+)?\.?(\d+)?(?:-(\D+\d+$)|($))/); + if (defined $d) { + (my $key = $d) =~ s/^(\D+)\d+$/-$1/; + unless (exists $PREFIX_MAP{$key}) { + usage(1, "Invalid version (bad suffix \"$d\"): $opt{v}"); + } + $opt{v} = qr/^$a\.$b\.$c-$d$/; + } + elsif (defined $c) { + $opt{v} = qr/^$a\.$b\.$c(?:-|$)/; + } + elsif (defined $b) { + $opt{v} = qr/^$a\.$b\./; + } + elsif (defined $a) { + $opt{v} = qr/^$a\./; + } + else { + usage(1, "Invalid version: $opt{v}"); + } + if ($opt{d}) { + print STDERR "Using version regex: $opt{v}\n"; + } +} +else { + $opt{v} = qr/^/; +} + +# Remove trailing slashes from uri and path +$opt{r} =~ s/\/+$//; +$opt{p} =~ s/\/+$//; + +# Required opts +usage(1, "Repository (-r) required.") unless(defined $opt{r}); +usage(1, "Local path (-p) required.") unless(defined $opt{p} or defined $opt{l}); + +my $ua = LWP::UserAgent->new( + agent => "ModSecurity Updator/$VERSION", + keep_alive => 1, + env_proxy => 1, + max_redirect => 5, + requests_redirectable => [qw(GET HEAD)], + timeout => ($opt{t} || 600), +); + +sub usage { + my $rc = defined($$_[0]) ? $_[0] : 0; + my $msg = defined($_[1]) ? "\n$_[1]\n\n" : ""; + + print STDERR << "EOT"; +${msg}Usage: $SCRIPT [-c config_file] [[options] [action] + + Options (commandline will override config file): + -r uri RepositoryURI Repository URI. + -p path LocalRepository Local repository path to use as base for downloads. + -s path LocalRules Local rules base path to use for unpacking. + -v text Version Full/partial version (EX: 1, 1.5, 1.5.2, 1.5.2-dev3) + -t secs Timeout Timeout for fetching data in seconds (default 600). + -e addr NotifyEmail Notify via email on update (comma separated list). + -f addr NotifyEmailFrom From address for notification email. + -u Unpack Unpack into LocalRules/version path. + -d Debug Print out lots of debugging. + + Actions: + -S name Fetch the latest stable ruleset, "name" + -D name Fetch the latest development ruleset, "name" + -R name Fetch the latest release candidate ruleset, "name" + -U name Fetch the latest unstable (non-stable) ruleset, "name" + -F name Fetch the latest ruleset, "name" + -l Print listing of what is available + + Misc: + -c Specify a config file for options. + -h This help + +Examples: + +# Get a list of what the repository contains: +$SCRIPT -rhttp://host/repo/ -l + +# Get a partial list of versions 1.5.x: +$SCRIPT -rhttp://host/repo/ -v1.5 -l + +# Get the latest stable version of "breach_ModSecurityCoreRules": +$SCRIPT -rhttp://host/repo/ -p/my/repo -Sbreach_ModSecurityCoreRules + +# Get the latest stable 1.5 release of "breach_ModSecurityCoreRules": +$SCRIPT -rhttp://host/repo/ -p/my/repo -v1.5 -Sbreach_ModSecurityCoreRules +EOT + exit $rc; +} + +sub sort_versions { + (my $A = $a) =~ s/^(\d+)\.(\d+)\.(\d+)(-[^-\d]+|)(\d*)$/sprintf("%03d%03d%03d%03d%03d", $1, $2, $3, $PREFIX_MAP{$4}, $5)/e; + (my $B = $b) =~ s/^(\d+)\.(\d+)\.(\d+)(-[^-\d]+|)(\d*)$/sprintf("%03d%03d%03d%03d%03d", $1, $2, $3, $PREFIX_MAP{$4}, $5)/e; + return $A cmp $B; +} + +sub parse_config { + my($file,$clo) = @_; + my %cfg = (); + + print STDERR "Parsing config: $file\n" if ($opt{d}); + open(CFG, "<$file") or die "Failed to open config \"$file\": $!\n"; + while(<CFG>) { + # Skip comments and empty lines + next if (/^\s*(?:#|$)/); + + # Parse + chomp; + my($var,$q1,$val,$q2) = (m/^\s*(\S+)\s+(['"]?)(.*)(\2)\s*$/); + + # Fixup values + $var = lc($var); + if ($val =~ m/^(?:true|on)$/i) { $val = 1 }; + if ($val =~ m/^(?:false|off)$/i) { $val = 0 }; + + # Set opts + if ($var eq "repositoryuri") { $cfg{r} = $val } + elsif ($var eq "localrepository") { $cfg{p} = $val } + elsif ($var eq "localrules") { $cfg{s} = $val } + elsif ($var eq "version") { $cfg{v} = $val } + elsif ($var eq "timeout") { $cfg{t} = $val } + elsif ($var eq "notifyemail") { $cfg{e} = $val } + elsif ($var eq "notifyemailfrom") { $cfg{f} = $val } + elsif ($var eq "notifyemaildiff") { $cfg{E} = $val } + elsif ($var eq "unpack") { $cfg{u} = $val } + elsif ($var eq "debug") { $cfg{d} = $val } + else { die "Invalid config directive: $var\n" } + } + close CFG; + + my($k, $v); + while (($k, $v) = each %{$clo || {}}) { + $cfg{$k} = $v if (defined $v); + } + + return %cfg; +} + +sub repository_dump { + my @replist = repository_listing(); + + print STDERR "\nRepository: $opt{r}\n\n"; + unless (@replist) { + print STDERR "No matching entries.\n"; + return; + } + + for my $repo (@replist) { + print "$repo {\n"; + my @versions = ruleset_available_versions($repo); + for my $version (@versions) { + if ($version =~ m/$opt{v}/) { + printf "%15s: %s_%s.zip\n", $version, $repo, $version; + } + elsif ($opt{d}) { + print STDERR "Skipping version: $version\n"; + } + } + print "}\n"; + } +} + +sub repository_listing { + my $res = $ua->get("$opt{r}/.listing"); + unless ($res->is_success()) { + die "Failed to get repository listing \"$opt{r}/.listing\": ".$res->status_line()."\n"; + } + return grep(/\S/, split(/$CRLFRE/, $res->content)) ; +} + +sub ruleset_listing { + my $res = $ua->get("$opt{r}/$_[0]/.listing"); + unless ($res->is_success()) { + die "Failed to get ruleset listing \"$opt{r}/$_[0]/.listing\": ".$res->status_line()."\n"; + } + return grep(/\S/, split(/$CRLFRE/, $res->content)) ; +} + +sub ruleset_available_versions { + return sort sort_versions map { m/_([^_]+)\.zip.*$/; $1 } ruleset_listing($_[0]); +} + +sub ruleset_fetch { + my($repo, $version) = @_; + + # Create paths + if (! -e "$opt{p}" ) { + mkdir "$opt{p}" or die "Failed to create \"$opt{p}\": $!\n"; + } + if (! -e "$opt{p}/$repo" ) { + mkdir "$opt{p}/$repo" or die "Failed to create \"$opt{p}/$repo\": $!\n"; + } + + my $fn = "${repo}_$version.zip"; + my $ruleset = "$repo/$fn"; + my $ruleset_sig = "$repo/$fn.sig"; + + if (-e "$opt{p}/$ruleset") { + die "Refused to overwrite ruleset \"$opt{p}/$ruleset\".\n"; + } + + # Fetch the ruleset + print STDERR "Fetching: $ruleset ...\n"; + my $res = $ua->get( + "$opt{r}/$ruleset", + ":content_file" => "$opt{p}/$ruleset", + ); + die "Failed to retrieve ruleset $ruleset: ".$res->status_line()."\n" unless ($res->is_success()); + + # Fetch the ruleset signature + if (-e "$opt{p}/$ruleset_sig") { + die "Refused to overwrite ruleset signature \"$opt{p}/$ruleset_sig\".\n"; + } + $res = $ua->get( + "$opt{r}/$ruleset_sig", + ":content_file" => "$opt{p}/$ruleset_sig", + ); + + # Verify the signature if we can + if ($HAVE_GNUPG) { + die "Failed to retrieve ruleset signature $ruleset_sig: ".$res->status_line()."\n" unless ($res->is_success()); + + ruleset_verifysig("$opt{p}/$ruleset", "$opt{p}/$ruleset_sig"); + } + push @fetched, [$repo, $version, $ruleset, undef]; +} + +sub ruleset_unpack { + my($repo, $version, $ruleset) = @{ $_[0] || [] }; + my $fn = "$opt{p}/$ruleset"; + + if (! -e "$fn" ) { + die "Internal Error: No ruleset to unpack - \"$fn\"\n"; + } + + # Create paths + if (! -e "$opt{s}" ) { + mkdir "$opt{s}" or die "Failed to create \"$opt{p}\": $!\n"; + } + if (! -e "$opt{s}/$repo" ) { + mkdir "$opt{s}/$repo" or die "Failed to create \"$opt{p}/$repo\": $!\n"; + } + if (! -e "$opt{s}/$repo/$version" ) { + mkdir "$opt{s}/$repo/$version" or die "Failed to create \"$opt{p}/$repo/$version\": $!\n"; + } + else { + die "Refused to overwrite previously unpacked \"$opt{s}/$repo/$version\".\n"; + } + + # TODO: Verify sig + + my $pwd = getcwd(); + my $unpackdir = "$opt{s}/$repo/$version"; + chdir "$unpackdir"; + if ($@) { + my $err = $!; + chdir $pwd; + die "Failed to chdir to \"$unpackdir\": $err\n"; + } + undef $!; + system(@$UNZIP, $fn); + if ($? != 0) { + my $err = $!; + chdir $pwd; + die "Failed to unpack \"$unpackdir\"".($err?": $err":".")."\n"; + } + chdir $pwd; + + # Add where we unpacked it + $_->[3] = $unpackdir; + + return 0; +} + +sub ruleset_fetch_latest { + my($repo, $type) = @_; + my @versions = ruleset_available_versions($repo); + my $verre = defined($opt{v}) ? qr/^$opt{v}/ : qr/^/; + my $typere = undef; + + # Figure out what to look for + if (defined($type) and $type ne "") { + if ($type eq "UNSTABLE") { + $typere = qr/\d-\D+\d+$/; + } + else { + $typere = qr/\d-$type\d+$/; + } + } + elsif (defined($type)) { + qr/\.\d+$/; + } + + while (@versions) { + my $last = pop(@versions); + # Check REs on version + if ($last =~ m/$opt{v}/ and (!defined($typere) || $last =~ m/$typere/)) { + return ruleset_fetch($repo, $last); + } + if ($opt{d}) { + print STDERR "Skipping version: $last\n"; + } + } + + die "No $type ruleset found.\n"; +} + +sub notify_email { + my $version_text = join("\n", map { "$_->[0] v$_->[1]".(defined($_->[3])?": $_->[3]":"") } @_); + my $from = $opt{f} ? "From: $opt{f}\n" : ""; + my $body = << "EOT"; +ModSecurity rulesets updated and ready to install on host $HOST: + +$version_text + +ModSecurity - http://www.modsecurity.org/ +EOT + + # TODO: Diffs + + open(SM, "|-", @$SENDMAIL) or die "Failed to send mail: $!\n"; + print STDERR "Sending notification email to: $opt{e}\n"; + print SM << "EOT"; +${from}To: $opt{e} +Subject: [$HOST] ModSecurity Ruleset Update Notification + +$body +EOT + close SM; +} + +sub ruleset_verifysig { + my($fn, $sigfn) = @_; + + print STDERR "Verifying \"$fn\" with signature \"$sigfn\"\n"; + my $gpg = new GnuPG(); + my $sig = eval { $gpg->verify( signature => $sigfn, file => $fn ) }; + if (defined $sig) { + print STDERR sig2str($sig)."\n"; + } + if (!defined($sig)) { + die "Signature validation failed.\n"; + } + if ( $sig->{trust} < $REQUIRED_SIG_TRUST ) { + die "Signature is not trusted ".$GPG_TRUST{$REQUIRED_SIG_TRUST}.".\n"; + } + + return; +} + +sub sig2str { + my %sig = %{ $_[0] || {} }; + "Signature made ".localtime($sig{timestamp})." by $sig{user} (ID: $sig{keyid}) and is $GPG_TRUST{$sig{trust}} trusted."; +} + +################################################################################ +################################################################################ + +# List what is there +if ($opt{l}) { repository_dump(); exit 0 } +# Latest stable +elsif (defined($opt{S})) { ruleset_fetch_latest($opt{S}, "") } +# Latest development +elsif (defined($opt{D})) { ruleset_fetch_latest($opt{D}, "dev") } +# Latest release candidate +elsif (defined($opt{R})) { ruleset_fetch_latest($opt{R}, "rc") } +# Latest unstable +elsif (defined($opt{U})) { ruleset_fetch_latest($opt{U}, "UNSTABLE") } +# Latest (any type) +elsif (defined($opt{F})) { ruleset_fetch_latest($opt{F}, undef) } + +# Unpack +if ($opt{u}) { + if (! defined $opt{s} ) { usage(1, "LocalRules is required for unpacking.") } + for (@fetched) { + ruleset_unpack($_); + } +} + +# Unpack +if ($opt{e}) { + notify_email(@fetched); +} -- 1.7.10.4