diff options
| author | Sebastien Blot | 2017-09-20 10:11:01 +0200 |
|---|---|---|
| committer | Sebastien Blot | 2017-09-20 10:11:01 +0200 |
| commit | 868f96c759b6650d88ff9f4fbc5c048302134248 (patch) | |
| tree | c0de0af318bf77a8959164ef11aeeeb2b7bab294 | |
Initial import
270 files changed, 8888 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..68dfa7a --- /dev/null +++ b/.gitignore | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | *.txt | ||
| 2 | *.orig | ||
| 3 | *.gdbhistory | ||
| 4 | *.swp | ||
| 5 | .deps | ||
| 6 | .libs | ||
| 7 | *.lo | ||
| 8 | src/tests/*.diff | ||
| 9 | src/tests/*.exp | ||
| 10 | src/tests/*.log | ||
| 11 | src/tests/*.out | ||
| 12 | src/tests/*.sh | ||
| 13 | src/tests/*.php | ||
| 14 | # Files generated by phpize, configure and make | ||
| 15 | src/autom4te.cache | ||
| 16 | src/build | ||
| 17 | src/modules | ||
| 18 | src/acinclude.m4 | ||
| 19 | src/aclocal.m4 | ||
| 20 | src/config.guess | ||
| 21 | src/config.h | ||
| 22 | src/config.h.in | ||
| 23 | src/config.log | ||
| 24 | src/config.nice | ||
| 25 | src/config.status | ||
| 26 | src/config.sub | ||
| 27 | src/configure | ||
| 28 | src/configure.in | ||
| 29 | src/install-sh | ||
| 30 | src/*.la | ||
| 31 | src/ltmain.sh | ||
| 32 | src/libtool | ||
| 33 | src/Makefile | ||
| 34 | src/Makefile.fragments | ||
| 35 | src/Makefile.global | ||
| 36 | src/Makefile.objects | ||
| 37 | src/missing | ||
| 38 | src/mkinstalldirs | ||
| 39 | src/run-tests.php | ||
| @@ -0,0 +1,165 @@ | |||
| 1 | GNU LESSER GENERAL PUBLIC LICENSE | ||
| 2 | Version 3, 29 June 2007 | ||
| 3 | |||
| 4 | Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> | ||
| 5 | Everyone is permitted to copy and distribute verbatim copies | ||
| 6 | of this license document, but changing it is not allowed. | ||
| 7 | |||
| 8 | |||
| 9 | This version of the GNU Lesser General Public License incorporates | ||
| 10 | the terms and conditions of version 3 of the GNU General Public | ||
| 11 | License, supplemented by the additional permissions listed below. | ||
| 12 | |||
| 13 | 0. Additional Definitions. | ||
| 14 | |||
| 15 | As used herein, "this License" refers to version 3 of the GNU Lesser | ||
| 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU | ||
| 17 | General Public License. | ||
| 18 | |||
| 19 | "The Library" refers to a covered work governed by this License, | ||
| 20 | other than an Application or a Combined Work as defined below. | ||
| 21 | |||
| 22 | An "Application" is any work that makes use of an interface provided | ||
| 23 | by the Library, but which is not otherwise based on the Library. | ||
| 24 | Defining a subclass of a class defined by the Library is deemed a mode | ||
| 25 | of using an interface provided by the Library. | ||
| 26 | |||
| 27 | A "Combined Work" is a work produced by combining or linking an | ||
| 28 | Application with the Library. The particular version of the Library | ||
| 29 | with which the Combined Work was made is also called the "Linked | ||
| 30 | Version". | ||
| 31 | |||
| 32 | The "Minimal Corresponding Source" for a Combined Work means the | ||
| 33 | Corresponding Source for the Combined Work, excluding any source code | ||
| 34 | for portions of the Combined Work that, considered in isolation, are | ||
| 35 | based on the Application, and not on the Linked Version. | ||
| 36 | |||
| 37 | The "Corresponding Application Code" for a Combined Work means the | ||
| 38 | object code and/or source code for the Application, including any data | ||
| 39 | and utility programs needed for reproducing the Combined Work from the | ||
| 40 | Application, but excluding the System Libraries of the Combined Work. | ||
| 41 | |||
| 42 | 1. Exception to Section 3 of the GNU GPL. | ||
| 43 | |||
| 44 | You may convey a covered work under sections 3 and 4 of this License | ||
| 45 | without being bound by section 3 of the GNU GPL. | ||
| 46 | |||
| 47 | 2. Conveying Modified Versions. | ||
| 48 | |||
| 49 | If you modify a copy of the Library, and, in your modifications, a | ||
| 50 | facility refers to a function or data to be supplied by an Application | ||
| 51 | that uses the facility (other than as an argument passed when the | ||
| 52 | facility is invoked), then you may convey a copy of the modified | ||
| 53 | version: | ||
| 54 | |||
| 55 | a) under this License, provided that you make a good faith effort to | ||
| 56 | ensure that, in the event an Application does not supply the | ||
| 57 | function or data, the facility still operates, and performs | ||
| 58 | whatever part of its purpose remains meaningful, or | ||
| 59 | |||
| 60 | b) under the GNU GPL, with none of the additional permissions of | ||
| 61 | this License applicable to that copy. | ||
| 62 | |||
| 63 | 3. Object Code Incorporating Material from Library Header Files. | ||
| 64 | |||
| 65 | The object code form of an Application may incorporate material from | ||
| 66 | a header file that is part of the Library. You may convey such object | ||
| 67 | code under terms of your choice, provided that, if the incorporated | ||
| 68 | material is not limited to numerical parameters, data structure | ||
| 69 | layouts and accessors, or small macros, inline functions and templates | ||
| 70 | (ten or fewer lines in length), you do both of the following: | ||
| 71 | |||
| 72 | a) Give prominent notice with each copy of the object code that the | ||
| 73 | Library is used in it and that the Library and its use are | ||
| 74 | covered by this License. | ||
| 75 | |||
| 76 | b) Accompany the object code with a copy of the GNU GPL and this license | ||
| 77 | document. | ||
| 78 | |||
| 79 | 4. Combined Works. | ||
| 80 | |||
| 81 | You may convey a Combined Work under terms of your choice that, | ||
| 82 | taken together, effectively do not restrict modification of the | ||
| 83 | portions of the Library contained in the Combined Work and reverse | ||
| 84 | engineering for debugging such modifications, if you also do each of | ||
| 85 | the following: | ||
| 86 | |||
| 87 | a) Give prominent notice with each copy of the Combined Work that | ||
| 88 | the Library is used in it and that the Library and its use are | ||
| 89 | covered by this License. | ||
| 90 | |||
| 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license | ||
| 92 | document. | ||
| 93 | |||
| 94 | c) For a Combined Work that displays copyright notices during | ||
| 95 | execution, include the copyright notice for the Library among | ||
| 96 | these notices, as well as a reference directing the user to the | ||
| 97 | copies of the GNU GPL and this license document. | ||
| 98 | |||
| 99 | d) Do one of the following: | ||
| 100 | |||
| 101 | 0) Convey the Minimal Corresponding Source under the terms of this | ||
| 102 | License, and the Corresponding Application Code in a form | ||
| 103 | suitable for, and under terms that permit, the user to | ||
| 104 | recombine or relink the Application with a modified version of | ||
| 105 | the Linked Version to produce a modified Combined Work, in the | ||
| 106 | manner specified by section 6 of the GNU GPL for conveying | ||
| 107 | Corresponding Source. | ||
| 108 | |||
| 109 | 1) Use a suitable shared library mechanism for linking with the | ||
| 110 | Library. A suitable mechanism is one that (a) uses at run time | ||
| 111 | a copy of the Library already present on the user's computer | ||
| 112 | system, and (b) will operate properly with a modified version | ||
| 113 | of the Library that is interface-compatible with the Linked | ||
| 114 | Version. | ||
| 115 | |||
| 116 | e) Provide Installation Information, but only if you would otherwise | ||
| 117 | be required to provide such information under section 6 of the | ||
| 118 | GNU GPL, and only to the extent that such information is | ||
| 119 | necessary to install and execute a modified version of the | ||
| 120 | Combined Work produced by recombining or relinking the | ||
| 121 | Application with a modified version of the Linked Version. (If | ||
| 122 | you use option 4d0, the Installation Information must accompany | ||
| 123 | the Minimal Corresponding Source and Corresponding Application | ||
| 124 | Code. If you use option 4d1, you must provide the Installation | ||
| 125 | Information in the manner specified by section 6 of the GNU GPL | ||
| 126 | for conveying Corresponding Source.) | ||
| 127 | |||
| 128 | 5. Combined Libraries. | ||
| 129 | |||
| 130 | You may place library facilities that are a work based on the | ||
| 131 | Library side by side in a single library together with other library | ||
| 132 | facilities that are not Applications and are not covered by this | ||
| 133 | License, and convey such a combined library under terms of your | ||
| 134 | choice, if you do both of the following: | ||
| 135 | |||
| 136 | a) Accompany the combined library with a copy of the same work based | ||
| 137 | on the Library, uncombined with any other library facilities, | ||
| 138 | conveyed under the terms of this License. | ||
| 139 | |||
| 140 | b) Give prominent notice with the combined library that part of it | ||
| 141 | is a work based on the Library, and explaining where to find the | ||
| 142 | accompanying uncombined form of the same work. | ||
| 143 | |||
| 144 | 6. Revised Versions of the GNU Lesser General Public License. | ||
| 145 | |||
| 146 | The Free Software Foundation may publish revised and/or new versions | ||
| 147 | of the GNU Lesser General Public License from time to time. Such new | ||
| 148 | versions will be similar in spirit to the present version, but may | ||
| 149 | differ in detail to address new problems or concerns. | ||
| 150 | |||
| 151 | Each version is given a distinguishing version number. If the | ||
| 152 | Library as you received it specifies that a certain numbered version | ||
| 153 | of the GNU Lesser General Public License "or any later version" | ||
| 154 | applies to it, you have the option of following the terms and | ||
| 155 | conditions either of that published version or of any later version | ||
| 156 | published by the Free Software Foundation. If the Library as you | ||
| 157 | received it does not specify a version number of the GNU Lesser | ||
| 158 | General Public License, you may choose any version of the GNU Lesser | ||
| 159 | General Public License ever published by the Free Software Foundation. | ||
| 160 | |||
| 161 | If the Library as you received it specifies that a proxy can decide | ||
| 162 | whether future versions of the GNU Lesser General Public License shall | ||
| 163 | apply, that proxy's public statement of acceptance of any version is | ||
| 164 | permanent authorization for you to choose that version for the | ||
| 165 | Library. | ||
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..869f9fb --- /dev/null +++ b/Makefile | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | clean: | ||
| 2 | make -C src clean | ||
| 3 | cd src; phpize --clean | ||
| 4 | |||
| 5 | debug: | ||
| 6 | cd src; phpize | ||
| 7 | export CFLAGS="-Wall -Wextra -g3 -ggdb -Wno-unused-function"; cd src; ./configure --enable-snuffleupagus --enable-debug | ||
| 8 | make -C src | ||
| 9 | TEST_PHP_ARGS='-q' REPORT_EXIT_STATUS=1 make -C src test | ||
| 10 | |||
| 11 | coverage: | ||
| 12 | cd src; phpize | ||
| 13 | export CFLAGS="--coverage -fprofile-arcs -ftest-coverage -O0"; export LDFLAGS="--coverage"; cd src; ./configure --enable-snuffleupagus --enable-coverage | ||
| 14 | make -C src | ||
| 15 | lcov --base-directory src --directory ./src --zerocounters -q --rc lcov_branch_coverage=1 | ||
| 16 | rm -Rf src/COV.html | ||
| 17 | TEST_PHP_ARGS='-q' REPORT_EXIT_STATUS=1 make -C src test | ||
| 18 | lcov --base-directory ./src --directory src -c -o ./src/COV.info --rc lcov_branch_coverage=1 2>/dev/null 1>/dev/null | ||
| 19 | lcov --remove src/COV.info '/usr/*' --remove src/COV.info '*tweetnacl.c' -o src/COV.info --rc lcov_branch_coverage=1 2>/dev/null 1>/dev/null | ||
| 20 | genhtml -o src/COV.html ./src/COV.info --branch-coverage | ||
| 21 | |||
| 22 | tests: joomla | ||
| 23 | |||
| 24 | joomla: | ||
| 25 | if [ -nd "joomla-cms" ]; then git clone --depth 1 git@github.com:joomla/joomla-cms.git; fi | ||
| 26 | cd joomla-cms; composer install | ||
| 27 | cd joomla-cms; libraries/vendor/phpunit/phpunit/phpunit -d extension=./src/modules/snuffleupagus.so | ||
| 28 | |||
| 29 | packages: debian | ||
| 30 | |||
| 31 | debian: | ||
| 32 | dpkg-buildpackage -i -us -uc -tc -I -rfakeroot | ||
diff --git a/README.md b/README.md new file mode 100644 index 0000000..53b9003 --- /dev/null +++ b/README.md | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | [](https://gitlab.nbs-system.com/secu/snuffleupagus/commits/master) | ||
| 3 | [](https://gitlab.nbs-system.com/secu/snuffleupagus/commits/master) | ||
| 5 | [Documentation]( https://secu.gitlab-pages.nbs-system.com/snuffleupagus/ ) | ||
| 6 | |||
| 7 | # Code style | ||
| 8 | We're using [clang-format](http://clang.llvm.org/docs/ClangFormat.html) to | ||
| 9 | ensure a consistent code-style. Please run it with `clang-format -style=google` | ||
| 10 | before committing, or even better, use a [pre-commit hook](https://github.com/andrewseidl/githook-clang-format) | ||
| 11 | |||
| 12 | # Resources | ||
| 13 | - The [writeup]( https://github.com/beberlei/whitewashing.de/blob/master/drafts/porting_extension_to_php7.rst) of [tideway profiler](https://github.com/tideways/php-profiler-extension)'s port to php7 | ||
| 14 | - [Upgrading to php-ng]( https://wiki.php.net/phpng-upgrading ) | ||
| 15 | - PHP7 [virtual machine](https://nikic.github.io/2017/04/14/PHP-7-Virtual-machine.html) | ||
diff --git a/config/default.ini b/config/default.ini new file mode 100644 index 0000000..0f67632 --- /dev/null +++ b/config/default.ini | |||
| @@ -0,0 +1,54 @@ | |||
| 1 | # Harden the `chmod` function | ||
| 2 | sp.disable_functions.function("chmod").param("mode").value_r("^[0-9]{2}[67]$").drop(); | ||
| 3 | sp.disable_functions.function("chmod").param("mode").value_r("o\\+w$").drop(); | ||
| 4 | |||
| 5 | # Prevent various `mail`-related vulnerabilities | ||
| 6 | sp.disable_functions.function("mail").param("additional_parameters").value_r("\\-").drop(); | ||
| 7 | |||
| 8 | ##Prevent various `include`-related vulnerabilities | ||
| 9 | sp.disable_functions.function_r("^(?:require|include)_once$").value_r("\\.(?:php|php7|inc|tpl)$").allow(); | ||
| 10 | sp.disable_functions.function_r("^require|include$").value_r("\\.(?:php|php7|inc|tpl)$").allow(); | ||
| 11 | sp.disable_functions.function_r("^(?:require|include)_once$").drop(); | ||
| 12 | sp.disable_functions.function_r("^require|include$").drop(); | ||
| 13 | |||
| 14 | # Prevent `system`-related injections | ||
| 15 | sp.disable_functions.function("system").param("command").value_r("[$|;&`\\n]").drop(); | ||
| 16 | sp.disable_functions.function("shell_exec").param("command").value_r("[$|;&`\\n]").drop(); | ||
| 17 | sp.disable_functions.function("exec").param("command").value_r("[$|;&`\\n]").drop(); | ||
| 18 | sp.disable_functions.function("proc_open").param("command").value_r("[$|;&`\\n]").drop(); | ||
| 19 | |||
| 20 | # Prevent runtime modification of interesting things | ||
| 21 | sp.disable_functions.function("ini_set").param("var_name").value("assert.active").drop(); | ||
| 22 | sp.disable_functions.function("ini_set").param("var_name").value("zend.assertions").drop(); | ||
| 23 | sp.disable_functions.function("ini_set").param("var_name").value("memory_limit").drop(); | ||
| 24 | sp.disable_functions.function("ini_set").param("var_name").value("include_path").drop(); | ||
| 25 | sp.disable_functions.function("ini_set").param("var_name").value("open_basedir").drop(); | ||
| 26 | |||
| 27 | # Detect some backdoors via environnement recon | ||
| 28 | sp.disable_functions.function("ini_get").param("var_name").value_r("(?:allow_url_fopen|open_basedir|suhosin)").drop(); | ||
| 29 | sp.disable_functions.function("function_exists").param("function_name").value_r("(?:eval|exec|system)").drop(); | ||
| 30 | sp.disable_functions.function("is_callable").param("var").value_r("(?:eval|exec|system)").drop(); | ||
| 31 | |||
| 32 | # Ghetto sqli hardening | ||
| 33 | sp.disable_functions.function_r("mysqli?_query").param("query").value_r("/\\*").drop(); | ||
| 34 | sp.disable_functions.function_r("mysqli?_query").param("query").value_r("--").drop(); | ||
| 35 | sp.disable_functions.function_r("mysqli?_query").param("query").value_r("#").drop(); | ||
| 36 | sp.disable_functions.function_r("mysqli?_query").param("query").value_r(";.*;").drop(); | ||
| 37 | sp.disable_functions.function_r("mysqli?_query").param("query").value_r("benchmark").drop(); | ||
| 38 | sp.disable_functions.function_r("mysqli?_query").param("query").value_r("sleep").drop(); | ||
| 39 | sp.disable_functions.function_r("mysqli?_query").param("query").value_r("information_schema").drop(); | ||
| 40 | sp.disable_functions.function("PDO::query").param("query").value_r("/\\*").drop(); | ||
| 41 | sp.disable_functions.function("PDO::query").param("query").value_r("--").drop(); | ||
| 42 | sp.disable_functions.function("PDO::query").param("query").value_r("#").drop(); | ||
| 43 | sp.disable_functions.function("PDO::query").param("query").value_r(";.*;").drop(); | ||
| 44 | sp.disable_functions.function("PDO::query").param("query").value_r("benchmark\\s*\\(").drop(); | ||
| 45 | sp.disable_functions.function("PDO::query").param("query").value_r("sleep\\s*\\(").drop(); | ||
| 46 | sp.disable_functions.function("PDO::query").param("query").value_r("information_schema").drop(); | ||
| 47 | |||
| 48 | # Ghetto sqli detection | ||
| 49 | sp.disable_functions.function_r("mysqli?_query").ret("FALSE").drop(); | ||
| 50 | sp.disable_functions.function_r("PDO::query").ret("FALSE").drop(); | ||
| 51 | |||
| 52 | #File upload | ||
| 53 | sp.disable_functions.function("move_uploaded_file").param("destination").value_r("\\.ph").drop(); | ||
| 54 | sp.disable_functions.function("move_uploaded_file").param("destination").value_r("\\.ht").drop(); | ||
diff --git a/config/examples.ini b/config/examples.ini new file mode 100644 index 0000000..d7599fb --- /dev/null +++ b/config/examples.ini | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | # Restrict system calls to specific file | ||
| 2 | sp.disable_functions.function("system").filename("update.php").allow(); | ||
| 3 | sp.disable_functions.function("system").drop(); | ||
| 4 | |||
| 5 | |||
| 6 | # Restrict system calls to specific file with a specific hash | ||
| 7 | sp.disable_functions.function("system").filename("update.php").hash("d27c6c5686bc129716b6aac8dfefe2d519a80eb6cc144e97ad42c728d423eed0").allow(); | ||
| 8 | sp.disable_functions.function("system").drop(); | ||
| 9 | |||
| 10 | |||
| 11 | # AbanteCart 1.2.8 - Multiple SQL Injections <https://blog.ripstech.com/2016/abantecart-multiple-sql-injections> | ||
| 12 | sp.disable_functions.filename("static_pages/index.php").var("_SERVER[PHP_SELF").value_r("\"").drop().alias("XSS"); | ||
| 13 | sp.disable_functions.filename("core/lib/language_manager.php").function("ALanguageManager>_clone_language_rows").param("from_language").value_r("[^0-9]").drop(); | ||
| 14 | sp.disable_functions.filename("admin/model/tool/backup.php").function("ModelToolBackup>createBackupTask").param("data[table_list]").value_r("'").drop(); | ||
| 15 | |||
| 16 | |||
| 17 | # Redaxo 5.2.0: Remote Code Execution via CSRF <https://blog.ripstech.com/2016/redaxo-remote-code-execution-via-csrf> | ||
| 18 | # See <http://code.vtiger.com/vtiger/vtigercrm/commit/9b5c5338f80237ae072a06e1ba4a5cfcbfe063b0> for details | ||
| 19 | sp.disable_functions.filename("redaxo/src/addons/structure/pages/linkmap.php").function("substr").param("string").value_r("\"").drop(); | ||
| 20 | |||
| 21 | |||
| 22 | # Guest Post: Vtiger 6.5.0 - SQL Injection <https://blog.ripstech.com/2016/vtiger-sql-injection/> | ||
| 23 | sp.disable_functions.filename("modules/Calendar/Activity.php").function("save_module").param("query").value_r("[^0-9;]").drop(); | ||
| 24 | |||
| 25 | |||
| 26 | # The State of Wordpress Security <https://blog.ripstech.com/2016/the-state-of-wordpress-security> | ||
| 27 | # All In One WP Security & Firewall | ||
| 28 | sp.disable_functions.filename("admin/wp-security-dashboard-menu.php").function("render_tab3").var("_REQUEST[tab]]").value_r("\"").drop(); | ||
| 29 | |||
| 30 | |||
| 31 | # PHPKit 1.6.6: Code Execution for Privileged Users <https://blog.ripstech.com/2016/phpkit-code-exection-for-privileged-users> | ||
| 32 | sp.disable_functions.filename("pkinc/func/default.php").function("move_uploaded_file").param("destination").value_r("\\.ph\\.+$").drop(); | ||
| 33 | |||
| 34 | |||
| 35 | # Coppermine 1.5.42: Second-Order Command Execution <https://blog.ripstech.com/2016/coppermine-second-order-command-execution> | ||
| 36 | sp.disable_functions.filename("include/imageobject_im.class.php").function("exec").var("CONFIG[im_options]).value_r("[^a-z0-9]").drop(); | ||
| 37 | sp.disable_functions.filename("forgot_passwd.php").function("cpg_db_query").var("CLEAN[id]").value_r("[^a-z0-9]").drop(); | ||
| 38 | |||
| 39 | |||
| 40 | # CVE-2014-1610 - Mediawiki RCE | ||
| 41 | sp.disable_functions.filename("includes/media/DjVu.php") | ||
| 42 | sp.disable_functions.filename("includes/media/ImageHandler.php").var("_GET[page]").value_r("[^0-9]").drop() | ||
| 43 | |||
| 44 | |||
| 45 | #Â CVE-2017-1001000 - https://blog.sucuri.net/2017/02/content-injection-vulnerability-wordpress-rest-api.html | ||
| 46 | sp.disable_functions.filename("wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php").function("register_routes").var("_GET[id]").value_r("[^0-9]").drop(); | ||
| 47 | sp.disable_functions.filename("wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php").function("register_routes").var("_POST[id]").value_r("[^0-9]").drop(); \ No newline at end of file | ||
diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..6d301b8 --- /dev/null +++ b/debian/changelog | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | snuffleupagus (0.1) UNRELEASED; urgency=medium | ||
| 2 | |||
| 3 | * Initial release. | ||
| 4 | |||
| 5 | -- jvoisin <snuffleupagus@nbs-system.com> Tue, 04 Jul 2017 17:51:31 +0200 | ||
diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..f599e28 --- /dev/null +++ b/debian/compat | |||
| @@ -0,0 +1 @@ | |||
| 10 | |||
diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..c1cfb92 --- /dev/null +++ b/debian/control | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | Source: snuffleupagus | ||
| 2 | Priority: optional | ||
| 3 | Maintainer: NBS System <snuffleupagus@nbs-system.com> | ||
| 4 | Build-Depends: debhelper (>= 9), php7.0-dev | ||
| 5 | Standards-Version: 3.9.2 | ||
| 6 | Homepage: https://snuffleupagus.fr | ||
| 7 | Section: php | ||
| 8 | Vcs-Git: https://github.com/nbs-system/snuffleupagus | ||
| 9 | |||
| 10 | Package: snuffleupagus | ||
| 11 | Architecture: any | ||
| 12 | Depends: ${misc:Depends} | ||
| 13 | Description: Hardening for your php7 stack | ||
| 14 | Snuffleupagus is cool | ||
diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..a792452 --- /dev/null +++ b/debian/copyright | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ | ||
| 2 | Upstream-Name: Snuffleupagus | ||
| 3 | Upstream-Contact: NBS System <snuffleupagus@nbs-system.com> | ||
| 4 | Source: https://github.com/nbs-system/snuffleupagus | ||
| 5 | |||
| 6 | Files: * | ||
| 7 | Copyright: 2017 NBS System | ||
| 8 | License: LGPL | ||
diff --git a/debian/docs b/debian/docs new file mode 100644 index 0000000..b43bf86 --- /dev/null +++ b/debian/docs | |||
| @@ -0,0 +1 @@ | |||
| README.md | |||
diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..66bf44a --- /dev/null +++ b/debian/rules | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | #!/usr/bin/make -f | ||
| 2 | |||
| 3 | DH_VERBOSE = 1 | ||
| 4 | |||
| 5 | DPKG_EXPORT_BUILDFLAGS = 1 | ||
| 6 | include /usr/share/dpkg/default.mk | ||
| 7 | |||
| 8 | export DEB_BUILD_MAINT_OPTIONS = hardening=+all | ||
| 9 | |||
| 10 | %: | ||
| 11 | dh $@ | ||
| 12 | |||
| 13 | override_dh_auto_clean: | ||
| 14 | cd ./src; phpize --clean | ||
| 15 | |||
| 16 | override_dh_auto_configure: | ||
| 17 | cd ./src; phpize | ||
| 18 | cd ./src; ./configure --enable-snuffleupagus | ||
| 19 | |||
| 20 | override_dh_auto_build: | ||
| 21 | make -C src | ||
| 22 | |||
| 23 | override_dh_auto_install: | ||
| 24 | make -C src install | ||
| 25 | |||
| 26 | override_dh_auto_test: | ||
| 27 | TEST_PHP_ARGS="-q" REPORT_EXIST_STATUS=1 make -C src test | ||
diff --git a/debian/watch b/debian/watch new file mode 100644 index 0000000..86028c7 --- /dev/null +++ b/debian/watch | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | version=3 | ||
| 2 | https://github.com/nbs-system/snuffleupagus/tags /nbs-system/snuffleupagus/archive/snuffleupagus-([0-9.]+)\.tar\.(gz|xz|bz2) | ||
diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 0000000..7355011 --- /dev/null +++ b/doc/Makefile | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | # Minimal makefile for Sphinx documentation | ||
| 2 | # | ||
| 3 | |||
| 4 | # You can set these variables from the command line. | ||
| 5 | SPHINXOPTS = | ||
| 6 | SPHINXBUILD = sphinx-build | ||
| 7 | SPHINXPROJ = Snuffleupagus | ||
| 8 | SOURCEDIR = source | ||
| 9 | BUILDDIR = build | ||
| 10 | |||
| 11 | # Put it first so that "make" without argument is like "make help". | ||
| 12 | help: | ||
| 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) | ||
| 14 | |||
| 15 | .PHONY: help Makefile | ||
| 16 | |||
| 17 | # Catch-all target: route all unknown targets to Sphinx using the new | ||
| 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). | ||
| 19 | %: Makefile | ||
| 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file | ||
diff --git a/doc/source/_static/custom.css b/doc/source/_static/custom.css new file mode 100644 index 0000000..1c47d04 --- /dev/null +++ b/doc/source/_static/custom.css | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | blockquote { | ||
| 2 | border-left: 2px solid #999; | ||
| 3 | padding-left: 20px; | ||
| 4 | } \ No newline at end of file | ||
diff --git a/doc/source/_static/sp.jpg b/doc/source/_static/sp.jpg new file mode 100644 index 0000000..0575ca7 --- /dev/null +++ b/doc/source/_static/sp.jpg | |||
| Binary files differ | |||
diff --git a/doc/source/conf.py b/doc/source/conf.py new file mode 100644 index 0000000..b2af5f2 --- /dev/null +++ b/doc/source/conf.py | |||
| @@ -0,0 +1,178 @@ | |||
| 1 | # -*- coding: utf-8 -*- | ||
| 2 | # | ||
| 3 | # Snuffleupagus documentation build configuration file, created by | ||
| 4 | # sphinx-quickstart on Tue Jun 27 14:15:46 2017. | ||
| 5 | # | ||
| 6 | # This file is execfile()d with the current directory set to its | ||
| 7 | # containing dir. | ||
| 8 | # | ||
| 9 | # Note that not all possible configuration values are present in this | ||
| 10 | # autogenerated file. | ||
| 11 | # | ||
| 12 | # All configuration values have a default; values that are commented out | ||
| 13 | # serve to show the default. | ||
| 14 | |||
| 15 | # If extensions (or modules to document with autodoc) are in another directory, | ||
| 16 | # add these directories to sys.path here. If the directory is relative to the | ||
| 17 | # documentation root, use os.path.abspath to make it absolute, like shown here. | ||
| 18 | # | ||
| 19 | # import os | ||
| 20 | # import sys | ||
| 21 | # sys.path.insert(0, os.path.abspath('.')) | ||
| 22 | from datetime import datetime | ||
| 23 | |||
| 24 | |||
| 25 | # -- General configuration ------------------------------------------------ | ||
| 26 | |||
| 27 | # If your documentation needs a minimal Sphinx version, state it here. | ||
| 28 | # | ||
| 29 | # needs_sphinx = '1.0' | ||
| 30 | |||
| 31 | # Add any Sphinx extension module names here, as strings. They can be | ||
| 32 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom | ||
| 33 | # ones. | ||
| 34 | #extensions = ['sphinx.ext.githubpages'] | ||
| 35 | |||
| 36 | # Add any paths that contain templates here, relative to this directory. | ||
| 37 | templates_path = ['_templates'] | ||
| 38 | |||
| 39 | # The suffix(es) of source filenames. | ||
| 40 | # You can specify multiple suffix as a list of string: | ||
| 41 | # | ||
| 42 | # source_suffix = ['.rst', '.md'] | ||
| 43 | source_suffix = '.rst' | ||
| 44 | |||
| 45 | # The master toctree document. | ||
| 46 | master_doc = 'index' | ||
| 47 | |||
| 48 | # General information about the project. | ||
| 49 | project = u'Snuffleupagus' | ||
| 50 | copyright = u'%d, NBS System' % datetime.now().year | ||
| 51 | author = u'Sebastien Blot & Julien Voisin' | ||
| 52 | |||
| 53 | # The version info for the project you're documenting, acts as replacement for | ||
| 54 | # |version| and |release|, also used in various other places throughout the | ||
| 55 | # built documents. | ||
| 56 | # | ||
| 57 | # The short X.Y version. | ||
| 58 | version = u'0.1' | ||
| 59 | # The full version, including alpha/beta/rc tags. | ||
| 60 | release = u'Public Alpha' | ||
| 61 | |||
| 62 | # The language for content autogenerated by Sphinx. Refer to documentation | ||
| 63 | # for a list of supported languages. | ||
| 64 | # | ||
| 65 | # This is also used if you do content translation via gettext catalogs. | ||
| 66 | # Usually you set "language" from the command line for these cases. | ||
| 67 | language = None | ||
| 68 | |||
| 69 | # List of patterns, relative to source directory, that match files and | ||
| 70 | # directories to ignore when looking for source files. | ||
| 71 | # This patterns also effect to html_static_path and html_extra_path | ||
| 72 | exclude_patterns = [] | ||
| 73 | |||
| 74 | # The name of the Pygments (syntax highlighting) style to use. | ||
| 75 | pygments_style = 'manni' | ||
| 76 | |||
| 77 | # If true, `todo` and `todoList` produce output, else they produce nothing. | ||
| 78 | todo_include_todos = False | ||
| 79 | |||
| 80 | |||
| 81 | # -- Options for HTML output ---------------------------------------------- | ||
| 82 | |||
| 83 | # The theme to use for HTML and HTML Help pages. See the documentation for | ||
| 84 | # a list of builtin themes. | ||
| 85 | # | ||
| 86 | html_theme = 'alabaster' | ||
| 87 | |||
| 88 | # Theme options are theme-specific and customize the look and feel of a theme | ||
| 89 | # further. For a list of options available for each theme, see the | ||
| 90 | # documentation. | ||
| 91 | # | ||
| 92 | |||
| 93 | html_sidebars = { | ||
| 94 | '**': [ | ||
| 95 | 'about.html', | ||
| 96 | 'navigation.html', | ||
| 97 | 'relations.html', | ||
| 98 | 'searchbox.html', | ||
| 99 | #'donate.html', | ||
| 100 | ] | ||
| 101 | } | ||
| 102 | html_theme_options = { | ||
| 103 | 'logo': './sp.jpg', | ||
| 104 | #'description': '<br>Killing bug-classes in PHP 7, virtual-patching the rest.', | ||
| 105 | #'fixed_sidebar': True, | ||
| 106 | 'page_width': '60%', | ||
| 107 | 'show_powered_by': False, | ||
| 108 | } | ||
| 109 | |||
| 110 | sidebar_collapse = True | ||
| 111 | |||
| 112 | # Add any paths that contain custom static files (such as style sheets) here, | ||
| 113 | # relative to this directory. They are copied after the builtin static files, | ||
| 114 | # so a file named "default.css" will overwrite the builtin "default.css". | ||
| 115 | html_static_path = ['_static'] | ||
| 116 | |||
| 117 | #html_logo = './sp.png' | ||
| 118 | |||
| 119 | html_show_sphinx = False | ||
| 120 | |||
| 121 | # -- Options for HTMLHelp output ------------------------------------------ | ||
| 122 | |||
| 123 | # Output file base name for HTML help builder. | ||
| 124 | htmlhelp_basename = 'Snuffleupagusdoc' | ||
| 125 | |||
| 126 | |||
| 127 | # -- Options for LaTeX output --------------------------------------------- | ||
| 128 | |||
| 129 | latex_elements = { | ||
| 130 | # The paper size ('letterpaper' or 'a4paper'). | ||
| 131 | # | ||
| 132 | # 'papersize': 'letterpaper', | ||
| 133 | |||
| 134 | # The font size ('10pt', '11pt' or '12pt'). | ||
| 135 | # | ||
| 136 | # 'pointsize': '10pt', | ||
| 137 | |||
| 138 | # Additional stuff for the LaTeX preamble. | ||
| 139 | # | ||
| 140 | # 'preamble': '', | ||
| 141 | |||
| 142 | # Latex figure (float) alignment | ||
| 143 | # | ||
| 144 | # 'figure_align': 'htbp', | ||
| 145 | } | ||
| 146 | |||
| 147 | # Grouping the document tree into LaTeX files. List of tuples | ||
| 148 | # (source start file, target name, title, | ||
| 149 | # author, documentclass [howto, manual, or own class]). | ||
| 150 | latex_documents = [ | ||
| 151 | (master_doc, 'Snuffleupagus.tex', u'Snuffleupagus Documentation', | ||
| 152 | u'Sebastien Blot \\& Julien Voisin', 'manual'), | ||
| 153 | ] | ||
| 154 | |||
| 155 | |||
| 156 | # -- Options for manual page output --------------------------------------- | ||
| 157 | |||
| 158 | # One entry per manual page. List of tuples | ||
| 159 | # (source start file, name, description, authors, manual section). | ||
| 160 | man_pages = [ | ||
| 161 | (master_doc, 'snuffleupagus', u'Snuffleupagus Documentation', | ||
| 162 | [author], 1) | ||
| 163 | ] | ||
| 164 | |||
| 165 | |||
| 166 | # -- Options for Texinfo output ------------------------------------------- | ||
| 167 | |||
| 168 | # Grouping the document tree into Texinfo files. List of tuples | ||
| 169 | # (source start file, target name, title, author, | ||
| 170 | # dir menu entry, description, category) | ||
| 171 | texinfo_documents = [ | ||
| 172 | (master_doc, 'Snuffleupagus', u'Snuffleupagus Documentation', | ||
| 173 | author, 'Snuffleupagus', 'One line description of project.', | ||
| 174 | 'Miscellaneous'), | ||
| 175 | ] | ||
| 176 | |||
| 177 | |||
| 178 | |||
diff --git a/doc/source/config.rst b/doc/source/config.rst new file mode 100644 index 0000000..8318e7d --- /dev/null +++ b/doc/source/config.rst | |||
| @@ -0,0 +1,283 @@ | |||
| 1 | Configuration | ||
| 2 | ============= | ||
| 3 | |||
| 4 | Since PHP *ini-like* configuration model isn't flexible enough, | ||
| 5 | Snuffleupagus is using its own format. | ||
| 6 | |||
| 7 | Options are chainable by using dots (``.``), and string parameters | ||
| 8 | **must** be quoted, while booleans and integers aren't. | ||
| 9 | |||
| 10 | Comments are prefixed either with ``#``, or ``;``. | ||
| 11 | |||
| 12 | Some rules applies in a specific ``function`` (context), on a specific ``variable`` | ||
| 13 | (data), like ``disable_functions``, others can only be enabled/disabled, like | ||
| 14 | ``harden_random``. | ||
| 15 | |||
| 16 | .. warning:: | ||
| 17 | |||
| 18 | Careful, a wrongly configured Snuffleupagus might break your website. | ||
| 19 | It's up to you to understand its :doc:`features <features>`, | ||
| 20 | read the present documentation about how to configure them, | ||
| 21 | evaluate your threat model, and write your configuration file accordingly. | ||
| 22 | |||
| 23 | The rules are evaluated in the order that they are written, and the **first** one | ||
| 24 | to match will terminate the evaluation (except for rules in simulation mode). | ||
| 25 | |||
| 26 | Bugclass-killer features | ||
| 27 | ------------------------ | ||
| 28 | |||
| 29 | global_strict | ||
| 30 | ^^^^^^^^^^^^^ | ||
| 31 | `default: disabled` | ||
| 32 | |||
| 33 | ``global_strict`` will enable the `strict <https://secure.php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration.strict>`_ mode globally, | ||
| 34 | forcing PHP to throw a `TypeError <https://secure.php.net/manual/en/class.typeerror.php>`_ | ||
| 35 | exception if an argument type being passed to a function does not match its corresponding declared parameter type. | ||
| 36 | |||
| 37 | It can either be ``enabled`` or ``disabled`` | ||
| 38 | |||
| 39 | :: | ||
| 40 | |||
| 41 | sp.global_strict.disable(); | ||
| 42 | sp.global_strict.enable(); | ||
| 43 | |||
| 44 | harden_random | ||
| 45 | ^^^^^^^^^^^^^ | ||
| 46 | * `default: enabled` | ||
| 47 | * `more <features.html#weak-prng-via-rand-mt-rand>`__ | ||
| 48 | |||
| 49 | ``harden_random`` will silently replace the insecure `rand <https://secure.php.net/manual/en/function.rand.php>`_ | ||
| 50 | and `mt_rand <https://secure.php.net/manual/en/function.mt-rand.php>`_ functions with | ||
| 51 | the secure PRNG `random_int <https://secure.php.net/manual/en/function.random-int.php>`_. | ||
| 52 | |||
| 53 | It can either be ``enabled`` or ``disabled``. | ||
| 54 | |||
| 55 | :: | ||
| 56 | |||
| 57 | sp.harden_random.enable(); | ||
| 58 | sp.harden_random.disable(); | ||
| 59 | |||
| 60 | .. _config_global: | ||
| 61 | |||
| 62 | global | ||
| 63 | ^^^^^^ | ||
| 64 | |||
| 65 | This configuration variable contain parameters that are used by other ones: | ||
| 66 | |||
| 67 | - ``secret_key``: A secret key used by various cryptographic features, | ||
| 68 | like `cookies protection <features.html#session-cookie-stealing-via-xss>`__ or `unserialize protection <features.html#unserialize-related-magic>`__, | ||
| 69 | so do make sure that it's random and long enough. | ||
| 70 | You can generate it with something like this: ``head -c 256 /dev/urandom | tr -dc 'a-zA-Z0-9'``. | ||
| 71 | |||
| 72 | :: | ||
| 73 | |||
| 74 | sp.global.secret_key("44239bd400aa82e125337c9d4eb8315767411ccd"); | ||
| 75 | |||
| 76 | unserialize_hmac | ||
| 77 | ^^^^^^^^^^^^^^^^ | ||
| 78 | * `default: disabled` | ||
| 79 | * `more <features.html#unserialize-related-magic>`__ | ||
| 80 | |||
| 81 | ``unserialize_hmac`` will add integrity check to ``unserialize`` calls, preventing | ||
| 82 | abritrary code execution in their context. | ||
| 83 | |||
| 84 | :: | ||
| 85 | |||
| 86 | sp.unserialize_hmac.enable(); | ||
| 87 | sp.unserialize_hmac.disable(); | ||
| 88 | |||
| 89 | |||
| 90 | auto_cookie_secure | ||
| 91 | ^^^^^^^^^^^^^^^^^^ | ||
| 92 | * `default: disabled` | ||
| 93 | * `more <features.html#session-cookie-stealing-via-xss>`__ | ||
| 94 | |||
| 95 | ``auto_cookie_secure`` will automatically mark cookies as `secure <https://en.wikipedia.org/wiki/HTTP_cookie#Secure_cookie>`_ | ||
| 96 | when the web page is requested over HTTPS. | ||
| 97 | |||
| 98 | It can either be ``enabled`` or ``disabled``. | ||
| 99 | |||
| 100 | :: | ||
| 101 | |||
| 102 | sp.auto_cookie_secure.enable(); | ||
| 103 | sp.auto_cookie_secure.disable(); | ||
| 104 | |||
| 105 | cookie_encryption | ||
| 106 | ^^^^^^^^^^^^^^^^^ | ||
| 107 | * `default: disabled` | ||
| 108 | * `more <features.html#session-cookie-stealing-via-xss>`__ | ||
| 109 | |||
| 110 | .. warning:: | ||
| 111 | |||
| 112 | To use this feature, you **must** set the :ref:`global.secret_key <config_global>` variable. | ||
| 113 | This design decision prevents attacker from | ||
| 114 | `trivially bruteforcing <https://www.idontplaydarts.com/2011/11/decrypting-suhosin-sessions-and-cookies/>`_ | ||
| 115 | session cookies. | ||
| 116 | |||
| 117 | ``cookie_secure`` will activate transparent encryption of specific cookies. | ||
| 118 | |||
| 119 | It can either be ``enabled`` or ``disabled``. | ||
| 120 | |||
| 121 | :: | ||
| 122 | |||
| 123 | sp.cookie_encryption.cookie("my_cookie_name"); | ||
| 124 | sp.cookie_encryption.cookie("another_cookie_name"); | ||
| 125 | |||
| 126 | |||
| 127 | readonly_exec | ||
| 128 | ^^^^^^^^^^^^^ | ||
| 129 | * `default: disabled` | ||
| 130 | |||
| 131 | ``readonly_exec`` will prevent the execution of writable PHP files. | ||
| 132 | |||
| 133 | It can either be ``enabled`` or ``disabled``. | ||
| 134 | |||
| 135 | :: | ||
| 136 | |||
| 137 | sp.readonly_exec.enable(); | ||
| 138 | |||
| 139 | upload_validation | ||
| 140 | ^^^^^^^^^^^^^^^^^ | ||
| 141 | * `default: disabled` | ||
| 142 | * `more <features.html#remote-code-execution-via-file-upload>`__ | ||
| 143 | |||
| 144 | ``upload_validation`` will call a given script upon a file upload, with the path | ||
| 145 | to the file being uploaded as argument, and various information about it in the environment: | ||
| 146 | |||
| 147 | * ``SP_FILENAME``: the name of the uploaded file | ||
| 148 | * ``SP_FILESIZE``: the size of the file being uploaded | ||
| 149 | * ``SP_REMOTE_ADDR``: the ip address of the uploader | ||
| 150 | * ``SP_CURRENT_FILE``: the current file being executed | ||
| 151 | |||
| 152 | This feature can be used, for example, to check if an uploaded file contains php | ||
| 153 | code, with something like `vld <https://derickrethans.nl/projects.html#vld>`_ | ||
| 154 | (``php -d vld.execute=0 -d vld.active=1 -d extension=vld.so yourfile.php``). | ||
| 155 | |||
| 156 | The upload will be **allowed** if the script return the value ``0``. Every other | ||
| 157 | value will prevent the file from being uploaded. | ||
| 158 | |||
| 159 | :: | ||
| 160 | |||
| 161 | sp.upload_validation.script("/var/www/is_valid_php.py").enable(); | ||
| 162 | |||
| 163 | |||
| 164 | disable_xxe | ||
| 165 | ^^^^^^^^^^^ | ||
| 166 | * `default: enabled` | ||
| 167 | * `more <features.html#xxe>`__ | ||
| 168 | |||
| 169 | ``disable_xxe`` will prevent XXE attacks by disabling the loading of external entities (``libxml_disable_entity_loader``) in the XML parser. | ||
| 170 | |||
| 171 | :: | ||
| 172 | |||
| 173 | sp.disable_xxe.enable(); | ||
| 174 | |||
| 175 | |||
| 176 | Virtual-patching | ||
| 177 | ---------------- | ||
| 178 | |||
| 179 | Snuffleupagus provides virtual-patching, via the ``disable_functions`` directive, allowing you to stop or control dangerous behaviours. | ||
| 180 | Admitting you have a call to ``system()`` that lacks proper user-input validation, thus leading to an **RCE**, this might be the right tool. | ||
| 181 | |||
| 182 | :: | ||
| 183 | |||
| 184 | # Allow `id.php` to restrict system() calls to `id` | ||
| 185 | sp.disable_functions.function("system").filename("id.php").param("cmd").value("id").allow(); | ||
| 186 | sp.disable_functions.function("system").filename("id.php").drop() | ||
| 187 | |||
| 188 | Of course, this is a trivial example, and a lot can be achieved with this feature, as you will see below. | ||
| 189 | |||
| 190 | |||
| 191 | Filters | ||
| 192 | ^^^^^^^ | ||
| 193 | |||
| 194 | - ``alias(:str)``: human-readable description of the rule | ||
| 195 | - ``cidr(ip/mask:str)``: match on the client's `cidr <https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing>`_ | ||
| 196 | - ``filename(name:str)``: match in the file ``name`` | ||
| 197 | - ``filename_r(regexp:str)``: the file name matching the ``regexp`` | ||
| 198 | - ``function(name:str)``: match on function ``name`` | ||
| 199 | - ``function_r(regexp:str)``: the function matching the ``regexp`` | ||
| 200 | - ``hash(:str)``: match on the file's `sha256 <https://en.wikipedia.org/wiki/SHA-2>`_ sum | ||
| 201 | - ``param(name:str)``: match on the function's parameter ``name`` | ||
| 202 | - ``param_r(regexp:str)``: match on the function's parameter ``regexp`` | ||
| 203 | - ``param_type(type:str)``: match on the function's parameter ``type`` | ||
| 204 | - ``ret(value:str)``: match on the function's return ``value`` | ||
| 205 | - ``ret_r(regexp:str)``: match with a ``regexp`` on the function's return | ||
| 206 | - ``ret_type(type_name:str)``: match on the ``type_name`` of the function's return value | ||
| 207 | - ``value(:str)``: match on a litteral value | ||
| 208 | - ``value_r(:regexp)``: match on a value matching the ``regexp`` | ||
| 209 | - ``var(name:str)``: match on a **local variable** ``name`` | ||
| 210 | |||
| 211 | The ``type`` must be one of the following values: | ||
| 212 | |||
| 213 | - ``FALSE``: for boolean false | ||
| 214 | - ``TRUE``: for boolean true | ||
| 215 | - ``NULL``: for the **null** value | ||
| 216 | - ``LONG``: for a long (also know as ``integer``) value | ||
| 217 | - ``DOUBLE``: for a **double** (also known as ``float``) value | ||
| 218 | - ``STRING``: for a string | ||
| 219 | - ``OBJECT``: for a object | ||
| 220 | - ``ARRAY``: for an array | ||
| 221 | - ``RESOURCE``: for a resource | ||
| 222 | |||
| 223 | Actions | ||
| 224 | ^^^^^^^ | ||
| 225 | |||
| 226 | - ``allow()``: **allow** the request if the rule matches | ||
| 227 | - ``drop()``: **drop** the request if the rule matches | ||
| 228 | - ``dump(directory:str)``: dump the request in the ``directory`` if it matches the rule | ||
| 229 | - ``simulation()``: enabled the simulation mode | ||
| 230 | |||
| 231 | Details | ||
| 232 | ^^^^^^^ | ||
| 233 | |||
| 234 | The ``function`` filter is able to do various dereferencing: | ||
| 235 | |||
| 236 | - ``function("AwesomeClass::my_method")`` will match in the method ``my_method`` in the class ``AwesomeClass`` | ||
| 237 | |||
| 238 | The ``param`` filter is also able to do some dereferencing: | ||
| 239 | |||
| 240 | - ``param(foo[bar])`` will get match on the value corresponding to the ``bar`` key in the hashtable ``foo``. | ||
| 241 | Remember that in PHP, almost every data structure is a hashtable. You can of course nest this like | ||
| 242 | ``param(foo[bar][baz][batman])``. | ||
| 243 | - The ``var`` filter will walk the calltrace until it finds the variable's name, or the end of it, | ||
| 244 | allowing to match on global variables: ``.var("_GET[param]")`` will match on the GET parameter ``param``. | ||
| 245 | |||
| 246 | For clarity's sake, the presence of the ``allow`` or ``drop`` action is **mandatory**. | ||
| 247 | |||
| 248 | .. warning:: | ||
| 249 | |||
| 250 | When you're writing rules, please do keep in mind that the **order matters**. | ||
| 251 | For example, if you're denying a call to ``system()`` and then allowing it in a | ||
| 252 | more narrowed way later, the call will be denied, | ||
| 253 | because it'll match the deny first. | ||
| 254 | |||
| 255 | If you're paranoid, we're providing a php script to automatically generate | ||
| 256 | hash of files containing dangerous functions, | ||
| 257 | and blacklisting them everywhere else. | ||
| 258 | |||
| 259 | Examples | ||
| 260 | ^^^^^^^^ | ||
| 261 | |||
| 262 | Evaluation order of rules | ||
| 263 | """"""""""""""""""""""""" | ||
| 264 | |||
| 265 | The following rules will: | ||
| 266 | |||
| 267 | 1. Allow calls to ``system("id")`` | ||
| 268 | 2. Issue a trace in the logs on calls to ``system`` with its parameters starting with ``ping``, | ||
| 269 | and pursuing evaluation of the remaining rules. | ||
| 270 | 3. Drop calls to ``system``. | ||
| 271 | |||
| 272 | |||
| 273 | :: | ||
| 274 | |||
| 275 | sp.disable_functions.function("system").param("cmd").value("id").allow(); | ||
| 276 | sp.disable_functions.function("system").param("cmd").value_r("^ping").drop().simulation(); | ||
| 277 | sp.disable_functions.function("system").param("cmd").drop(); | ||
| 278 | |||
| 279 | Miscellaneous examples | ||
| 280 | """""""""""""""""""""" | ||
| 281 | |||
| 282 | .. literalinclude:: ../../config/examples.ini | ||
| 283 | :language: python \ No newline at end of file | ||
diff --git a/doc/source/download.rst b/doc/source/download.rst new file mode 100644 index 0000000..161937f --- /dev/null +++ b/doc/source/download.rst | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | Download | ||
| 2 | ======== | ||
| 3 | |||
| 4 | Debian | ||
| 5 | ------ | ||
| 6 | |||
| 7 | |||
| 8 | Ubuntu | ||
| 9 | ------ | ||
| 10 | |||
| 11 | |||
| 12 | Source code | ||
| 13 | ----------- | ||
| 14 | |||
| 15 | :: | ||
| 16 | git clone https://github.com/nbs-system.com/snuffleupagus | ||
diff --git a/doc/source/faq.rst b/doc/source/faq.rst new file mode 100644 index 0000000..07aba33 --- /dev/null +++ b/doc/source/faq.rst | |||
| @@ -0,0 +1,196 @@ | |||
| 1 | FAQ | ||
| 2 | === | ||
| 3 | |||
| 4 | General | ||
| 5 | ------- | ||
| 6 | |||
| 7 | What is Snuffleupagus? | ||
| 8 | """""""""""""""""""""" | ||
| 9 | |||
| 10 | Snuffleupagus is a `PHP7+ <http://php.net/manual/en/migration70.php>`_ | ||
| 11 | module designed to drastically raising the cost of attacks against website, | ||
| 12 | by killing entire bug classes, and also providing a powerful virtual-patching system, | ||
| 13 | allowing administrator to fix specific vulnerabilities without having to touch the PHP code. | ||
| 14 | |||
| 15 | |||
| 16 | Where does the name *Snuffeupagus* comes from? | ||
| 17 | """""""""""""""""""""""""""""""""""""""""""""" | ||
| 18 | |||
| 19 | Aloysius Snuffleupagus, more commonly known as Mr. Snuffleupagus, Snuffleupagus | ||
| 20 | or Snuffy for short, is one of the characters on Sesame Street, | ||
| 21 | the educational television program for young children. | ||
| 22 | |||
| 23 | He was created as a woolly mammoth, without tusks or (visible) ears, | ||
| 24 | and has a long thick pointed tail, similar in shape to that of a dinosaur | ||
| 25 | or other reptile. He has long thick brown hair and a trunk, or "snuffle", | ||
| 26 | that drags along the ground. He is Big Bird's best friend and | ||
| 27 | has a baby sister named Alice. He also attends "Snufflegarten". | ||
| 28 | |||
| 29 | --- `Wikipedia <https://en.wikipedia.org/wiki/Mr._Snuffleupagus>`_ | ||
| 30 | |||
| 31 | |||
| 32 | Why is Snuffleupagus called Snuffleupagus? | ||
| 33 | """""""""""""""""""""""""""""""""""""""""" | ||
| 34 | |||
| 35 | Like PHP's `ElePHPant <https://secure.php.net/elephpant.php>`_, | ||
| 36 | we thought that using an elephant as a mascot would be a great idea. | ||
| 37 | |||
| 38 | |||
| 39 | Why did you write Snuffleupagus? | ||
| 40 | """""""""""""""""""""""""""""""" | ||
| 41 | |||
| 42 | We're working for `NBS System <https://nbs-system.com/en/>`__, | ||
| 43 | a web hosting company (meaning that we're dealing with PHP code all day long), | ||
| 44 | with a strong focus on security. We do have hardening | ||
| 45 | (kernel, `WAF <https://naxsi.org>`_, `IDS <https://en.wikipedia.org/wiki/Intrusion_detection_system>`_, …) | ||
| 46 | below the web stack, but most of the time, when a website is compromised, | ||
| 47 | it's either to send ads, spam, deface it, steal data, … | ||
| 48 | This is why we need to harden the website itself too, but we can't touch its | ||
| 49 | source code. | ||
| 50 | |||
| 51 | Why not Suhosin? | ||
| 52 | """""""""""""""" | ||
| 53 | |||
| 54 | We're huge fans of `Suhosin <https://suhosin.org>`_, unfortunately: | ||
| 55 | |||
| 56 | - it doesn't work very well on PHP 7 | ||
| 57 | - it has some oudated features and misses new ones | ||
| 58 | - it doesn't cope very well with our various industrialization needs | ||
| 59 | - it has some shortcomings by design | ||
| 60 | |||
| 61 | We're using the `disable_function <https://secure.php.net/manual/en/ini.core.php#ini.disable-functions>`_ | ||
| 62 | directive, but unfortunately, it doesn't provide enough usable granularity (guess how many CMS are using | ||
| 63 | ``system`` to do various mandatory maintenance tasks…). | ||
| 64 | |||
| 65 | This is why we decided to write our own hardening module, in the spirit of Suhosin, | ||
| 66 | via virtual-patching support, and other cool new features. | ||
| 67 | |||
| 68 | What license is Snuffleupagus under and why? | ||
| 69 | """""""""""""""""""""""""""""""""""""""""""" | ||
| 70 | |||
| 71 | Snuffleupagus is licensed under the `LGPL <https://www.gnu.org/copyleft/lesser.html>`_, | ||
| 72 | and is developed by the fine people from `NBS System <https://nbs-system.com/>`__. | ||
| 73 | |||
| 74 | We chose the LGPL because we don't care that much how you're using Snuffleupagus, | ||
| 75 | but we'd like to force people to make their improvements/contributions | ||
| 76 | available to everyone. | ||
| 77 | |||
| 78 | Should I use Snuffleupagus? | ||
| 79 | """"""""""""""""""""""""""" | ||
| 80 | |||
| 81 | Yes. | ||
| 82 | |||
| 83 | Even if you're not using the virtual-patching capabilities, Snuffleupagus comes | ||
| 84 | with various passive features that won't break your website while killing numerous vulnerabilities. | ||
| 85 | |||
| 86 | Please keep in mind that you are not only protecting yourself and your users/customers, | ||
| 87 | but also other people on the internet that might be attacked by your server if | ||
| 88 | it becomes compromised. | ||
| 89 | |||
| 90 | How mature is this project? | ||
| 91 | """"""""""""""""""""""""""" | ||
| 92 | |||
| 93 | This project was floating around since early 2016, and we did the first commit | ||
| 94 | the 28ᵗʰ of December of the same year. We're currently in a private alpha phase, | ||
| 95 | finding and fixing as much bugs as possible with the help of friends. | ||
| 96 | |||
| 97 | Are you saying that PHP isn't secure? | ||
| 98 | """"""""""""""""""""""""""""""""""""" | ||
| 99 | |||
| 100 | We don't like PHP's approach of security; namely (sometimes) adding warnings | ||
| 101 | in the documentation and trusting the developer to not do any mistake, | ||
| 102 | instead of focusing on the root cause, and killing the | ||
| 103 | bug class one for all. | ||
| 104 | |||
| 105 | Moreover, it seems that the current attitude toward security in the PHP world | ||
| 106 | is to `blame the user <https://externals.io/message/100147>`_ instead of acknowledging | ||
| 107 | issues, as stated in their `documentation <https://wiki.php.net/security#not_a_security_issue>`_. | ||
| 108 | We do think that an security issue that "requires the use of code or settings known to be insecure" | ||
| 109 | is still a security issue, and should be treated as such. | ||
| 110 | |||
| 111 | Installation and configuration | ||
| 112 | ------------------------------ | ||
| 113 | |||
| 114 | Can snuffleupagus break my application? | ||
| 115 | """"""""""""""""""""""""""""""""""""""" | ||
| 116 | Yes. | ||
| 117 | |||
| 118 | Some options won't break anything, like ``harden_rand``, but some like ``global_strict`` | ||
| 119 | or overly-restrictives virtual-patching rules might pretty well break your website. | ||
| 120 | It's up to you to configure Snuffleupaggus accordingly to your needs. | ||
| 121 | |||
| 122 | You can also enable the ``simulation`` mode on features that you're not sure about, | ||
| 123 | to see what would snuffleupagus do to your application, before activating them for good. | ||
| 124 | |||
| 125 | How can I find out the problem when my application breaks? | ||
| 126 | """""""""""""""""""""""""""""""""""""""""""""""""""""""""" | ||
| 127 | |||
| 128 | By checking the logs; Snuffleupagus systematically prefix them with ``[snuffleupagus]``. | ||
| 129 | |||
| 130 | |||
| 131 | Does Snuffleupagus run on Windows? | ||
| 132 | """""""""""""""""""""""""""""""""" | ||
| 133 | No idea. | ||
| 134 | |||
| 135 | |||
| 136 | Will Snuffleupagus run on my old PHP 5? | ||
| 137 | """"""""""""""""""""""""""""""""""""""" | ||
| 138 | No. | ||
| 139 | |||
| 140 | Since PHP5 `will be deprecated at the end of 2018 <http://php.net/supported-versions.php>`_, | ||
| 141 | you should think about moving to PHP7 anyway. You can (and should) use | ||
| 142 | `Suhosin <https://suhosin.org>`_ in the meantime. | ||
| 143 | |||
| 144 | Help and support | ||
| 145 | ---------------- | ||
| 146 | |||
| 147 | I found a security issue | ||
| 148 | """""""""""""""""""""""" | ||
| 149 | If you believe you have found a security issue affecting Snuffleupagus, | ||
| 150 | then we would be more than happy to hear from you! | ||
| 151 | |||
| 152 | We promise to treat any reported issue seriously and, | ||
| 153 | if the investigation confirms it affects Snuffleupagus, | ||
| 154 | to patch it within a reasonable time, | ||
| 155 | release a public announcement that describes the issue, | ||
| 156 | discuss potential impact of the vulnerability, | ||
| 157 | reference applicable patches or workarounds, | ||
| 158 | and credit the discoverer. | ||
| 159 | |||
| 160 | Please send it us a mail to the ``snuffleupagus`` user, | ||
| 161 | on ``nbs-system.com``. | ||
| 162 | |||
| 163 | I found a bug. How can I report it? | ||
| 164 | """"""""""""""""""""""""""""""""""" | ||
| 165 | We do have an issue tracker on `Github <https://github.com/nbs-system/snuffleupagus/issues>`_. | ||
| 166 | Please make sure to include as much information as possible when reporting your issue, | ||
| 167 | such as your operating system, your version of PHP 7, your version of snuffleupagus, | ||
| 168 | your logs, the problematic php code, the request, a brief description, … long story short, | ||
| 169 | give us everything that you can. | ||
| 170 | |||
| 171 | Where can I find even more help? | ||
| 172 | """""""""""""""""""""""""""""""" | ||
| 173 | The :doc:`configuration page <config>` might be what you're looking for. | ||
| 174 | If you're adventurous, you can also check the `issue tracker <https://github.com/nbs-system/snuffleupagus/issues/?q=is%3Aissue>`_ | ||
| 175 | (make sure to check the closed issues too). | ||
| 176 | |||
| 177 | I need professional support for my company. | ||
| 178 | """"""""""""""""""""""""""""""""""""""""""" | ||
| 179 | Contact `NBS System <https://nbs-system.com>`_. | ||
| 180 | |||
| 181 | Unimplemented mitigations and abandoned ideas | ||
| 182 | --------------------------------------------- | ||
| 183 | |||
| 184 | Contant time comparisons | ||
| 185 | """""""""""""""""""""""" | ||
| 186 | We didn't manage to perform time-based side-channel attacks on strings | ||
| 187 | against real world PHP application, and the results that we gathered on | ||
| 188 | tailored test cases weren't concluding: for simplicity's sake, we chose | ||
| 189 | to not implement a mitigation against this class of attacks. | ||
| 190 | |||
| 191 | We would be happy to be proven wrong, and reconsider implementing this feature, | ||
| 192 | if someone can manage to get better results than us. | ||
| 193 | |||
| 194 | The possibility of having this natively in PHP has | ||
| 195 | `been discussed <https://marc.info/?l=php-internals&m=141692988212413&w=2>`_, | ||
| 196 | but as 2017, nothing has been merged yet. | ||
diff --git a/doc/source/features.rst b/doc/source/features.rst new file mode 100644 index 0000000..89cd756 --- /dev/null +++ b/doc/source/features.rst | |||
| @@ -0,0 +1,352 @@ | |||
| 1 | Features | ||
| 2 | ======== | ||
| 3 | |||
| 4 | Snuffleupagus has a lot of features that can be divided in two main categories: bug-classes | ||
| 5 | killers and virtual-patching. The first category provides primitives to kill various | ||
| 6 | bug families (like arbitrary code execution via ``unserialize`` for example) or rise the | ||
| 7 | cost of exploitation, the second one is a highly configurable system to patch functions in php itself. | ||
| 8 | |||
| 9 | Bug classes killed | ||
| 10 | ------------------ | ||
| 11 | |||
| 12 | ``system`` injections | ||
| 13 | ^^^^^^^^^^^^^^^^^^^^^ | ||
| 14 | |||
| 15 | The ``system`` function execute an external program and displays the output. | ||
| 16 | It's used to interract with various external tools, like file-format converters for example. | ||
| 17 | Unfortunately, passing user-controlled parameters to it often leads to an arbitrary command execution. | ||
| 18 | |||
| 19 | When allowing user-supplied data to be passed to this function, | ||
| 20 | use `escapeshellarg()` or `escapeshellcmd()` to ensure that users cannot trick | ||
| 21 | the system into executing arbitrary commands. | ||
| 22 | |||
| 23 | --- `The PHP documentation about system <https://secure.php.net/manual/en/function.system.php>`_ | ||
| 24 | |||
| 25 | We're kind of killing it by filtering the ``$``, ``|``, ``;``, ````` and ``&`` chars in our | ||
| 26 | default configuration, making it a lot harder for an attacker to inject arbitrary commands. | ||
| 27 | |||
| 28 | This family of vulnerabilities lead to various CVE, like: | ||
| 29 | |||
| 30 | - `CVE-2017-7981 <https://tuleap.net/plugins/tracker/?aid=10159>`_: Authenticated remote code execution on Tuleap | ||
| 31 | - `CVE-2014-4688 <https://www.pfsense.org/security/advisories/pfSense-SA-14_10.webgui.asc>`_: Authenticated remote code execution on pfSense | ||
| 32 | - `CVE-2014-1610 <https://www.rapid7.com/db/modules/exploit/multi/http/mediawiki_thumb>`_: Unauthenticated remote code execution on DokuWiki | ||
| 33 | - `CVE-2013-3630 <https://www.rapid7.com/db/modules/exploit/multi/http/moodle_cmd_exec>`_: Authenticated remote code execution on Moodle | ||
| 34 | - Every single shitty `modem/router/switch/IoT <https://twitter.com/internetofshit>`_. | ||
| 35 | |||
| 36 | |||
| 37 | ``mail``-related injections | ||
| 38 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 39 | |||
| 40 | This vulnerability is known `since 2011 <http://esec-pentest.sogeti.com/posts/2011/11/03/using-mail-for-remote-code-execution.html>`_, | ||
| 41 | and was popularized by `RIPS <https://www.ripstech.com/blog/2016/roundcube-command-execution-via-email/>`_ in 2016. | ||
| 42 | The last flag of the `mail` function can be used to pass various parameters to | ||
| 43 | the underlying binary used to send emails: this can lead to an arbitrary file write, | ||
| 44 | often meaning an arbitrary code execution. | ||
| 45 | |||
| 46 | The ``additional_parameters`` parameter can be used to pass additional flags | ||
| 47 | as command line options to the program configured to be used when sending mail | ||
| 48 | |||
| 49 | --- `The PHP documentation about mail <https://secure.php.net/manual/en/function.mail.php>`_ | ||
| 50 | |||
| 51 | We're killing it by preventing any extra options in additional_parameters. | ||
| 52 | |||
| 53 | This family of vulnerabilities lead to various CVE, like: | ||
| 54 | |||
| 55 | - `CVE-2017-7692 <https://legalhackers.com/advisories/SquirrelMail-Exploit-Remote-Code-Exec-CVE-2017-7692-Vuln.html>`_: Authenticated remote code execution in SquirrelMail | ||
| 56 | - `CVE-2016-10074 <https://legalhackers.com/advisories/SwiftMailer-Exploit-Remote-Code-Exec-CVE-2016-10074-Vuln.html>`_: remote code execution in SwiftMailer | ||
| 57 | - `CVE-2016-10033 <https://legalhackers.com/advisories/PHPMailer-Exploit-Remote-Code-Exec-CVE-2016-10033-Vuln.html>`_: remote code execution in PHPMailer | ||
| 58 | - `CVE-2016-9920 <https://www.ripstech.com/blog/2016/roundcube-command-execution-via-email/>`_: Unauthenticated remote code execution in Roundcube | ||
| 59 | |||
| 60 | Session-cookie stealing via XSS | ||
| 61 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 62 | |||
| 63 | The goto payload for XSS is often to steal cookies. | ||
| 64 | Like *Suhosin*, we are encrypting the cookies with a secret key, the IP of the user | ||
| 65 | and its user-agent. This means that an attacker with an XSS won't be able to use | ||
| 66 | the stolen cookie, since he (often) can't spoof the IP address of the user. | ||
| 67 | |||
| 68 | This feature is roughly the same than the `Suhosin one <https://suhosin.org/stories/configuration.html#transparent-encryption-options>`_. | ||
| 69 | |||
| 70 | Users behind the same IP address but with different browsers won't be able to use each other stolen cookies, | ||
| 71 | except if they can manage to guess the user agent. This isn't especially difficult, | ||
| 72 | but an invalid decryption will leave a trace in the logs. | ||
| 73 | |||
| 74 | Finally, having a secret server-side key will prevent anyone (even the user himself) | ||
| 75 | from reading the content of the cookie, reducing the impact of an application storing sensitive data client-side. | ||
| 76 | |||
| 77 | The encryption is done via the [tweetnacl library](https://tweetnacl.cr.yp.to/), | ||
| 78 | thus using curve25519, xsalsa20 and poly1305 for the encryption. We chose this | ||
| 79 | library because of its portability, simplicity and reduced size (a single `.h` and | ||
| 80 | `.c` file.). | ||
| 81 | |||
| 82 | Remote code execution via file-upload | ||
| 83 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 84 | |||
| 85 | Some PHP applications allows users to upload contents, like avatars for a forum. | ||
| 86 | Unfortunately, sometimes, content validation isn't implemented properly (if at all), | ||
| 87 | meaning arbitrary file upload, often leading, contrary to what the documentation is saying, | ||
| 88 | to an arbitrary code execution. | ||
| 89 | |||
| 90 | Not validating which file you operate on may mean that users can *access sensitive information* in other directories. | ||
| 91 | |||
| 92 | --- `The PHP documentation about file uploads <https://secure.php.net/manual/en/features.file-upload.common-pitfalls.php>`_ | ||
| 93 | |||
| 94 | We're killing it, like Suhosin, by automatically calling a script upon file upload, | ||
| 95 | if it returns something else than ``0``, the file will be removed (or stored in a quarantine, | ||
| 96 | for further analysis). | ||
| 97 | |||
| 98 | We're recommending to use the `vld <https://derickrethans.nl/projects.html#vld>`_ project | ||
| 99 | inside the script to ensure the file doesn't contain any valid PHP code, with something like this: | ||
| 100 | |||
| 101 | :: | ||
| 102 | |||
| 103 | $ php -d vld.execute=0 -d vld.active=1 -d extension=vld.so $file | ||
| 104 | |||
| 105 | Unserialize-related magic | ||
| 106 | ^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 107 | |||
| 108 | PHP is able to *serialize* arbitrary objects, to easily store them. | ||
| 109 | Unfortunately, it's often possible to gain arbitrary code execution upon deserialization | ||
| 110 | of user-supplied serialized objects. | ||
| 111 | |||
| 112 | Do not pass untrusted user input to ``unserialize()`` regardless of the options value of allowed_classes. | ||
| 113 | Unserialization can result in code being loaded and executed due to object instantiation and autoloading, | ||
| 114 | and a malicious user may be able to exploit this. | ||
| 115 | |||
| 116 | --- `The PHP documentation about serialize <https://secure.php.net/manual/en/function.serialize.php>`_ | ||
| 117 | |||
| 118 | We're killing it by exploiting the fact that PHP will discard any garbage found at the end of a serialized object, | ||
| 119 | allowing us to simply append a `HMAC <https://en.wikipedia.org/wiki/Hash-based_message_authentication_code>`_ | ||
| 120 | at the end of strings generated by the ``serialize``, | ||
| 121 | hence guaranteeing that any object deserialized came from the application, | ||
| 122 | and wasn't tampered with, | ||
| 123 | |||
| 124 | We're not encrypting it, like we do with the cookies, | ||
| 125 | allowing this feature to be disabled (or switch into leaning mode) | ||
| 126 | without the need to invalidate any data. | ||
| 127 | |||
| 128 | .. warning:: | ||
| 129 | |||
| 130 | This feature can't be deployed on websites that already stored serialized | ||
| 131 | objects (ie. in database), since they are missing the HMAC, and thus will be detected as | ||
| 132 | an attack. If you're in this situation, you should use this feature with the | ||
| 133 | ``simulation`` mode, and switch it off once you don't have any messages in your | ||
| 134 | logs. | ||
| 135 | |||
| 136 | A nice side-effect of this feature is that it'll defeat various memory corruption | ||
| 137 | issues related to the complexity of ``unserialize``'s implementation, | ||
| 138 | and the amount of control if provides to an attacker, like `CVE-2016-9137, CVE-2016-9138 <https://bugs.php.net/bug.php?id=73147>`_, | ||
| 139 | `2016-7124 <https://bugs.php.net/bug.php?id=72663>`_, `CVE-2016-5771 and CVE-2016-5773 <https://www.evonide.com/how-we-broke-php-hacked-pornhub-and-earned-20000-dollar/>`_, … | ||
| 140 | |||
| 141 | This family of vulnerabilities lead to various CVE, like: | ||
| 142 | |||
| 143 | - `CVE-2016-???? <https://www.computest.nl/advisories/CT-2016-1110_Observium.txt>`_: Unauthenticated remote code execution in Observium (leading to remote root) | ||
| 144 | - `CVE-2016-5726 <http://seclists.org/oss-sec/2016/q2/521>`_: Unauthenticated remote code execution in Simple Machines Forums | ||
| 145 | - `CVE-2016-4010 <http://netanelrub.in/2016/05/17/magento-unauthenticated-remote-code-execution/>`_: Unauthenticated remote code execution in Magento | ||
| 146 | - `CVE-2017-2641 <http://netanelrub.in/2017/03/20/moodle-remote-code-execution/>`_: Unauthenticated remote code execution in Moodle | ||
| 147 | - `CVE-2015-8562 <https://www.rapid7.com/db/modules/exploit/multi/http/joomla_http_header_rce>`_: Unauthenticated remote code execution in Joomla | ||
| 148 | - `CVE-2015-7808 <https://www.rapid7.com/db/modules/exploit/multi/http/vbulletin_unserialize>`_: Unauthenticated remote code execution in vBulletin | ||
| 149 | - `CVE-2014-1691 <http://seclists.org/oss-sec/2014/q1/153>`_: Unauthenticated remote code execution in Horde | ||
| 150 | - `CVE-2012-5692 <https://www.rapid7.com/db/modules/exploit/unix/webapp/invision_pboard_unserialize_exec>`_: Unauthenticated remote code execution in IP.Board | ||
| 151 | |||
| 152 | |||
| 153 | |||
| 154 | Weak-PRNG via rand/mt_rand | ||
| 155 | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 156 | |||
| 157 | The functions ``rand`` and ``mt_rand`` are often used to generate random numbers used | ||
| 158 | in sensitive context, like password generation, token creation, … | ||
| 159 | Unfortunately, as said in the documentation, the quality of their entropy is low, | ||
| 160 | leading to the generation of guessable values. | ||
| 161 | |||
| 162 | This function does not generate cryptographically secure values, and should not be used for cryptographic purposes. | ||
| 163 | |||
| 164 | --- `The PHP documentation about rand <https://secure.php.net/manual/en/function.rand.php>`_ | ||
| 165 | |||
| 166 | We're addressing this issue by replacing every call to ``rand`` and ``mt_rand`` with | ||
| 167 | a call to the ``random_int``, a `CSPRNG <https://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator>`_. | ||
| 168 | |||
| 169 | It's worth noting that the PHP documentation contains the following warning: | ||
| 170 | |||
| 171 | ``min`` ``max`` range must be within the range ``getrandmax()``. i.e. ``(max - min) <= getrandmax()``. | ||
| 172 | Otherwise, ``rand()`` may return poor-quality random numbers. | ||
| 173 | |||
| 174 | --- `The PHP documentation about rand <https://secure.php.net/manual/en/function.rand.php>`_ | ||
| 175 | |||
| 176 | This is of course addressed as well by the ``harden_rand`` feature. | ||
| 177 | |||
| 178 | .. warning:: | ||
| 179 | |||
| 180 | Activating this feature will raise an `Error <https://secure.php.net/manual/en/class.error.php>`_ | ||
| 181 | exception if ``min`` is superior to ``max``, while the default dehaviour is simply to swap them. | ||
| 182 | |||
| 183 | This family of vulnerabilities lead to various CVE, like: | ||
| 184 | |||
| 185 | - `CVE-2015-5267 <https://moodle.org/mod/forum/discuss.php?d=320291>`_: Unauthenticated accounts takeover in in Moodle | ||
| 186 | - `CVE-2014-9624 <https://www.mantisbt.org/bugs/view.php?id=17984>`_: Captcha bypass in MantisBT | ||
| 187 | - `CVE-2014-6412 <https://core.trac.wordpress.org/ticket/28633>`_: Unauthenticated account takeover in Wordpress | ||
| 188 | - `CVE-2015-???? <https://hackerone.com/reports/31171>`_: Unauthenticated accounts takeover in Concrete5 | ||
| 189 | - `CVE-2013-6386 <https://www.drupal.org/SA-CORE-2013-003>`_: Unauthenticated accounts takeover in Drupal | ||
| 190 | - `CVE-2010-???? <http://www.sektioneins.com/advisories/advisory-022010-mybb-password-reset-weak-random-numbers-vulnerability.html>`_: Unauthenticated accounts takeover in MyBB | ||
| 191 | - `CVE-2008-4102 <https://sektioneins.de/en/advisories/advisory-042008-joomla-weak-random-password-reset-token-vulnerability.html>`_: Unauthenticated accounts takeover in Joomla | ||
| 192 | - `CVE-2006-0632 <https://www.cvedetails.com/cve/CVE-2006-0632/>`_: Unauthenticated account takeover in phpBB | ||
| 193 | |||
| 194 | XXE | ||
| 195 | ^^^ | ||
| 196 | |||
| 197 | Despite the documentation saying nothing about this class of vulnerabilities, | ||
| 198 | `XML eXternal Entitiy <https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Processing>`_ (XXE) are often leading to arbitrary file reading, SSRF, and sometimes even arbitrary | ||
| 199 | code execution. | ||
| 200 | |||
| 201 | XML documents can contain a `Document Type Definition <https://www.w3.org/TR/REC-xml/#sec-prolog-dtd>`_ (DTD), | ||
| 202 | enabling definition of XML entities. It's possible to define an (external) entity by an | ||
| 203 | URI, that the parser will access, and embed its content back into the document | ||
| 204 | for further processing. | ||
| 205 | |||
| 206 | For example, providing an url like ``file:///etc/passwd`` will read | ||
| 207 | this file's content, and since it's not valid XML, the application | ||
| 208 | will spit it out in an error message, thus leaking its content. | ||
| 209 | |||
| 210 | We're killing this class of vulnerabilities by calling | ||
| 211 | the `libxml_disable_entity_loader <https://secure.php.net/manual/en/function.libxml-disable-entity-loader.php>`_ | ||
| 212 | function with its parameter set to ``true`` at startup, | ||
| 213 | and then *nop'ing* it, so it won't do anything if ever called again. | ||
| 214 | |||
| 215 | This family of vulnerabilities lead to various CVE, like: | ||
| 216 | |||
| 217 | - `CVE-2015-5161 <https://legalhackers.com/advisories/eBay-Magento-XXE-Injection-Vulnerability.html>`_: Unauthenticated arbitrary file disclosure on Magento | ||
| 218 | - `CVE-2014-8790 <https://github.com/GetSimpleCMS/GetSimpleCMS/issues/944>`_: Unauthenticated remote code execution in GetSimple CMS | ||
| 219 | - `CVE-2011-4107 <https://www.phpmyadmin.net/security/PMASA-2011-17/>`_: Authenticated local file disclosure in PHPMyAdmin | ||
| 220 | |||
| 221 | |||
| 222 | Cookie stealing via HTTP MITM | ||
| 223 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 224 | |||
| 225 | While it's possible to set the ``secure`` flag on cookies to prevent them from being | ||
| 226 | transmitted over HTTP, and only allow its transmission over HTTPS. | ||
| 227 | Snuffleupagus can automatically set this flag if the client is accessing the | ||
| 228 | website over a secure connection. | ||
| 229 | |||
| 230 | This behaviour is suggested in the documentation: | ||
| 231 | |||
| 232 | On the server-side, it's on the programmer to send this kind of cookie only | ||
| 233 | on secure connection (e.g. with respect to ``$_SERVER["HTTPS"]``). | ||
| 234 | |||
| 235 | --- `The PHP documentation about setcookie <https://secure.php.net/manual/en/function.setcookie.php>`_ | ||
| 236 | |||
| 237 | |||
| 238 | Exploitation, post-exploitation and general hardening | ||
| 239 | ----------------------------------------------------- | ||
| 240 | |||
| 241 | Virtual-patching | ||
| 242 | ^^^^^^^^^^^^^^^^ | ||
| 243 | |||
| 244 | PHP itself exposes a number of functions that might be considered **dangerous** and that have limited legitimate use cases. | ||
| 245 | ``system()``, ``exec()``, ``dlopen()`` - for example - fall into this category. By default, PHP only allows to globally disable some functions. | ||
| 246 | |||
| 247 | |||
| 248 | However, (ie. ``system()``) they might have legitimate use cases in processes such as self upgrade etc., making it impossible to effectively | ||
| 249 | disable them - at the risk of breaking critical features. | ||
| 250 | |||
| 251 | SnuffleuPagus allows the user to restrict usage of specific functions per files, or per | ||
| 252 | files with a matching (sha256) hash, thus allowing the use of such functions **only** in the intended places. | ||
| 253 | |||
| 254 | Furthermore, running the `following script <FIXME>`_ will generate an hash and line-based whitelist | ||
| 255 | of dangerous functions, droping them everywhere else: | ||
| 256 | |||
| 257 | |||
| 258 | .. literalinclude:: ../../scripts/generate_rules.php | ||
| 259 | :language: php | ||
| 260 | |||
| 261 | |||
| 262 | The intent is to make post-exploitation process (such as backdooring of legitimate code, or RAT usage) a lot harder for the attacker. | ||
| 263 | |||
| 264 | |||
| 265 | Global strict mode | ||
| 266 | ^^^^^^^^^^^^^^^^^^ | ||
| 267 | |||
| 268 | By default, PHP will coerce values of the wrong type into the expected one | ||
| 269 | if possible. For example, if a function expecting an integer is given a string, | ||
| 270 | it will be coerced in an integer. | ||
| 271 | |||
| 272 | PHP7 introduced a **strict mode**, in which variables won't be coerced anymore, | ||
| 273 | and a `TypeError <https://php.net/manual/en/class.typeerror.php>`_ exception will | ||
| 274 | be raised if the types aren't matching. | ||
| 275 | `Scalar type declarations <https://secure.php.net/manual/en/migration70.new-features.php#migration70.new-features.scalar-type-declarations>`_ | ||
| 276 | are optional, but you don't have to used them in your code to benefit from them, | ||
| 277 | since every internal function from php has them. | ||
| 278 | |||
| 279 | This option provide a switch to globally activate this strict mode, | ||
| 280 | helping to uncover vulnerabilities like the classical | ||
| 281 | `strcmp bypass <https://danuxx.blogspot.fr/2013/03/unauthorized-access-bypassing-php-strcmp.html>`_, | ||
| 282 | and various other types mismatch. | ||
| 283 | |||
| 284 | This feature is largely inspired from the | ||
| 285 | `autostrict <https://github.com/krakjoe/autostrict>`_ module from `krakjoe <krakjoe.ninja>`_. | ||
| 286 | |||
| 287 | |||
| 288 | Preventing execution of writable PHP files | ||
| 289 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 290 | |||
| 291 | If an attacker manages to upload an arbitrary file or to modify an existing one, | ||
| 292 | odds are that (thanks to the default `umask <https://en.wikipedia.org/wiki/Umask>`_) | ||
| 293 | this file is writable by the PHP process. | ||
| 294 | |||
| 295 | Snuffleupagus can prevent the execution of this kind of files. A good practise | ||
| 296 | would be to use a different user to run PHP than for administrating the website, | ||
| 297 | and using this feature to lock this up. | ||
| 298 | |||
| 299 | |||
| 300 | |||
| 301 | Dumping capabilities | ||
| 302 | ^^^^^^^^^^^^^^^^^^^^ | ||
| 303 | It's possible to apply the ``dump(:str)`` filter to any virtual-patching rule, | ||
| 304 | to dump the complete web request, along with the filename and the corresponding | ||
| 305 | line number. By using the *right* set of restrictive rules (or by using the | ||
| 306 | *overly* restrictives ones in ``simulation`` mode), you might be able | ||
| 307 | to gather interesting vulnerabilities used against your website. | ||
| 308 | |||
| 309 | |||
| 310 | Misc low-hanging fruits in the default configuration file | ||
| 311 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 312 | |||
| 313 | Snuffleupagus is shipping with a default configuration file, containing | ||
| 314 | various examples and ideas of things that you might want to enable (or not). | ||
| 315 | |||
| 316 | Available functions recon | ||
| 317 | """"""""""""""""""""""""" | ||
| 318 | |||
| 319 | After compromising a website, most of the time, the attacker does some recon | ||
| 320 | within its webshell, to check which functions are available to execute arbitrary code, | ||
| 321 | since it's not uncommon for some web-hoster to disable things like ``system`` or ``passthru``, | ||
| 322 | or to check if mitigations are enabled, like ``open_basedir``. | ||
| 323 | This behaviour can be detected by preventing the execution of functions like ``ini_get`` | ||
| 324 | or ``is_callable`` with *suspicious* parameters. | ||
| 325 | |||
| 326 | ``chmod`` hardening | ||
| 327 | """"""""""""""""""" | ||
| 328 | |||
| 329 | Some PHP applications are using broad rights when using the ``chmod`` function, | ||
| 330 | like the infamous ``chmod(777)`` command, effectively making the file writable by everyone. | ||
| 331 | Snuffleupagus is preventing this kind of behaviour by restricting the parameters | ||
| 332 | than can be passer to ``chmod``. | ||
| 333 | |||
| 334 | Arbitrary file inclusion hardening | ||
| 335 | """""""""""""""""""""""""""""""""" | ||
| 336 | |||
| 337 | Arbitrary file inclusion is a common vulnerability, that might be detected | ||
| 338 | by preventing the use of anything else than a whitelist of extensions in calls | ||
| 339 | to ``include`` or ``require``. | ||
| 340 | |||
| 341 | *Cheap* SQL injections detection | ||
| 342 | """""""""""""""""""""""""""""""" | ||
| 343 | |||
| 344 | In some SQL injections, attackers might need to use comments, a feature that is | ||
| 345 | often not used in production system, so it might be a good idea to filter | ||
| 346 | queries that contains some. The same filtering idea can be used against | ||
| 347 | SQL functions that are frequently used in SQL injections, like ``sleep``, ``benchmark`` | ||
| 348 | or strings like ``version_info``. | ||
| 349 | |||
| 350 | Still about SQL injections, if a function performing a query returns ``FALSE`` | ||
| 351 | (indicating an error), it might be useful to dump the request for further analysis. | ||
| 352 | |||
diff --git a/doc/source/index.rst b/doc/source/index.rst new file mode 100644 index 0000000..8a9c340 --- /dev/null +++ b/doc/source/index.rst | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | Snuffleupagus | ||
| 2 | ============= | ||
| 3 | |||
| 4 | Snuffleupagus is a `PHP 7+ <https://secure.php.net/>`_ module designed to drastically raising the cost of | ||
| 5 | attacks against website, by killing entire bug classes, and also providing a | ||
| 6 | powerful virtual-patching system, allowing administrator to fix specific | ||
| 7 | vulnerabilities and audit suspicious behaviours without having to touch the PHP code. | ||
| 8 | |||
| 9 | Documentation | ||
| 10 | ------------- | ||
| 11 | |||
| 12 | .. toctree:: | ||
| 13 | :maxdepth: 2 | ||
| 14 | |||
| 15 | features | ||
| 16 | installation | ||
| 17 | config | ||
| 18 | download | ||
| 19 | faq | ||
| 20 | papers | ||
| 21 | |||
| 22 | Greetings | ||
| 23 | --------- | ||
| 24 | We would like to thank the following people: | ||
| 25 | |||
| 26 | - `Suhosin <http://suhosin.org>`_, for paving the way. | ||
| 27 | - The people behind the `RIPS <https://www.ripstech.com/>`_ scanner for their ground breaking work | ||
| 28 | - `NBS System <https://nbs-system.com>`_, for creating and open-sourcing this piece of software | ||
| 29 | - `Websec.fr <https://websec.fr>`_, for keeping our interesting vulnerabilities alive | ||
| 30 | - Web developers around the world, for being so imaginative | ||
diff --git a/doc/source/installation.rst b/doc/source/installation.rst new file mode 100644 index 0000000..779008d --- /dev/null +++ b/doc/source/installation.rst | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | Installation | ||
| 2 | ============ | ||
| 3 | |||
| 4 | Snuffleupagus is tested against various PHP 7+ versions: XXX | ||
| 5 | |||
| 6 | Manual installation | ||
| 7 | ------------------- | ||
| 8 | |||
| 9 | Depending on the system, we might already offer binary packages. | ||
| 10 | You can check our :doc:`download`. In that case you only need to activate | ||
| 11 | the extension inside your ``php.ini`` and to configure it. | ||
| 12 | |||
| 13 | |||
| 14 | Quickstart | ||
| 15 | ^^^^^^^^^^ | ||
| 16 | |||
| 17 | :: | ||
| 18 | |||
| 19 | git clone https://github.com/nbs-system/snuffleupagus | ||
| 20 | cd snuffleupagus | ||
| 21 | phpize | ||
| 22 | ./configure | ||
| 23 | make | ||
| 24 | make install | ||
| 25 | |||
| 26 | This should install ``snuffleupagus.so`` file in your extension directory. The final step is adding a load directive to ``php.ini``:: | ||
| 27 | |||
| 28 | extension=snuffleupagus.so | ||
| 29 | |||
| 30 | Upgrading | ||
| 31 | --------- | ||
| 32 | |||
| 33 | Upgrading the Snuffleupagus is as simple as recompiling it (or using a binary), replacing the file and restarting your webserver. | ||
diff --git a/doc/source/papers.rst b/doc/source/papers.rst new file mode 100644 index 0000000..d028b14 --- /dev/null +++ b/doc/source/papers.rst | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | Propaganda | ||
| 2 | ========== | ||
| 3 | |||
| 4 | This pages lists various mentions, articles and presentations about Snuffleupagus. | ||
| 5 | |||
| 6 | Talks | ||
| 7 | ----- | ||
| 8 | |||
| 9 | - `BerlinSide0x08 <https://berlinsides.org/?page_id=2168>`_ - `Php7 Nightmares <slides.pdf>`_ - 2017-05-28 | ||
| 10 | - `Hack.lu <https://2017.hack.lu/talks/>`_ - soonâ„¢ - 2017-10-18 | ||
| 11 | - `BlackAlps <https://blackalps.ch/2017program.php>`_ - soonâ„¢ - 2017-11-16 | ||
| 12 | |||
| 13 | Articles | ||
| 14 | -------- | ||
| 15 | |||
| 16 | - `Killing php bug classes at berlinsides <https://dustri.org/b/killing-php-bug-classes-at-berlinsides.html>`_ - 2017-06-05 \ No newline at end of file | ||
diff --git a/scripts/generate_rules.php b/scripts/generate_rules.php new file mode 100644 index 0000000..e286ef1 --- /dev/null +++ b/scripts/generate_rules.php | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | <?php | ||
| 2 | |||
| 3 | if ($argc != 2) { | ||
| 4 | echo 'Please provide a folder as argument.'; | ||
| 5 | die(); | ||
| 6 | } | ||
| 7 | |||
| 8 | $functions_blacklist = ['shell_exec', 'exec', 'passthru', 'php_uname', 'popen', | ||
| 9 | 'posix_kill', 'posix_mkfifo', 'posix_setpgid', 'posix_setsid', 'posix_setuid', | ||
| 10 | 'posix_setgid', 'posix_uname', 'proc_close', 'proc_nice', 'proc_open', | ||
| 11 | 'proc_terminate', 'proc_open', 'proc_get_status', 'dl', 'pnctl_exec', | ||
| 12 | 'pnctl_fork', 'assert', 'system']; | ||
| 13 | |||
| 14 | $extensions = ['php', 'php7', 'php5']; | ||
| 15 | |||
| 16 | $path = realpath($argv[1]); | ||
| 17 | |||
| 18 | $objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path)); | ||
| 19 | foreach($objects as $name => $object){ | ||
| 20 | if (FALSE === in_array (pathinfo($name, PATHINFO_EXTENSION), $extensions, true)) { | ||
| 21 | continue; | ||
| 22 | } | ||
| 23 | |||
| 24 | $hash = ''; | ||
| 25 | $file_content = file_get_contents($name); | ||
| 26 | |||
| 27 | foreach(token_get_all($file_content) as $token) { | ||
| 28 | if ($token[0] != 319) { | ||
| 29 | continue; | ||
| 30 | } | ||
| 31 | |||
| 32 | if (in_array($token[1], $functions_blacklist, true)) { | ||
| 33 | if ('' === $hash) { | ||
| 34 | $hash = hash('sha256', $file_content); | ||
| 35 | } | ||
| 36 | echo 'sp.disable_function.function("' . $token[1] . '").filename("' . $name . '").hash("' . $hash . '").allow();' . "\n"; | ||
| 37 | } | ||
| 38 | } | ||
| 39 | } | ||
| 40 | foreach($functions_blacklist as $fun) { | ||
| 41 | echo 'sp.disable_function.function("' . $fun . '").drop();' . "\n"; | ||
| 42 | |||
| 43 | } | ||
diff --git a/src/bench/bench.php b/src/bench/bench.php new file mode 100644 index 0000000..5f77180 --- /dev/null +++ b/src/bench/bench.php | |||
| @@ -0,0 +1,422 @@ | |||
| 1 | <?php | ||
| 2 | if (function_exists("date_default_timezone_set")) { | ||
| 3 | date_default_timezone_set("UTC"); | ||
| 4 | } | ||
| 5 | |||
| 6 | function simple() { | ||
| 7 | $a = 0; | ||
| 8 | for ($i = 0; $i < 1000000; $i++) | ||
| 9 | $a++; | ||
| 10 | |||
| 11 | $thisisanotherlongname = 0; | ||
| 12 | for ($thisisalongname = 0; $thisisalongname < 1000000; $thisisalongname++) | ||
| 13 | $thisisanotherlongname++; | ||
| 14 | } | ||
| 15 | |||
| 16 | /****/ | ||
| 17 | |||
| 18 | function simplecall() { | ||
| 19 | for ($i = 0; $i < 1000000; $i++) | ||
| 20 | strlen("hallo"); | ||
| 21 | } | ||
| 22 | |||
| 23 | /****/ | ||
| 24 | |||
| 25 | function hallo($a) { | ||
| 26 | } | ||
| 27 | |||
| 28 | function simpleucall() { | ||
| 29 | for ($i = 0; $i < 1000000; $i++) | ||
| 30 | hallo("hallo"); | ||
| 31 | } | ||
| 32 | |||
| 33 | /****/ | ||
| 34 | |||
| 35 | function simpleudcall() { | ||
| 36 | for ($i = 0; $i < 1000000; $i++) | ||
| 37 | hallo2("hallo"); | ||
| 38 | } | ||
| 39 | |||
| 40 | function hallo2($a) { | ||
| 41 | } | ||
| 42 | |||
| 43 | /****/ | ||
| 44 | |||
| 45 | function mandel() { | ||
| 46 | $w1=50; | ||
| 47 | $h1=150; | ||
| 48 | $recen=-.45; | ||
| 49 | $imcen=0.0; | ||
| 50 | $r=0.7; | ||
| 51 | $s=0; $rec=0; $imc=0; $re=0; $im=0; $re2=0; $im2=0; | ||
| 52 | $x=0; $y=0; $w2=0; $h2=0; $color=0; | ||
| 53 | $s=2*$r/$w1; | ||
| 54 | $w2=40; | ||
| 55 | $h2=12; | ||
| 56 | for ($y=0 ; $y<=$w1; $y=$y+1) { | ||
| 57 | $imc=$s*($y-$h2)+$imcen; | ||
| 58 | for ($x=0 ; $x<=$h1; $x=$x+1) { | ||
| 59 | $rec=$s*($x-$w2)+$recen; | ||
| 60 | $re=$rec; | ||
| 61 | $im=$imc; | ||
| 62 | $color=1000; | ||
| 63 | $re2=$re*$re; | ||
| 64 | $im2=$im*$im; | ||
| 65 | while( ((($re2+$im2)<1000000) && $color>0)) { | ||
| 66 | $im=$re*$im*2+$imc; | ||
| 67 | $re=$re2-$im2+$rec; | ||
| 68 | $re2=$re*$re; | ||
| 69 | $im2=$im*$im; | ||
| 70 | $color=$color-1; | ||
| 71 | } | ||
| 72 | if ( $color==0 ) { | ||
| 73 | print "_"; | ||
| 74 | } else { | ||
| 75 | print "#"; | ||
| 76 | } | ||
| 77 | } | ||
| 78 | print "<br>"; | ||
| 79 | flush(); | ||
| 80 | } | ||
| 81 | } | ||
| 82 | |||
| 83 | /****/ | ||
| 84 | |||
| 85 | function mandel2() { | ||
| 86 | $b = " .:,;!/>)|&IH%*#"; | ||
| 87 | //float r, i, z, Z, t, c, C; | ||
| 88 | for ($y=30; printf("\n"), $C = $y*0.1 - 1.5, $y--;){ | ||
| 89 | for ($x=0; $c = $x*0.04 - 2, $z=0, $Z=0, $x++ < 75;){ | ||
| 90 | for ($r=$c, $i=$C, $k=0; $t = $z*$z - $Z*$Z + $r, $Z = 2*$z*$Z + $i, $z=$t, $k<5000; $k++) | ||
| 91 | if ($z*$z + $Z*$Z > 500000) break; | ||
| 92 | echo $b[$k%16]; | ||
| 93 | } | ||
| 94 | } | ||
| 95 | } | ||
| 96 | |||
| 97 | /****/ | ||
| 98 | |||
| 99 | function Ack($m, $n){ | ||
| 100 | if($m == 0) return $n+1; | ||
| 101 | if($n == 0) return Ack($m-1, 1); | ||
| 102 | return Ack($m - 1, Ack($m, ($n - 1))); | ||
| 103 | } | ||
| 104 | |||
| 105 | function ackermann($n) { | ||
| 106 | $r = Ack(3,$n); | ||
| 107 | print "Ack(3,$n): $r\n"; | ||
| 108 | } | ||
| 109 | |||
| 110 | /****/ | ||
| 111 | |||
| 112 | function ary($n) { | ||
| 113 | for ($i=0; $i<$n; $i++) { | ||
| 114 | $X[$i] = $i; | ||
| 115 | } | ||
| 116 | for ($i=$n-1; $i>=0; $i--) { | ||
| 117 | $Y[$i] = $X[$i]; | ||
| 118 | } | ||
| 119 | $last = $n-1; | ||
| 120 | print "$Y[$last]\n"; | ||
| 121 | } | ||
| 122 | |||
| 123 | /****/ | ||
| 124 | |||
| 125 | function ary2($n) { | ||
| 126 | for ($i=0; $i<$n;) { | ||
| 127 | $X[$i] = $i; ++$i; | ||
| 128 | $X[$i] = $i; ++$i; | ||
| 129 | $X[$i] = $i; ++$i; | ||
| 130 | $X[$i] = $i; ++$i; | ||
| 131 | $X[$i] = $i; ++$i; | ||
| 132 | |||
| 133 | $X[$i] = $i; ++$i; | ||
| 134 | $X[$i] = $i; ++$i; | ||
| 135 | $X[$i] = $i; ++$i; | ||
| 136 | $X[$i] = $i; ++$i; | ||
| 137 | $X[$i] = $i; ++$i; | ||
| 138 | } | ||
| 139 | for ($i=$n-1; $i>=0;) { | ||
| 140 | $Y[$i] = $X[$i]; --$i; | ||
| 141 | $Y[$i] = $X[$i]; --$i; | ||
| 142 | $Y[$i] = $X[$i]; --$i; | ||
| 143 | $Y[$i] = $X[$i]; --$i; | ||
| 144 | $Y[$i] = $X[$i]; --$i; | ||
| 145 | |||
| 146 | $Y[$i] = $X[$i]; --$i; | ||
| 147 | $Y[$i] = $X[$i]; --$i; | ||
| 148 | $Y[$i] = $X[$i]; --$i; | ||
| 149 | $Y[$i] = $X[$i]; --$i; | ||
| 150 | $Y[$i] = $X[$i]; --$i; | ||
| 151 | } | ||
| 152 | $last = $n-1; | ||
| 153 | print "$Y[$last]\n"; | ||
| 154 | } | ||
| 155 | |||
| 156 | /****/ | ||
| 157 | |||
| 158 | function ary3($n) { | ||
| 159 | for ($i=0; $i<$n; $i++) { | ||
| 160 | $X[$i] = $i + 1; | ||
| 161 | $Y[$i] = 0; | ||
| 162 | } | ||
| 163 | for ($k=0; $k<1000; $k++) { | ||
| 164 | for ($i=$n-1; $i>=0; $i--) { | ||
| 165 | $Y[$i] += $X[$i]; | ||
| 166 | } | ||
| 167 | } | ||
| 168 | $last = $n-1; | ||
| 169 | print "$Y[0] $Y[$last]\n"; | ||
| 170 | } | ||
| 171 | |||
| 172 | /****/ | ||
| 173 | |||
| 174 | function fibo_r($n){ | ||
| 175 | return(($n < 2) ? 1 : fibo_r($n - 2) + fibo_r($n - 1)); | ||
| 176 | } | ||
| 177 | |||
| 178 | function fibo($n) { | ||
| 179 | $r = fibo_r($n); | ||
| 180 | print "$r\n"; | ||
| 181 | } | ||
| 182 | |||
| 183 | /****/ | ||
| 184 | |||
| 185 | function hash1($n) { | ||
| 186 | for ($i = 1; $i <= $n; $i++) { | ||
| 187 | $X[dechex($i)] = $i; | ||
| 188 | } | ||
| 189 | $c = 0; | ||
| 190 | for ($i = $n; $i > 0; $i--) { | ||
| 191 | if ($X[dechex($i)]) { $c++; } | ||
| 192 | } | ||
| 193 | print "$c\n"; | ||
| 194 | } | ||
| 195 | |||
| 196 | /****/ | ||
| 197 | |||
| 198 | function hash2($n) { | ||
| 199 | for ($i = 0; $i < $n; $i++) { | ||
| 200 | $hash1["foo_$i"] = $i; | ||
| 201 | $hash2["foo_$i"] = 0; | ||
| 202 | } | ||
| 203 | for ($i = $n; $i > 0; $i--) { | ||
| 204 | foreach($hash1 as $key => $value) $hash2[$key] += $value; | ||
| 205 | } | ||
| 206 | $first = "foo_0"; | ||
| 207 | $last = "foo_".($n-1); | ||
| 208 | print "$hash1[$first] $hash1[$last] $hash2[$first] $hash2[$last]\n"; | ||
| 209 | } | ||
| 210 | |||
| 211 | /****/ | ||
| 212 | |||
| 213 | function gen_random ($n) { | ||
| 214 | global $LAST; | ||
| 215 | return( ($n * ($LAST = ($LAST * IA + IC) % IM)) / IM ); | ||
| 216 | } | ||
| 217 | |||
| 218 | function heapsort_r($n, &$ra) { | ||
| 219 | $l = ($n >> 1) + 1; | ||
| 220 | $ir = $n; | ||
| 221 | |||
| 222 | while (1) { | ||
| 223 | if ($l > 1) { | ||
| 224 | $rra = $ra[--$l]; | ||
| 225 | } else { | ||
| 226 | $rra = $ra[$ir]; | ||
| 227 | $ra[$ir] = $ra[1]; | ||
| 228 | if (--$ir == 1) { | ||
| 229 | $ra[1] = $rra; | ||
| 230 | return; | ||
| 231 | } | ||
| 232 | } | ||
| 233 | $i = $l; | ||
| 234 | $j = $l << 1; | ||
| 235 | while ($j <= $ir) { | ||
| 236 | if (($j < $ir) && ($ra[$j] < $ra[$j+1])) { | ||
| 237 | $j++; | ||
| 238 | } | ||
| 239 | if ($rra < $ra[$j]) { | ||
| 240 | $ra[$i] = $ra[$j]; | ||
| 241 | $j += ($i = $j); | ||
| 242 | } else { | ||
| 243 | $j = $ir + 1; | ||
| 244 | } | ||
| 245 | } | ||
| 246 | $ra[$i] = $rra; | ||
| 247 | } | ||
| 248 | } | ||
| 249 | |||
| 250 | function heapsort($N) { | ||
| 251 | global $LAST; | ||
| 252 | |||
| 253 | define("IM", 139968); | ||
| 254 | define("IA", 3877); | ||
| 255 | define("IC", 29573); | ||
| 256 | |||
| 257 | $LAST = 42; | ||
| 258 | for ($i=1; $i<=$N; $i++) { | ||
| 259 | $ary[$i] = gen_random(1); | ||
| 260 | } | ||
| 261 | heapsort_r($N, $ary); | ||
| 262 | printf("%.10f\n", $ary[$N]); | ||
| 263 | } | ||
| 264 | |||
| 265 | /****/ | ||
| 266 | |||
| 267 | function mkmatrix ($rows, $cols) { | ||
| 268 | $count = 1; | ||
| 269 | $mx = array(); | ||
| 270 | for ($i=0; $i<$rows; $i++) { | ||
| 271 | for ($j=0; $j<$cols; $j++) { | ||
| 272 | $mx[$i][$j] = $count++; | ||
| 273 | } | ||
| 274 | } | ||
| 275 | return($mx); | ||
| 276 | } | ||
| 277 | |||
| 278 | function mmult ($rows, $cols, $m1, $m2) { | ||
| 279 | $m3 = array(); | ||
| 280 | for ($i=0; $i<$rows; $i++) { | ||
| 281 | for ($j=0; $j<$cols; $j++) { | ||
| 282 | $x = 0; | ||
| 283 | for ($k=0; $k<$cols; $k++) { | ||
| 284 | $x += $m1[$i][$k] * $m2[$k][$j]; | ||
| 285 | } | ||
| 286 | $m3[$i][$j] = $x; | ||
| 287 | } | ||
| 288 | } | ||
| 289 | return($m3); | ||
| 290 | } | ||
| 291 | |||
| 292 | function matrix($n) { | ||
| 293 | $SIZE = 30; | ||
| 294 | $m1 = mkmatrix($SIZE, $SIZE); | ||
| 295 | $m2 = mkmatrix($SIZE, $SIZE); | ||
| 296 | while ($n--) { | ||
| 297 | $mm = mmult($SIZE, $SIZE, $m1, $m2); | ||
| 298 | } | ||
| 299 | print "{$mm[0][0]} {$mm[2][3]} {$mm[3][2]} {$mm[4][4]}\n"; | ||
| 300 | } | ||
| 301 | |||
| 302 | /****/ | ||
| 303 | |||
| 304 | function nestedloop($n) { | ||
| 305 | $x = 0; | ||
| 306 | for ($a=0; $a<$n; $a++) | ||
| 307 | for ($b=0; $b<$n; $b++) | ||
| 308 | for ($c=0; $c<$n; $c++) | ||
| 309 | for ($d=0; $d<$n; $d++) | ||
| 310 | for ($e=0; $e<$n; $e++) | ||
| 311 | for ($f=0; $f<$n; $f++) | ||
| 312 | $x++; | ||
| 313 | print "$x\n"; | ||
| 314 | } | ||
| 315 | |||
| 316 | /****/ | ||
| 317 | |||
| 318 | function sieve($n) { | ||
| 319 | $count = 0; | ||
| 320 | while ($n-- > 0) { | ||
| 321 | $count = 0; | ||
| 322 | $flags = range (0,8192); | ||
| 323 | for ($i=2; $i<8193; $i++) { | ||
| 324 | if ($flags[$i] > 0) { | ||
| 325 | for ($k=$i+$i; $k <= 8192; $k+=$i) { | ||
| 326 | $flags[$k] = 0; | ||
| 327 | } | ||
| 328 | $count++; | ||
| 329 | } | ||
| 330 | } | ||
| 331 | } | ||
| 332 | print "Count: $count\n"; | ||
| 333 | } | ||
| 334 | |||
| 335 | /****/ | ||
| 336 | |||
| 337 | function strcat($n) { | ||
| 338 | $str = ""; | ||
| 339 | while ($n-- > 0) { | ||
| 340 | $str .= "hello\n"; | ||
| 341 | } | ||
| 342 | $len = strlen($str); | ||
| 343 | print "$len\n"; | ||
| 344 | } | ||
| 345 | |||
| 346 | /*****/ | ||
| 347 | |||
| 348 | function getmicrotime() | ||
| 349 | { | ||
| 350 | $t = gettimeofday(); | ||
| 351 | return ($t['sec'] + $t['usec'] / 1000000); | ||
| 352 | } | ||
| 353 | |||
| 354 | function start_test() | ||
| 355 | { | ||
| 356 | ob_start(); | ||
| 357 | return getmicrotime(); | ||
| 358 | } | ||
| 359 | |||
| 360 | function end_test($start, $name) | ||
| 361 | { | ||
| 362 | global $total; | ||
| 363 | $end = getmicrotime(); | ||
| 364 | ob_end_clean(); | ||
| 365 | $total += $end-$start; | ||
| 366 | $num = number_format($end-$start,3); | ||
| 367 | $pad = str_repeat(" ", 24-strlen($name)-strlen($num)); | ||
| 368 | |||
| 369 | echo $name.$pad.$num."\n"; | ||
| 370 | ob_start(); | ||
| 371 | return getmicrotime(); | ||
| 372 | } | ||
| 373 | |||
| 374 | function total() | ||
| 375 | { | ||
| 376 | global $total; | ||
| 377 | $pad = str_repeat("-", 24); | ||
| 378 | echo $pad."\n"; | ||
| 379 | $num = number_format($total,3); | ||
| 380 | $pad = str_repeat(" ", 24-strlen("Total")-strlen($num)); | ||
| 381 | echo "Total".$pad.$num."\n"; | ||
| 382 | } | ||
| 383 | |||
| 384 | $t0 = $t = start_test(); | ||
| 385 | simple(); | ||
| 386 | $t = end_test($t, "simple"); | ||
| 387 | simplecall(); | ||
| 388 | $t = end_test($t, "simplecall"); | ||
| 389 | simpleucall(); | ||
| 390 | $t = end_test($t, "simpleucall"); | ||
| 391 | simpleudcall(); | ||
| 392 | $t = end_test($t, "simpleudcall"); | ||
| 393 | mandel(); | ||
| 394 | $t = end_test($t, "mandel"); | ||
| 395 | mandel2(); | ||
| 396 | $t = end_test($t, "mandel2"); | ||
| 397 | ackermann(7); | ||
| 398 | $t = end_test($t, "ackermann(7)"); | ||
| 399 | ary(50000); | ||
| 400 | $t = end_test($t, "ary(50000)"); | ||
| 401 | ary2(50000); | ||
| 402 | $t = end_test($t, "ary2(50000)"); | ||
| 403 | ary3(2000); | ||
| 404 | $t = end_test($t, "ary3(2000)"); | ||
| 405 | fibo(30); | ||
| 406 | $t = end_test($t, "fibo(30)"); | ||
| 407 | hash1(50000); | ||
| 408 | $t = end_test($t, "hash1(50000)"); | ||
| 409 | hash2(500); | ||
| 410 | $t = end_test($t, "hash2(500)"); | ||
| 411 | heapsort(20000); | ||
| 412 | $t = end_test($t, "heapsort(20000)"); | ||
| 413 | matrix(20); | ||
| 414 | $t = end_test($t, "matrix(20)"); | ||
| 415 | nestedloop(12); | ||
| 416 | $t = end_test($t, "nestedloop(12)"); | ||
| 417 | sieve(30); | ||
| 418 | $t = end_test($t, "sieve(30)"); | ||
| 419 | strcat(200000); | ||
| 420 | $t = end_test($t, "strcat(200000)"); | ||
| 421 | total($t0, "Total"); | ||
| 422 | ?> | ||
diff --git a/src/bench/micro_bench.php b/src/bench/micro_bench.php new file mode 100644 index 0000000..7052588 --- /dev/null +++ b/src/bench/micro_bench.php | |||
| @@ -0,0 +1,358 @@ | |||
| 1 | <?php | ||
| 2 | |||
| 3 | function hallo() { | ||
| 4 | } | ||
| 5 | |||
| 6 | function simpleucall($n) { | ||
| 7 | for ($i = 0; $i < $n; $i++) | ||
| 8 | hallo(); | ||
| 9 | } | ||
| 10 | |||
| 11 | function simpleudcall($n) { | ||
| 12 | for ($i = 0; $i < $n; $i++) | ||
| 13 | hallo2(); | ||
| 14 | } | ||
| 15 | |||
| 16 | function hallo2() { | ||
| 17 | } | ||
| 18 | |||
| 19 | function simpleicall($n) { | ||
| 20 | for ($i = 0; $i < $n; $i++) | ||
| 21 | func_num_args(); | ||
| 22 | } | ||
| 23 | |||
| 24 | class Foo { | ||
| 25 | static $a = 0; | ||
| 26 | public $b = 0; | ||
| 27 | const TEST = 0; | ||
| 28 | |||
| 29 | static function read_static($n) { | ||
| 30 | for ($i = 0; $i < $n; ++$i) { | ||
| 31 | $x = self::$a; | ||
| 32 | } | ||
| 33 | } | ||
| 34 | |||
| 35 | static function write_static($n) { | ||
| 36 | for ($i = 0; $i < $n; ++$i) { | ||
| 37 | self::$a = 0; | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | static function isset_static($n) { | ||
| 42 | for ($i = 0; $i < $n; ++$i) { | ||
| 43 | $x = isset(self::$a); | ||
| 44 | } | ||
| 45 | } | ||
| 46 | |||
| 47 | static function empty_static($n) { | ||
| 48 | for ($i = 0; $i < $n; ++$i) { | ||
| 49 | $x = empty(self::$a); | ||
| 50 | } | ||
| 51 | } | ||
| 52 | |||
| 53 | static function f() { | ||
| 54 | } | ||
| 55 | |||
| 56 | static function call_static($n) { | ||
| 57 | for ($i = 0; $i < $n; ++$i) { | ||
| 58 | self::f(); | ||
| 59 | } | ||
| 60 | } | ||
| 61 | |||
| 62 | function read_prop($n) { | ||
| 63 | for ($i = 0; $i < $n; ++$i) { | ||
| 64 | $x = $this->b; | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | function write_prop($n) { | ||
| 69 | for ($i = 0; $i < $n; ++$i) { | ||
| 70 | $this->b = 0; | ||
| 71 | } | ||
| 72 | } | ||
| 73 | |||
| 74 | function assign_add_prop($n) { | ||
| 75 | for ($i = 0; $i < $n; ++$i) { | ||
| 76 | $this->b += 2; | ||
| 77 | } | ||
| 78 | } | ||
| 79 | |||
| 80 | function pre_inc_prop($n) { | ||
| 81 | for ($i = 0; $i < $n; ++$i) { | ||
| 82 | ++$this->b; | ||
| 83 | } | ||
| 84 | } | ||
| 85 | |||
| 86 | function pre_dec_prop($n) { | ||
| 87 | for ($i = 0; $i < $n; ++$i) { | ||
| 88 | --$this->b; | ||
| 89 | } | ||
| 90 | } | ||
| 91 | |||
| 92 | function post_inc_prop($n) { | ||
| 93 | for ($i = 0; $i < $n; ++$i) { | ||
| 94 | $this->b++; | ||
| 95 | } | ||
| 96 | } | ||
| 97 | |||
| 98 | function post_dec_prop($n) { | ||
| 99 | for ($i = 0; $i < $n; ++$i) { | ||
| 100 | $this->b--; | ||
| 101 | } | ||
| 102 | } | ||
| 103 | |||
| 104 | function isset_prop($n) { | ||
| 105 | for ($i = 0; $i < $n; ++$i) { | ||
| 106 | $x = isset($this->b); | ||
| 107 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | function empty_prop($n) { | ||
| 111 | for ($i = 0; $i < $n; ++$i) { | ||
| 112 | $x = empty($this->b); | ||
| 113 | } | ||
| 114 | } | ||
| 115 | |||
| 116 | function g() { | ||
| 117 | } | ||
| 118 | |||
| 119 | function call($n) { | ||
| 120 | for ($i = 0; $i < $n; ++$i) { | ||
| 121 | $this->g(); | ||
| 122 | } | ||
| 123 | } | ||
| 124 | |||
| 125 | function read_const($n) { | ||
| 126 | for ($i = 0; $i < $n; ++$i) { | ||
| 127 | $x = $this::TEST; | ||
| 128 | } | ||
| 129 | } | ||
| 130 | |||
| 131 | } | ||
| 132 | |||
| 133 | function read_static($n) { | ||
| 134 | for ($i = 0; $i < $n; ++$i) { | ||
| 135 | $x = Foo::$a; | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 | function write_static($n) { | ||
| 140 | for ($i = 0; $i < $n; ++$i) { | ||
| 141 | Foo::$a = 0; | ||
| 142 | } | ||
| 143 | } | ||
| 144 | |||
| 145 | function isset_static($n) { | ||
| 146 | for ($i = 0; $i < $n; ++$i) { | ||
| 147 | $x = isset(Foo::$a); | ||
| 148 | } | ||
| 149 | } | ||
| 150 | |||
| 151 | function empty_static($n) { | ||
| 152 | for ($i = 0; $i < $n; ++$i) { | ||
| 153 | $x = empty(Foo::$a); | ||
| 154 | } | ||
| 155 | } | ||
| 156 | |||
| 157 | function call_static($n) { | ||
| 158 | for ($i = 0; $i < $n; ++$i) { | ||
| 159 | Foo::f(); | ||
| 160 | } | ||
| 161 | } | ||
| 162 | |||
| 163 | function create_object($n) { | ||
| 164 | for ($i = 0; $i < $n; ++$i) { | ||
| 165 | $x = new Foo(); | ||
| 166 | } | ||
| 167 | } | ||
| 168 | |||
| 169 | define('TEST', null); | ||
| 170 | |||
| 171 | function read_const($n) { | ||
| 172 | for ($i = 0; $i < $n; ++$i) { | ||
| 173 | $x = TEST; | ||
| 174 | } | ||
| 175 | } | ||
| 176 | |||
| 177 | function read_auto_global($n) { | ||
| 178 | for ($i = 0; $i < $n; ++$i) { | ||
| 179 | $x = $_GET; | ||
| 180 | } | ||
| 181 | } | ||
| 182 | |||
| 183 | $g_var = 0; | ||
| 184 | |||
| 185 | function read_global_var($n) { | ||
| 186 | for ($i = 0; $i < $n; ++$i) { | ||
| 187 | $x = $GLOBALS['g_var']; | ||
| 188 | } | ||
| 189 | } | ||
| 190 | |||
| 191 | function read_hash($n) { | ||
| 192 | $hash = array('test' => 0); | ||
| 193 | for ($i = 0; $i < $n; ++$i) { | ||
| 194 | $x = $hash['test']; | ||
| 195 | } | ||
| 196 | } | ||
| 197 | |||
| 198 | function read_str_offset($n) { | ||
| 199 | $str = "test"; | ||
| 200 | for ($i = 0; $i < $n; ++$i) { | ||
| 201 | $x = $str[1]; | ||
| 202 | } | ||
| 203 | } | ||
| 204 | |||
| 205 | function issetor($n) { | ||
| 206 | $val = array(0,1,2,3,4,5,6,7,8,9); | ||
| 207 | for ($i = 0; $i < $n; ++$i) { | ||
| 208 | $x = $val ?: null; | ||
| 209 | } | ||
| 210 | } | ||
| 211 | |||
| 212 | function issetor2($n) { | ||
| 213 | $f = false; $j = 0; | ||
| 214 | for ($i = 0; $i < $n; ++$i) { | ||
| 215 | $x = $f ?: $j + 1; | ||
| 216 | } | ||
| 217 | } | ||
| 218 | |||
| 219 | function ternary($n) { | ||
| 220 | $val = array(0,1,2,3,4,5,6,7,8,9); | ||
| 221 | $f = false; | ||
| 222 | for ($i = 0; $i < $n; ++$i) { | ||
| 223 | $x = $f ? null : $val; | ||
| 224 | } | ||
| 225 | } | ||
| 226 | |||
| 227 | function ternary2($n) { | ||
| 228 | $f = false; $j = 0; | ||
| 229 | for ($i = 0; $i < $n; ++$i) { | ||
| 230 | $x = $f ? $f : $j + 1; | ||
| 231 | } | ||
| 232 | } | ||
| 233 | |||
| 234 | /*****/ | ||
| 235 | |||
| 236 | function empty_loop($n) { | ||
| 237 | for ($i = 0; $i < $n; ++$i) { | ||
| 238 | } | ||
| 239 | } | ||
| 240 | |||
| 241 | function getmicrotime() | ||
| 242 | { | ||
| 243 | $t = gettimeofday(); | ||
| 244 | return ($t['sec'] + $t['usec'] / 1000000); | ||
| 245 | } | ||
| 246 | |||
| 247 | function start_test() | ||
| 248 | { | ||
| 249 | ob_start(); | ||
| 250 | return getmicrotime(); | ||
| 251 | } | ||
| 252 | |||
| 253 | function end_test($start, $name, $overhead = null) | ||
| 254 | { | ||
| 255 | global $total; | ||
| 256 | global $last_time; | ||
| 257 | $end = getmicrotime(); | ||
| 258 | ob_end_clean(); | ||
| 259 | $last_time = $end-$start; | ||
| 260 | $total += $last_time; | ||
| 261 | $num = number_format($last_time,3); | ||
| 262 | $pad = str_repeat(" ", 24-strlen($name)-strlen($num)); | ||
| 263 | if (is_null($overhead)) { | ||
| 264 | echo $name.$pad.$num."\n"; | ||
| 265 | } else { | ||
| 266 | $num2 = number_format($last_time - $overhead,3); | ||
| 267 | echo $name.$pad.$num." ".$num2."\n"; | ||
| 268 | } | ||
| 269 | ob_start(); | ||
| 270 | return getmicrotime(); | ||
| 271 | } | ||
| 272 | |||
| 273 | function total() | ||
| 274 | { | ||
| 275 | global $total; | ||
| 276 | $pad = str_repeat("-", 24); | ||
| 277 | echo $pad."\n"; | ||
| 278 | $num = number_format($total,3); | ||
| 279 | $pad = str_repeat(" ", 24-strlen("Total")-strlen($num)); | ||
| 280 | echo "Total".$pad.$num."\n"; | ||
| 281 | } | ||
| 282 | |||
| 283 | const N = 5000000; | ||
| 284 | |||
| 285 | $t0 = $t = start_test(); | ||
| 286 | empty_loop(N); | ||
| 287 | $t = end_test($t, 'empty_loop'); | ||
| 288 | $overhead = $last_time; | ||
| 289 | simpleucall(N); | ||
| 290 | $t = end_test($t, 'func()', $overhead); | ||
| 291 | simpleudcall(N); | ||
| 292 | $t = end_test($t, 'undef_func()', $overhead); | ||
| 293 | simpleicall(N); | ||
| 294 | $t = end_test($t, 'int_func()', $overhead); | ||
| 295 | Foo::read_static(N); | ||
| 296 | $t = end_test($t, '$x = self::$x', $overhead); | ||
| 297 | Foo::write_static(N); | ||
| 298 | $t = end_test($t, 'self::$x = 0', $overhead); | ||
| 299 | Foo::isset_static(N); | ||
| 300 | $t = end_test($t, 'isset(self::$x)', $overhead); | ||
| 301 | Foo::empty_static(N); | ||
| 302 | $t = end_test($t, 'empty(self::$x)', $overhead); | ||
| 303 | read_static(N); | ||
| 304 | $t = end_test($t, '$x = Foo::$x', $overhead); | ||
| 305 | write_static(N); | ||
| 306 | $t = end_test($t, 'Foo::$x = 0', $overhead); | ||
| 307 | isset_static(N); | ||
| 308 | $t = end_test($t, 'isset(Foo::$x)', $overhead); | ||
| 309 | empty_static(N); | ||
| 310 | $t = end_test($t, 'empty(Foo::$x)', $overhead); | ||
| 311 | Foo::call_static(N); | ||
| 312 | $t = end_test($t, 'self::f()', $overhead); | ||
| 313 | call_static(N); | ||
| 314 | $t = end_test($t, 'Foo::f()', $overhead); | ||
| 315 | $x = new Foo(); | ||
| 316 | $x->read_prop(N); | ||
| 317 | $t = end_test($t, '$x = $this->x', $overhead); | ||
| 318 | $x->write_prop(N); | ||
| 319 | $t = end_test($t, '$this->x = 0', $overhead); | ||
| 320 | $x->assign_add_prop(N); | ||
| 321 | $t = end_test($t, '$this->x += 2', $overhead); | ||
| 322 | $x->pre_inc_prop(N); | ||
| 323 | $t = end_test($t, '++$this->x', $overhead); | ||
| 324 | $x->pre_dec_prop(N); | ||
| 325 | $t = end_test($t, '--$this->x', $overhead); | ||
| 326 | $x->post_inc_prop(N); | ||
| 327 | $t = end_test($t, '$this->x++', $overhead); | ||
| 328 | $x->post_dec_prop(N); | ||
| 329 | $t = end_test($t, '$this->x--', $overhead); | ||
| 330 | $x->isset_prop(N); | ||
| 331 | $t = end_test($t, 'isset($this->x)', $overhead); | ||
| 332 | $x->empty_prop(N); | ||
| 333 | $t = end_test($t, 'empty($this->x)', $overhead); | ||
| 334 | $x->call(N); | ||
| 335 | $t = end_test($t, '$this->f()', $overhead); | ||
| 336 | $x->read_const(N); | ||
| 337 | $t = end_test($t, '$x = Foo::TEST', $overhead); | ||
| 338 | create_object(N); | ||
| 339 | $t = end_test($t, 'new Foo()', $overhead); | ||
| 340 | read_const(N); | ||
| 341 | $t = end_test($t, '$x = TEST', $overhead); | ||
| 342 | read_auto_global(N); | ||
| 343 | $t = end_test($t, '$x = $_GET', $overhead); | ||
| 344 | read_global_var(N); | ||
| 345 | $t = end_test($t, '$x = $GLOBALS[\'v\']', $overhead); | ||
| 346 | read_hash(N); | ||
| 347 | $t = end_test($t, '$x = $hash[\'v\']', $overhead); | ||
| 348 | read_str_offset(N); | ||
| 349 | $t = end_test($t, '$x = $str[0]', $overhead); | ||
| 350 | issetor(N); | ||
| 351 | $t = end_test($t, '$x = $a ?: null', $overhead); | ||
| 352 | issetor2(N); | ||
| 353 | $t = end_test($t, '$x = $f ?: tmp', $overhead); | ||
| 354 | ternary(N); | ||
| 355 | $t = end_test($t, '$x = $f ? $f : $a', $overhead); | ||
| 356 | ternary2(N); | ||
| 357 | $t = end_test($t, '$x = $f ? $f : tmp', $overhead); | ||
| 358 | total($t0, "Total"); | ||
diff --git a/src/config.m4 b/src/config.m4 new file mode 100644 index 0000000..aba355c --- /dev/null +++ b/src/config.m4 | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | dnl $Id$ | ||
| 2 | dnl config.m4 for extension snuffleupagus | ||
| 3 | |||
| 4 | sources="snuffleupagus.c sp_config.c sp_config_utils.c sp_harden_rand.c" | ||
| 5 | sources="$sources sp_unserialize.c sp_utils.c sp_disable_xxe.c sp_list.c" | ||
| 6 | sources="$sources sp_disabled_functions.c sp_execute.c sp_upload_validation.c" | ||
| 7 | sources="$sources sp_cookie_encryption.c sp_network_utils.c tweetnacl.c" | ||
| 8 | sources="$sources sp_config_keywords.c sp_compile.c" | ||
| 9 | |||
| 10 | PHP_ARG_ENABLE(snuffleupagus, whether to enable snuffleupagus support, | ||
| 11 | [ --enable-snuffleupagus Enable snuffleupagus support]) | ||
| 12 | |||
| 13 | PHP_ARG_ENABLE(coverage, whether to enable coverage support, | ||
| 14 | [ --enable-coverage Enable coverage support]) | ||
| 15 | |||
| 16 | PHP_ARG_ENABLE(debug, whether to enable debug messages, | ||
| 17 | [ --enable-debug Enable debug messages]) | ||
| 18 | |||
| 19 | CFLAGS="$CFLAGS -lpcre" | ||
| 20 | CFLAGS="$CFLAGS -D_DEFAULT_SOURCE=1 -std=c99" | ||
| 21 | CFLAGS="$CFLAGS -Wall -Wextra -Wno-unused-parameter" | ||
| 22 | |||
| 23 | if test "$PHP_DEBUG" = "yes"; then | ||
| 24 | AC_DEFINE(SP_DEBUG, 1, [Wether you want to enable debug messages]) | ||
| 25 | fi | ||
| 26 | |||
| 27 | if test "$PHP_SNUFFLEUPAGUS" != "no"; then | ||
| 28 | if test "$PHP_COVERAGE" != "no"; then | ||
| 29 | CFLAGS="$CFLAGS --coverage -fprofile-arcs -ftest-coverage" | ||
| 30 | LDFLAGS="$LDFLAGS --coverage" | ||
| 31 | PHP_NEW_EXTENSION(snuffleupagus, $sources, $ext_shared,-DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -g -fprofile-arcs -ftest-coverage -lgcov) | ||
| 32 | else | ||
| 33 | PHP_NEW_EXTENSION(snuffleupagus, $sources, $ext_shared,-DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) | ||
| 34 | fi | ||
| 35 | fi | ||
diff --git a/src/config.w32 b/src/config.w32 new file mode 100644 index 0000000..a0197c1 --- /dev/null +++ b/src/config.w32 | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | // $Id$ | ||
| 2 | // vim:ft=javascript | ||
| 3 | |||
| 4 | // If your extension references something external, use ARG_WITH | ||
| 5 | // ARG_WITH("snuffleupagus", "for snuffleupagus support", "no"); | ||
| 6 | |||
| 7 | // Otherwise, use ARG_ENABLE | ||
| 8 | // ARG_ENABLE("snuffleupagus", "enable snuffleupagus support", "no"); | ||
| 9 | |||
| 10 | if (PHP_SNUFFLEUPAGUS != "no") { | ||
| 11 | EXTENSION("snuffleupagus", "snuffleupagus.c", PHP_EXTNAME_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); | ||
| 12 | } | ||
| 13 | |||
diff --git a/src/php_snuffleupagus.h b/src/php_snuffleupagus.h new file mode 100644 index 0000000..e7a3d59 --- /dev/null +++ b/src/php_snuffleupagus.h | |||
| @@ -0,0 +1,71 @@ | |||
| 1 | #ifndef PHP_SNUFFLEUPAGUS_H | ||
| 2 | #define PHP_SNUFFLEUPAGUS_H | ||
| 3 | |||
| 4 | #define PHP_SNUFFLEUPAGUS_VERSION "0.1" | ||
| 5 | #define PHP_SNUFFLEUPAGUS_EXTNAME "snuffleupagus" | ||
| 6 | #define PHP_SNUFFLEUPAGUS_AUTHOR "NBS System" | ||
| 7 | #define PHP_SNUFFLEUPAGUS_URL "https://github.com/nbs-system/snuffleupagus" | ||
| 8 | #define PHP_SNUFFLEUPAGUS_COPYRIGHT "LGPLv2" | ||
| 9 | |||
| 10 | #include <stdbool.h> | ||
| 11 | #include <stdio.h> | ||
| 12 | |||
| 13 | #include <pcre.h> | ||
| 14 | #include <sys/types.h> | ||
| 15 | #include <sys/wait.h> | ||
| 16 | |||
| 17 | #include "SAPI.h" | ||
| 18 | #include "ext/standard/info.h" | ||
| 19 | #include "php.h" | ||
| 20 | #include "php_ini.h" | ||
| 21 | #include "zend_hash.h" | ||
| 22 | #include "zend_string.h" | ||
| 23 | #include "zend_extensions.h" | ||
| 24 | |||
| 25 | #include "sp_list.h" | ||
| 26 | #include "sp_compile.h" | ||
| 27 | #include "sp_config.h" | ||
| 28 | #include "sp_config_utils.h" | ||
| 29 | #include "sp_config_keywords.h" | ||
| 30 | #include "sp_cookie_encryption.h" | ||
| 31 | #include "sp_disable_xxe.h" | ||
| 32 | #include "sp_disabled_functions.h" | ||
| 33 | #include "sp_execute.h" | ||
| 34 | #include "sp_harden_rand.h" | ||
| 35 | #include "sp_network_utils.h" | ||
| 36 | #include "sp_unserialize.h" | ||
| 37 | #include "sp_upload_validation.h" | ||
| 38 | #include "sp_utils.h" | ||
| 39 | |||
| 40 | extern zend_module_entry snuffleupagus_module_entry; | ||
| 41 | #define phpext_snuffleupagus_ptr &snuffleupagus_module_entry | ||
| 42 | |||
| 43 | #ifdef PHP_WIN32 | ||
| 44 | #define PHP_SNUFFLEUPAGUS_API __declspec(dllexport) | ||
| 45 | #elif defined(__GNUC__) && __GNUC__ >= 4 | ||
| 46 | #define PHP_SNUFFLEUPAGUS_API __attribute__((visibility("default"))) | ||
| 47 | #else | ||
| 48 | #define PHP_SNUFFLEUPAGUS_API | ||
| 49 | #endif | ||
| 50 | |||
| 51 | #ifdef ZTS | ||
| 52 | #include "TSRM.h" | ||
| 53 | #endif | ||
| 54 | |||
| 55 | ZEND_BEGIN_MODULE_GLOBALS(snuffleupagus) | ||
| 56 | sp_config config; | ||
| 57 | HashTable *disabled_functions_hook; | ||
| 58 | HashTable *sp_internal_functions_hook; | ||
| 59 | ZEND_END_MODULE_GLOBALS(snuffleupagus) | ||
| 60 | |||
| 61 | #define SNUFFLEUPAGUS_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(snuffleupagus, v) | ||
| 62 | |||
| 63 | #if defined(ZTS) && defined(COMPILE_DL_SNUFFLEUPAGUS) | ||
| 64 | ZEND_TSRMLS_CACHE_EXTERN() | ||
| 65 | #endif | ||
| 66 | |||
| 67 | PHP_FUNCTION(check_disabled_function); | ||
| 68 | |||
| 69 | static inline void sp_terminate() { zend_bailout(); } | ||
| 70 | |||
| 71 | #endif /* PHP_SNUFFLEUPAGUS_H */ | ||
diff --git a/src/snuffleupagus.c b/src/snuffleupagus.c new file mode 100644 index 0000000..52b975e --- /dev/null +++ b/src/snuffleupagus.c | |||
| @@ -0,0 +1,222 @@ | |||
| 1 | #ifdef HAVE_CONFIG_H | ||
| 2 | #include "config.h" | ||
| 3 | #endif | ||
| 4 | |||
| 5 | #include "php_snuffleupagus.h" | ||
| 6 | |||
| 7 | #ifndef ZEND_EXT_API | ||
| 8 | #define ZEND_EXT_API ZEND_DLEXPORT | ||
| 9 | #endif | ||
| 10 | |||
| 11 | static PHP_INI_MH(OnUpdateConfiguration); | ||
| 12 | static inline int zend_auto_start(zend_extension *extension); | ||
| 13 | static inline void sp_op_array_handler(zend_op_array *op); | ||
| 14 | |||
| 15 | ZEND_EXTENSION(); | ||
| 16 | |||
| 17 | ZEND_DLEXPORT int sp_zend_startup(zend_extension *extension) { | ||
| 18 | return zend_startup_module(&snuffleupagus_module_entry); | ||
| 19 | } | ||
| 20 | |||
| 21 | static inline void sp_op_array_handler(zend_op_array *op) { | ||
| 22 | if (NULL == op->filename) { | ||
| 23 | return; | ||
| 24 | } else { | ||
| 25 | op->fn_flags |= ZEND_ACC_STRICT_TYPES; | ||
| 26 | } | ||
| 27 | } | ||
| 28 | |||
| 29 | ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus) | ||
| 30 | |||
| 31 | PHP_INI_BEGIN() | ||
| 32 | PHP_INI_ENTRY("sp.configuration_file", "", PHP_INI_SYSTEM, | ||
| 33 | OnUpdateConfiguration) | ||
| 34 | PHP_INI_END() | ||
| 35 | |||
| 36 | ZEND_DLEXPORT zend_extension zend_extension_entry = { | ||
| 37 | PHP_SNUFFLEUPAGUS_EXTNAME, | ||
| 38 | PHP_SNUFFLEUPAGUS_VERSION, | ||
| 39 | PHP_SNUFFLEUPAGUS_AUTHOR, | ||
| 40 | PHP_SNUFFLEUPAGUS_URL, | ||
| 41 | PHP_SNUFFLEUPAGUS_COPYRIGHT, | ||
| 42 | sp_zend_startup, | ||
| 43 | NULL, | ||
| 44 | NULL, /* activate_func_t */ | ||
| 45 | NULL, /* deactivate_func_t */ | ||
| 46 | NULL, /* message_handler_func_t */ | ||
| 47 | sp_op_array_handler,//zend_global_strict, /* op_array_handler_func_t */ | ||
| 48 | NULL, /* statement_handler_func_t */ | ||
| 49 | NULL, /* fcall_begin_handler_func_t */ | ||
| 50 | NULL, /* fcall_end_handler_func_t */ | ||
| 51 | NULL, /* op_array_ctor_func_t */ | ||
| 52 | NULL, /* op_array_dtor_func_t */ | ||
| 53 | STANDARD_ZEND_EXTENSION_PROPERTIES}; | ||
| 54 | |||
| 55 | /* Uncomment this function if you have INI entries | ||
| 56 | static void php_snuffleupagus_init_globals(zend_snuffleupagus_globals | ||
| 57 | *snuffleupagus_globals) | ||
| 58 | { | ||
| 59 | snuffleupagus_globals->global_value = 0; | ||
| 60 | snuffleupagus_globals->global_string = NULL; | ||
| 61 | } | ||
| 62 | */ | ||
| 63 | |||
| 64 | PHP_GINIT_FUNCTION(snuffleupagus) { | ||
| 65 | #define SP_INIT(F) F = pecalloc(sizeof(*F), 1, 1); | ||
| 66 | #define SP_INIT_HT(F) \ | ||
| 67 | F = pemalloc(sizeof(*F), 1); \ | ||
| 68 | zend_hash_init(F, 10, NULL, NULL, 1); | ||
| 69 | |||
| 70 | SP_INIT_HT(snuffleupagus_globals->disabled_functions_hook); | ||
| 71 | SP_INIT_HT(snuffleupagus_globals->sp_internal_functions_hook); | ||
| 72 | |||
| 73 | SP_INIT(snuffleupagus_globals->config.config_unserialize); | ||
| 74 | SP_INIT(snuffleupagus_globals->config.config_random); | ||
| 75 | SP_INIT(snuffleupagus_globals->config.config_readonly_exec); | ||
| 76 | SP_INIT(snuffleupagus_globals->config.config_global_strict); | ||
| 77 | SP_INIT(snuffleupagus_globals->config.config_auto_cookie_secure); | ||
| 78 | SP_INIT(snuffleupagus_globals->config.config_snuffleupagus); | ||
| 79 | SP_INIT(snuffleupagus_globals->config.config_disable_xxe); | ||
| 80 | SP_INIT(snuffleupagus_globals->config.config_upload_validation); | ||
| 81 | SP_INIT(snuffleupagus_globals->config.config_disabled_functions); | ||
| 82 | SP_INIT(snuffleupagus_globals->config.config_disabled_functions_ret); | ||
| 83 | SP_INIT(snuffleupagus_globals->config.config_cookie_encryption); | ||
| 84 | SP_INIT(snuffleupagus_globals->config.config_regexp_inclusion); | ||
| 85 | |||
| 86 | snuffleupagus_globals->config.config_regexp_inclusion->regexp_inclusion = sp_new_list(); | ||
| 87 | snuffleupagus_globals->config.config_disabled_functions->disabled_functions = sp_new_list(); | ||
| 88 | snuffleupagus_globals->config.config_disabled_functions_ret->disabled_functions = sp_new_list(); | ||
| 89 | |||
| 90 | SP_INIT_HT(snuffleupagus_globals->config.config_cookie_encryption->names); | ||
| 91 | |||
| 92 | #undef SP_INIT | ||
| 93 | #undef SP_INIT_HT | ||
| 94 | } | ||
| 95 | |||
| 96 | PHP_MINIT_FUNCTION(snuffleupagus) { | ||
| 97 | REGISTER_INI_ENTRIES(); | ||
| 98 | |||
| 99 | return SUCCESS; | ||
| 100 | } | ||
| 101 | |||
| 102 | PHP_MSHUTDOWN_FUNCTION(snuffleupagus) { | ||
| 103 | #define FREE_HT(F) \ | ||
| 104 | zend_hash_destroy(SNUFFLEUPAGUS_G(F)); \ | ||
| 105 | pefree(SNUFFLEUPAGUS_G(F), 1); | ||
| 106 | |||
| 107 | FREE_HT(disabled_functions_hook); | ||
| 108 | FREE_HT(config.config_cookie_encryption->names); | ||
| 109 | |||
| 110 | #undef FREE_HT | ||
| 111 | |||
| 112 | pefree(SNUFFLEUPAGUS_G(config.config_unserialize), 1); | ||
| 113 | pefree(SNUFFLEUPAGUS_G(config.config_random), 1); | ||
| 114 | pefree(SNUFFLEUPAGUS_G(config.config_readonly_exec), 1); | ||
| 115 | pefree(SNUFFLEUPAGUS_G(config.config_global_strict), 1); | ||
| 116 | pefree(SNUFFLEUPAGUS_G(config.config_auto_cookie_secure), 1); | ||
| 117 | pefree(SNUFFLEUPAGUS_G(config.config_snuffleupagus), 1); | ||
| 118 | pefree(SNUFFLEUPAGUS_G(config.config_disable_xxe), 1); | ||
| 119 | pefree(SNUFFLEUPAGUS_G(config.config_upload_validation), 1); | ||
| 120 | pefree(SNUFFLEUPAGUS_G(config.config_cookie_encryption), 1); | ||
| 121 | |||
| 122 | sp_list_free(SNUFFLEUPAGUS_G(config.config_disabled_functions->disabled_functions)); | ||
| 123 | pefree(SNUFFLEUPAGUS_G(config.config_disabled_functions), 1); | ||
| 124 | sp_list_free(SNUFFLEUPAGUS_G(config.config_disabled_functions_ret->disabled_functions)); | ||
| 125 | pefree(SNUFFLEUPAGUS_G(config.config_disabled_functions_ret), 1); | ||
| 126 | |||
| 127 | UNREGISTER_INI_ENTRIES(); | ||
| 128 | |||
| 129 | return SUCCESS; | ||
| 130 | } | ||
| 131 | |||
| 132 | PHP_RINIT_FUNCTION(snuffleupagus) { | ||
| 133 | #if defined(COMPILE_DL_SNUFFLEUPAGUS) && defined(ZTS) | ||
| 134 | ZEND_TSRMLS_CACHE_UPDATE(); | ||
| 135 | #endif | ||
| 136 | if (NULL != SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key) { | ||
| 137 | if (NULL != SNUFFLEUPAGUS_G(config).config_cookie_encryption->names) { | ||
| 138 | zend_hash_apply_with_arguments( | ||
| 139 | Z_ARRVAL(PG(http_globals)[TRACK_VARS_COOKIE]), decrypt_cookie, 0); | ||
| 140 | } | ||
| 141 | } | ||
| 142 | return SUCCESS; | ||
| 143 | } | ||
| 144 | |||
| 145 | PHP_RSHUTDOWN_FUNCTION(snuffleupagus) { return SUCCESS; } | ||
| 146 | |||
| 147 | PHP_MINFO_FUNCTION(snuffleupagus) { | ||
| 148 | php_info_print_table_start(); | ||
| 149 | php_info_print_table_header(2, "snuffleupagus support", "enabled"); | ||
| 150 | php_info_print_table_end(); | ||
| 151 | |||
| 152 | /* Remove comments if you have entries in php.ini | ||
| 153 | DISPLAY_INI_ENTRIES(); | ||
| 154 | */ | ||
| 155 | } | ||
| 156 | |||
| 157 | static PHP_INI_MH(OnUpdateConfiguration) { | ||
| 158 | TSRMLS_FETCH(); | ||
| 159 | |||
| 160 | if (!new_value || !new_value->len) { | ||
| 161 | return FAILURE; | ||
| 162 | } | ||
| 163 | |||
| 164 | if (sp_parse_config(new_value->val) != SUCCESS) { | ||
| 165 | return FAILURE; | ||
| 166 | } | ||
| 167 | |||
| 168 | if (SNUFFLEUPAGUS_G(config).config_random->enable) { | ||
| 169 | hook_rand(); | ||
| 170 | } | ||
| 171 | if (SNUFFLEUPAGUS_G(config).config_upload_validation->enable) { | ||
| 172 | hook_upload(); | ||
| 173 | } | ||
| 174 | if (SNUFFLEUPAGUS_G(config).config_disable_xxe->enable == 0) { | ||
| 175 | hook_libxml_disable_entity_loader(); | ||
| 176 | } | ||
| 177 | hook_disabled_functions(); | ||
| 178 | hook_execute(); | ||
| 179 | |||
| 180 | if (NULL != SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key) { | ||
| 181 | if (SNUFFLEUPAGUS_G(config).config_unserialize->enable) { | ||
| 182 | hook_serialize(); | ||
| 183 | } | ||
| 184 | hook_cookies(); | ||
| 185 | } | ||
| 186 | |||
| 187 | if (true == SNUFFLEUPAGUS_G(config).config_global_strict->enable) { | ||
| 188 | if (!zend_get_extension(PHP_SNUFFLEUPAGUS_EXTNAME)) { | ||
| 189 | zend_extension_entry.startup = NULL; | ||
| 190 | zend_register_extension(&zend_extension_entry, NULL); | ||
| 191 | } | ||
| 192 | // This is needed to implement the global strict mode | ||
| 193 | CG(compiler_options) |= ZEND_COMPILE_HANDLE_OP_ARRAY; | ||
| 194 | } | ||
| 195 | |||
| 196 | return SUCCESS; | ||
| 197 | } | ||
| 198 | |||
| 199 | const zend_function_entry snuffleupagus_functions[] = {PHP_FE_END}; | ||
| 200 | |||
| 201 | zend_module_entry snuffleupagus_module_entry = | ||
| 202 | {STANDARD_MODULE_HEADER, | ||
| 203 | PHP_SNUFFLEUPAGUS_EXTNAME, | ||
| 204 | snuffleupagus_functions, | ||
| 205 | PHP_MINIT(snuffleupagus), | ||
| 206 | PHP_MSHUTDOWN(snuffleupagus), | ||
| 207 | PHP_RINIT(snuffleupagus), | ||
| 208 | PHP_RSHUTDOWN(snuffleupagus), | ||
| 209 | PHP_MINFO(snuffleupagus), | ||
| 210 | PHP_SNUFFLEUPAGUS_VERSION, | ||
| 211 | PHP_MODULE_GLOBALS(snuffleupagus), | ||
| 212 | PHP_GINIT(snuffleupagus), | ||
| 213 | NULL, | ||
| 214 | NULL, | ||
| 215 | STANDARD_MODULE_PROPERTIES_EX}; | ||
| 216 | |||
| 217 | #ifdef COMPILE_DL_SNUFFLEUPAGUS | ||
| 218 | #ifdef ZTS | ||
| 219 | ZEND_TSRMLS_CACHE_DEFINE() | ||
| 220 | #endif | ||
| 221 | ZEND_GET_MODULE(snuffleupagus) | ||
| 222 | #endif | ||
diff --git a/src/snuffleupagus.php b/src/snuffleupagus.php new file mode 100644 index 0000000..b373a53 --- /dev/null +++ b/src/snuffleupagus.php | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | <?php | ||
| 2 | $br = (php_sapi_name() == "cli")? "":"<br>"; | ||
| 3 | |||
| 4 | if(!extension_loaded('snuffleupagus')) { | ||
| 5 | dl('snuffleupagus.' . PHP_SHLIB_SUFFIX); | ||
| 6 | } | ||
| 7 | $module = 'snuffleupagus'; | ||
| 8 | $functions = get_extension_funcs($module); | ||
| 9 | echo "Functions available in the test extension:$br\n"; | ||
| 10 | foreach($functions as $func) { | ||
| 11 | echo $func."$br\n"; | ||
| 12 | } | ||
| 13 | echo "$br\n"; | ||
| 14 | $function = 'confirm_' . $module . '_compiled'; | ||
| 15 | if (extension_loaded($module)) { | ||
| 16 | $str = $function($module); | ||
| 17 | } else { | ||
| 18 | $str = "Module $module is not compiled into PHP"; | ||
| 19 | } | ||
| 20 | echo "$str\n"; | ||
| 21 | ?> | ||
diff --git a/src/sp_compile.c b/src/sp_compile.c new file mode 100644 index 0000000..2902377 --- /dev/null +++ b/src/sp_compile.c | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | #include "php_snuffleupagus.h" | ||
| 2 | |||
| 3 | ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus); | ||
| 4 | |||
| 5 | static zend_op_array *(*orig_compile_file)(zend_file_handle *, int); | ||
| 6 | static zend_op_array *(*orig_compile_string)(zval *, char *); | ||
| 7 | |||
| 8 | zend_op_array *sp_compile_file(zend_file_handle *file_handle, int type) { | ||
| 9 | zend_op_array *ret = orig_compile_file(file_handle, type); | ||
| 10 | |||
| 11 | const sp_node_t* config = SNUFFLEUPAGUS_G(config).config_disabled_functions->disabled_functions; | ||
| 12 | |||
| 13 | while (config && config->data) { | ||
| 14 | const char* function_name = ((sp_disabled_function*)config->data)->function; | ||
| 15 | const pcre* function_name_regexp = ((sp_disabled_function*)config->data)->r_function; | ||
| 16 | |||
| 17 | sp_log_err("checking for %s", function_name); | ||
| 18 | // EG(function_table)->arData[count - 1].val.value.func->internal_function.handler = PHP_FN(check_disabled_function); | ||
| 19 | |||
| 20 | if (function_name) { | ||
| 21 | if (HOOK_FUNCTION(function_name, disabled_functions_hook, PHP_FN(check_disabled_function), true) == SUCCESS) { | ||
| 22 | sp_log_err("Successfully hooked %s", function_name); | ||
| 23 | } | ||
| 24 | break; | ||
| 25 | } else if (function_name_regexp) { | ||
| 26 | sp_log_err("error", "We'll hook regard later."); | ||
| 27 | } | ||
| 28 | config = config->next; | ||
| 29 | } | ||
| 30 | |||
| 31 | return ret; | ||
| 32 | } | ||
| 33 | |||
| 34 | zend_op_array *sp_compile_string(zval *source_string, char *filename) { | ||
| 35 | zend_op_array *ret = orig_compile_string(source_string, filename); | ||
| 36 | sp_log_err("in compile_string : filename is :%s", filename); | ||
| 37 | return ret; | ||
| 38 | } | ||
| 39 | |||
| 40 | |||
| 41 | int hook_compile(void) { | ||
| 42 | TSRMLS_FETCH(); | ||
| 43 | |||
| 44 | /* zend_compile_file is used to compile php file */ | ||
| 45 | orig_compile_file = zend_compile_file; | ||
| 46 | zend_compile_file = sp_compile_file; | ||
| 47 | |||
| 48 | /* zend_compile_string is used to compile php string */ | ||
| 49 | orig_compile_string = zend_compile_string; | ||
| 50 | zend_compile_string = sp_compile_string; | ||
| 51 | |||
| 52 | return SUCCESS; | ||
| 53 | } \ No newline at end of file | ||
diff --git a/src/sp_compile.h b/src/sp_compile.h new file mode 100644 index 0000000..538ff52 --- /dev/null +++ b/src/sp_compile.h | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | #ifndef SP_COMPILE_H | ||
| 2 | #define SP_COMPILE_H | ||
| 3 | |||
| 4 | int hook_compile(void); | ||
| 5 | |||
| 6 | #endif /* SP_COMPILE_H */ \ No newline at end of file | ||
diff --git a/src/sp_config.c b/src/sp_config.c new file mode 100644 index 0000000..f73347d --- /dev/null +++ b/src/sp_config.c | |||
| @@ -0,0 +1,193 @@ | |||
| 1 | #include <errno.h> | ||
| 2 | #include <stdio.h> | ||
| 3 | #include <string.h> | ||
| 4 | |||
| 5 | #include "php_snuffleupagus.h" | ||
| 6 | |||
| 7 | ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus) | ||
| 8 | |||
| 9 | sp_config_tokens const sp_func[] = { | ||
| 10 | {.func = parse_unserialize, .token = SP_TOKEN_UNSERIALIZE_HMAC}, | ||
| 11 | {.func = parse_random, .token = SP_TOKEN_HARDEN_RANDOM}, | ||
| 12 | {.func = parse_disabled_functions, .token = SP_TOKEN_DISABLE_FUNC}, | ||
| 13 | {.func = parse_readonly_exec, .token = SP_TOKEN_READONLY_EXEC}, | ||
| 14 | {.func = parse_global_strict, .token = SP_TOKEN_GLOBAL_STRICT}, | ||
| 15 | {.func = parse_upload_validation, .token = SP_TOKEN_UPLOAD_VALIDATION}, | ||
| 16 | {.func = parse_cookie_encryption, .token = SP_TOKEN_COOKIE_ENCRYPTION}, | ||
| 17 | {.func = parse_global, .token = SP_TOKEN_GLOBAL}, | ||
| 18 | {.func = parse_auto_cookie_secure, .token = SP_TOKEN_AUTO_COOKIE_SECURE}, | ||
| 19 | {.func = parse_disable_xxe, .token = SP_TOKEN_DISABLE_XXE}, | ||
| 20 | {NULL, NULL}}; | ||
| 21 | |||
| 22 | /* Top level keyword parsing */ | ||
| 23 | |||
| 24 | static int parse_line(char *line) { | ||
| 25 | char *ptr = line; | ||
| 26 | |||
| 27 | while (*ptr == ' ' || *ptr == '\t') { | ||
| 28 | ++ptr; | ||
| 29 | } | ||
| 30 | |||
| 31 | if (!*ptr || *ptr == '#' || *ptr == ';') { | ||
| 32 | return 0; | ||
| 33 | } | ||
| 34 | |||
| 35 | if (strncmp(ptr, SP_TOKEN_BASE, strlen(SP_TOKEN_BASE))) { | ||
| 36 | sp_log_err("config", "Invalid configuration prefix for '%s'.", line); | ||
| 37 | return -1; | ||
| 38 | } | ||
| 39 | ptr += strlen(SP_TOKEN_BASE); | ||
| 40 | |||
| 41 | for (size_t i = 0; sp_func[i].func; i++) { | ||
| 42 | if (!strncmp(sp_func[i].token, ptr, strlen(sp_func[i].token))) { | ||
| 43 | return sp_func[i].func(ptr + strlen(sp_func[i].token)); | ||
| 44 | } | ||
| 45 | } | ||
| 46 | sp_log_err("config", "Invalid configuration section '%s'.", line); | ||
| 47 | return -1; | ||
| 48 | } | ||
| 49 | |||
| 50 | /* keyword parsing */ | ||
| 51 | int parse_empty(char *restrict line, char *restrict keyword, void *retval) { | ||
| 52 | *(bool *)retval = true; | ||
| 53 | return 0; | ||
| 54 | } | ||
| 55 | |||
| 56 | int parse_int(char *restrict line, char *restrict keyword, void *retval) { | ||
| 57 | size_t consumed = 0; | ||
| 58 | char *value = get_param(&consumed, line, SP_TYPE_INT, keyword); | ||
| 59 | if (value) { | ||
| 60 | sscanf(value, "%ud", (uint32_t *)retval); | ||
| 61 | pefree(value, 1); | ||
| 62 | return consumed; | ||
| 63 | } else { | ||
| 64 | sp_log_err("error", "%s) is expecting a valid integer.", keyword); | ||
| 65 | return -1; | ||
| 66 | } | ||
| 67 | } | ||
| 68 | |||
| 69 | int parse_php_type(char *restrict line, char *restrict keyword, void *retval) { | ||
| 70 | size_t consumed = 0; | ||
| 71 | char *value = get_param(&consumed, line, SP_TYPE_STR, keyword); | ||
| 72 | if (value) { | ||
| 73 | if (0 == strcasecmp("undef", value)) { | ||
| 74 | *(sp_php_type*)retval = SP_PHP_TYPE_UNDEF; | ||
| 75 | } else if (0 == strcasecmp("null", value)) { | ||
| 76 | *(sp_php_type*)retval = SP_PHP_TYPE_NULL; | ||
| 77 | } else if (0 == strcasecmp("true", value)) { | ||
| 78 | *(sp_php_type*)retval = SP_PHP_TYPE_TRUE; | ||
| 79 | } else if (0 == strcasecmp("false", value)) { | ||
| 80 | *(sp_php_type*)retval = SP_PHP_TYPE_FALSE; | ||
| 81 | } else if (0 == strcasecmp("long", value)) { | ||
| 82 | *(sp_php_type*)retval = SP_PHP_TYPE_LONG; | ||
| 83 | } else if (0 == strcasecmp("double", value)) { | ||
| 84 | *(sp_php_type*)retval = SP_PHP_TYPE_DOUBLE; | ||
| 85 | } else if (0 == strcasecmp("string", value)) { | ||
| 86 | *(sp_php_type*)retval = SP_PHP_TYPE_STRING; | ||
| 87 | } else if (0 == strcasecmp("array", value)) { | ||
| 88 | *(sp_php_type*)retval = SP_PHP_TYPE_ARRAY; | ||
| 89 | } else if (0 == strcasecmp("object", value)) { | ||
| 90 | *(sp_php_type*)retval = SP_PHP_TYPE_OBJECT; | ||
| 91 | } else if (0 == strcasecmp("resource", value)) { | ||
| 92 | *(sp_php_type*)retval = SP_PHP_TYPE_RESOURCE; | ||
| 93 | } else if (0 == strcasecmp("reference", value)) { | ||
| 94 | *(sp_php_type*)retval = SP_PHP_TYPE_REFERENCE; | ||
| 95 | } else { | ||
| 96 | pefree(value, 1); | ||
| 97 | sp_log_err("error", "%s) is expecting a valid php type ('false', 'true'," | ||
| 98 | " 'array'. 'object', 'long', 'double', 'null', 'resource', 'reference'," | ||
| 99 | " 'undef').", keyword); | ||
| 100 | return -1; | ||
| 101 | } | ||
| 102 | pefree(value, 1); | ||
| 103 | return consumed; | ||
| 104 | } else { | ||
| 105 | return -1; | ||
| 106 | } | ||
| 107 | } | ||
| 108 | |||
| 109 | int parse_str(char *restrict line, char *restrict keyword, void *retval) { | ||
| 110 | char *value = NULL; | ||
| 111 | |||
| 112 | size_t consumed = 0; | ||
| 113 | value = get_param(&consumed, line, SP_TYPE_STR, keyword); | ||
| 114 | if (value) { | ||
| 115 | *(char **)retval = value; | ||
| 116 | return consumed; | ||
| 117 | } | ||
| 118 | return -1; | ||
| 119 | } | ||
| 120 | |||
| 121 | int parse_cidr(char *restrict line, char *restrict keyword, void *retval) { | ||
| 122 | size_t consumed = 0; | ||
| 123 | char *value = get_param(&consumed, line, SP_TYPE_STR, keyword); | ||
| 124 | sp_cidr *cidr = pecalloc(sizeof(sp_cidr), 1, 1); | ||
| 125 | |||
| 126 | if (value) { | ||
| 127 | if (-1 == get_ip_and_cidr(value, cidr)) { | ||
| 128 | return -1; | ||
| 129 | } | ||
| 130 | *(sp_cidr **)retval = cidr; | ||
| 131 | return consumed; | ||
| 132 | } else { | ||
| 133 | sp_log_err("config", "%s doesn't contain a valid cidr.", line); | ||
| 134 | return -1; | ||
| 135 | } | ||
| 136 | } | ||
| 137 | |||
| 138 | int parse_regexp(char *restrict line, char *restrict keyword, void *retval) { | ||
| 139 | /* TODO: Do we want to use pcre_study? | ||
| 140 | * (http://www.pcre.org/original/doc/html/pcre_study.html) | ||
| 141 | * maybe not: http://sljit.sourceforge.net/pcre.html*/ | ||
| 142 | size_t consumed = 0; | ||
| 143 | char *value = get_param(&consumed, line, SP_TYPE_STR, keyword); | ||
| 144 | |||
| 145 | if (value) { | ||
| 146 | const char *pcre_error; | ||
| 147 | int pcre_error_offset; | ||
| 148 | pcre *compiled_re = pcre_compile(value, PCRE_CASELESS, &pcre_error, | ||
| 149 | &pcre_error_offset, NULL); | ||
| 150 | if (NULL == compiled_re) { | ||
| 151 | sp_log_err("config", "Failed to compile '%s': %s.", value, pcre_error); | ||
| 152 | } else { | ||
| 153 | *(pcre **)retval = compiled_re; | ||
| 154 | return consumed; | ||
| 155 | } | ||
| 156 | } | ||
| 157 | char *closing_paren = strchr(line, ')'); | ||
| 158 | if (NULL != closing_paren) { | ||
| 159 | closing_paren[0] = '\0'; | ||
| 160 | } | ||
| 161 | sp_log_err("config", "'%s)' is expecting a valid regexp, and not '%s'.", | ||
| 162 | keyword, line); | ||
| 163 | return -1; | ||
| 164 | } | ||
| 165 | |||
| 166 | int sp_parse_config(const char *conf_file) { | ||
| 167 | FILE *fd = fopen(conf_file, "r"); | ||
| 168 | char *lineptr = NULL; | ||
| 169 | size_t n = 0; | ||
| 170 | |||
| 171 | if (fd == NULL) { | ||
| 172 | sp_log_err("config", "Could not open configuration file %s : %s", conf_file, | ||
| 173 | strerror(errno)); | ||
| 174 | return FAILURE; | ||
| 175 | } | ||
| 176 | |||
| 177 | while (getline(&lineptr, &n, fd) > 0) { | ||
| 178 | /* We trash the terminal `\n`. This simplify the display of logs. */ | ||
| 179 | if (lineptr[strlen(lineptr) - 1] == '\n') { | ||
| 180 | lineptr[strlen(lineptr) - 1] = '\0'; | ||
| 181 | } | ||
| 182 | if (parse_line(lineptr) == -1) { | ||
| 183 | fclose(fd); | ||
| 184 | free(lineptr); | ||
| 185 | return FAILURE; | ||
| 186 | } | ||
| 187 | free(lineptr); | ||
| 188 | lineptr = NULL; | ||
| 189 | n = 0; | ||
| 190 | } | ||
| 191 | fclose(fd); | ||
| 192 | return SUCCESS; | ||
| 193 | } | ||
diff --git a/src/sp_config.h b/src/sp_config.h new file mode 100644 index 0000000..54ec2cc --- /dev/null +++ b/src/sp_config.h | |||
| @@ -0,0 +1,206 @@ | |||
| 1 | #ifndef SP_CONFIG_H | ||
| 2 | #define SP_CONFIG_H | ||
| 3 | |||
| 4 | #include <arpa/inet.h> | ||
| 5 | #include <netinet/in.h> | ||
| 6 | #include <sys/socket.h> | ||
| 7 | |||
| 8 | typedef enum { | ||
| 9 | SP_TYPE_STR = 0, | ||
| 10 | SP_TYPE_REGEXP, | ||
| 11 | SP_TYPE_INT, | ||
| 12 | SP_TYPE_EMPTY | ||
| 13 | } sp_type; | ||
| 14 | |||
| 15 | typedef enum { | ||
| 16 | SP_PHP_TYPE_UNDEF = IS_UNDEF, | ||
| 17 | SP_PHP_TYPE_NULL = IS_NULL, | ||
| 18 | SP_PHP_TYPE_FALSE = IS_FALSE, | ||
| 19 | SP_PHP_TYPE_TRUE = IS_TRUE, | ||
| 20 | SP_PHP_TYPE_LONG = IS_LONG, | ||
| 21 | SP_PHP_TYPE_DOUBLE = IS_DOUBLE, | ||
| 22 | SP_PHP_TYPE_STRING = IS_STRING, | ||
| 23 | SP_PHP_TYPE_ARRAY = IS_ARRAY, | ||
| 24 | SP_PHP_TYPE_OBJECT = IS_OBJECT, | ||
| 25 | SP_PHP_TYPE_RESOURCE = IS_RESOURCE, | ||
| 26 | SP_PHP_TYPE_REFERENCE = IS_REFERENCE | ||
| 27 | } sp_php_type; | ||
| 28 | |||
| 29 | typedef struct { | ||
| 30 | int ip_version; | ||
| 31 | union { | ||
| 32 | struct in_addr ipv4; | ||
| 33 | struct in6_addr ipv6; | ||
| 34 | } ip; | ||
| 35 | uint8_t mask; | ||
| 36 | } sp_cidr; | ||
| 37 | |||
| 38 | typedef struct { char *encryption_key; } sp_config_encryption_key; | ||
| 39 | |||
| 40 | typedef struct { | ||
| 41 | bool enable; | ||
| 42 | bool simulation; | ||
| 43 | } sp_config_readonly_exec; | ||
| 44 | |||
| 45 | typedef struct { bool enable; } sp_config_global_strict; | ||
| 46 | |||
| 47 | typedef struct { bool enable; } sp_config_random; | ||
| 48 | |||
| 49 | typedef struct { bool enable; } sp_config_auto_cookie_secure; | ||
| 50 | |||
| 51 | typedef struct { bool enable; } sp_config_disable_xxe; | ||
| 52 | |||
| 53 | typedef struct { | ||
| 54 | HashTable *names; | ||
| 55 | uint32_t mask_ipv4; | ||
| 56 | uint32_t mask_ipv6; | ||
| 57 | } sp_config_cookie_encryption; | ||
| 58 | |||
| 59 | typedef struct { | ||
| 60 | bool enable; | ||
| 61 | bool simulation; | ||
| 62 | } sp_config_unserialize; | ||
| 63 | |||
| 64 | typedef struct { | ||
| 65 | char *filename; | ||
| 66 | pcre *r_filename; | ||
| 67 | |||
| 68 | char *function; | ||
| 69 | pcre *r_function; | ||
| 70 | |||
| 71 | char *hash; | ||
| 72 | int simulation; | ||
| 73 | bool enable; | ||
| 74 | |||
| 75 | char *param; | ||
| 76 | pcre *r_param; | ||
| 77 | sp_php_type param_type; | ||
| 78 | |||
| 79 | char *ret; | ||
| 80 | pcre *r_ret; | ||
| 81 | sp_php_type ret_type; | ||
| 82 | |||
| 83 | pcre *regexp; | ||
| 84 | char *value; | ||
| 85 | |||
| 86 | char *dump; | ||
| 87 | char *alias; | ||
| 88 | bool param_is_array; | ||
| 89 | bool var_is_array; | ||
| 90 | sp_node_t *param_array_keys; | ||
| 91 | sp_node_t *var_array_keys; | ||
| 92 | |||
| 93 | bool allow; | ||
| 94 | bool drop; | ||
| 95 | |||
| 96 | char *var; | ||
| 97 | |||
| 98 | sp_cidr *cidr; | ||
| 99 | } sp_disabled_function; | ||
| 100 | |||
| 101 | typedef struct { | ||
| 102 | sp_node_t *disabled_functions; // list of sp_disabled_function | ||
| 103 | } sp_config_disabled_functions; | ||
| 104 | |||
| 105 | typedef struct { | ||
| 106 | sp_node_t *regexp_inclusion; // list of regexp for inclusion | ||
| 107 | } sp_config_regexp_inclusion; | ||
| 108 | |||
| 109 | typedef struct { | ||
| 110 | char *script; | ||
| 111 | bool simulation; | ||
| 112 | bool enable; | ||
| 113 | } sp_config_upload_validation; | ||
| 114 | |||
| 115 | typedef struct { | ||
| 116 | sp_config_random *config_random; | ||
| 117 | sp_config_unserialize *config_unserialize; | ||
| 118 | sp_config_disabled_functions *config_disabled_functions; | ||
| 119 | sp_config_disabled_functions *config_disabled_functions_ret; | ||
| 120 | sp_config_readonly_exec *config_readonly_exec; | ||
| 121 | sp_config_upload_validation *config_upload_validation; | ||
| 122 | sp_config_cookie_encryption *config_cookie_encryption; | ||
| 123 | sp_config_encryption_key *config_snuffleupagus; | ||
| 124 | sp_config_auto_cookie_secure *config_auto_cookie_secure; | ||
| 125 | sp_config_global_strict *config_global_strict; | ||
| 126 | sp_config_disable_xxe *config_disable_xxe; | ||
| 127 | sp_config_regexp_inclusion *config_regexp_inclusion; | ||
| 128 | } sp_config; | ||
| 129 | |||
| 130 | typedef struct { | ||
| 131 | int (*func)(char *, char *, void *); | ||
| 132 | char *token; | ||
| 133 | void *retval; | ||
| 134 | } sp_config_functions; | ||
| 135 | |||
| 136 | typedef struct { | ||
| 137 | int (*func)(char *); | ||
| 138 | char *token; | ||
| 139 | } sp_config_tokens; | ||
| 140 | |||
| 141 | #define SP_TOKEN_BASE "sp" | ||
| 142 | |||
| 143 | #define SP_TOKEN_AUTO_COOKIE_SECURE ".auto_cookie_secure" | ||
| 144 | #define SP_TOKEN_COOKIE_ENCRYPTION ".cookie_encryption" | ||
| 145 | #define SP_TOKEN_DISABLE_FUNC ".disable_functions" | ||
| 146 | #define SP_TOKEN_GLOBAL ".global" | ||
| 147 | #define SP_TOKEN_GLOBAL_STRICT ".global_strict" | ||
| 148 | #define SP_TOKEN_HARDEN_RANDOM ".harden_random" | ||
| 149 | #define SP_TOKEN_READONLY_EXEC ".readonly_exec" | ||
| 150 | #define SP_TOKEN_UNSERIALIZE_HMAC ".unserialize_hmac" | ||
| 151 | #define SP_TOKEN_UPLOAD_VALIDATION ".upload_validation" | ||
| 152 | #define SP_TOKEN_DISABLE_XXE ".disable_xxe" | ||
| 153 | |||
| 154 | // common tokens | ||
| 155 | #define SP_TOKEN_ENABLE ".enable(" | ||
| 156 | #define SP_TOKEN_DISABLE ".disable(" | ||
| 157 | #define SP_TOKEN_SIMULATION ".simulation(" | ||
| 158 | #define SP_TOKEN_TRUE "1" | ||
| 159 | #define SP_TOKEN_FALSE "0" | ||
| 160 | #define SP_TOKEN_DUMP ".dump(" | ||
| 161 | #define SP_TOKEN_ALIAS ".alias(" | ||
| 162 | #define SP_TOKEN_ALLOW ".allow(" | ||
| 163 | #define SP_TOKEN_DROP ".drop(" | ||
| 164 | |||
| 165 | #define SP_TOKEN_END_PARAM ')' | ||
| 166 | |||
| 167 | // disable_function | ||
| 168 | #define SP_TOKEN_CIDR ".cidr(" | ||
| 169 | #define SP_TOKEN_FILENAME ".filename(" | ||
| 170 | #define SP_TOKEN_FILENAME_REGEXP ".filename_r(" | ||
| 171 | #define SP_TOKEN_FUNCTION ".function(" | ||
| 172 | #define SP_TOKEN_FUNCTION_REGEXP ".function_r(" | ||
| 173 | #define SP_TOKEN_HASH ".hash(" | ||
| 174 | #define SP_TOKEN_LOCAL_VAR ".var(" | ||
| 175 | #define SP_TOKEN_PARAM ".param(" | ||
| 176 | #define SP_TOKEN_PARAM_REGEXP ".param_r(" | ||
| 177 | #define SP_TOKEN_PARAM_TYPE ".param_type(" | ||
| 178 | #define SP_TOKEN_RET ".ret(" | ||
| 179 | #define SP_TOKEN_RET_REGEXP ".ret_r(" | ||
| 180 | #define SP_TOKEN_RET_TYPE ".ret_type(" | ||
| 181 | #define SP_TOKEN_VALUE ".value(" | ||
| 182 | #define SP_TOKEN_VALUE_REGEXP ".value_r(" | ||
| 183 | |||
| 184 | // cookies encryption | ||
| 185 | #define SP_TOKEN_NAME ".cookie(" | ||
| 186 | #define SP_TOKEN_MASK_IPV4 ".mask_ipv4(" | ||
| 187 | #define SP_TOKEN_MASK_IPV6 ".mask_ipv6(" | ||
| 188 | |||
| 189 | // Global configuration options | ||
| 190 | #define SP_TOKEN_ENCRYPTION_KEY ".secret_key(" | ||
| 191 | |||
| 192 | // upload_validator | ||
| 193 | #define SP_TOKEN_UPLOAD_SCRIPT ".script(" | ||
| 194 | |||
| 195 | int sp_parse_config(const char *); | ||
| 196 | int parse_array(sp_disabled_function *); | ||
| 197 | |||
| 198 | int parse_str(char *restrict, char *restrict, void *); | ||
| 199 | int parse_regexp(char *restrict, char *restrict, void *); | ||
| 200 | int parse_empty(char *restrict, char *restrict, void *); | ||
| 201 | int parse_int(char *restrict, char *restrict, void *); | ||
| 202 | int parse_cidr(char *restrict, char *restrict, void *); | ||
| 203 | int parse_php_type(char *restrict, char *restrict, void *); | ||
| 204 | |||
| 205 | |||
| 206 | #endif /* SP_CONFIG_H */ | ||
diff --git a/src/sp_config_keywords.c b/src/sp_config_keywords.c new file mode 100644 index 0000000..4a6dd3a --- /dev/null +++ b/src/sp_config_keywords.c | |||
| @@ -0,0 +1,268 @@ | |||
| 1 | #include "php_snuffleupagus.h" | ||
| 2 | |||
| 3 | ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus) | ||
| 4 | |||
| 5 | static int parse_enable(char *line, bool * restrict retval, bool * restrict simulation) { | ||
| 6 | bool enable = false, disable = false; | ||
| 7 | sp_config_functions sp_config_funcs[] = { | ||
| 8 | {parse_empty, SP_TOKEN_ENABLE, &(enable)}, | ||
| 9 | {parse_empty, SP_TOKEN_DISABLE, &(disable)}, | ||
| 10 | {parse_empty, SP_TOKEN_SIMULATION, simulation}, | ||
| 11 | {0}}; | ||
| 12 | |||
| 13 | int ret = parse_keywords(sp_config_funcs, line); | ||
| 14 | |||
| 15 | if (0 != ret) { | ||
| 16 | return ret; | ||
| 17 | } | ||
| 18 | |||
| 19 | if (!(enable ^ disable)) { | ||
| 20 | sp_log_err("config", "A rule can't be enabled and disabled."); | ||
| 21 | return -1; | ||
| 22 | } | ||
| 23 | |||
| 24 | *retval = enable; | ||
| 25 | |||
| 26 | return ret; | ||
| 27 | } | ||
| 28 | |||
| 29 | int parse_random(char *line) { | ||
| 30 | return parse_enable(line, &(SNUFFLEUPAGUS_G(config).config_random->enable), NULL); | ||
| 31 | } | ||
| 32 | |||
| 33 | int parse_disable_xxe(char *line) { | ||
| 34 | return parse_enable(line, &(SNUFFLEUPAGUS_G(config).config_disable_xxe->enable), NULL); | ||
| 35 | } | ||
| 36 | |||
| 37 | int parse_auto_cookie_secure(char *line) { | ||
| 38 | return parse_enable(line, &(SNUFFLEUPAGUS_G(config).config_auto_cookie_secure->enable), NULL); | ||
| 39 | } | ||
| 40 | |||
| 41 | int parse_global_strict(char *line) { | ||
| 42 | return parse_enable(line, &(SNUFFLEUPAGUS_G(config).config_global_strict->enable), NULL); | ||
| 43 | } | ||
| 44 | |||
| 45 | int parse_unserialize(char *line) { | ||
| 46 | return parse_enable(line, &(SNUFFLEUPAGUS_G(config).config_unserialize->enable), &(SNUFFLEUPAGUS_G(config).config_unserialize->simulation)); | ||
| 47 | } | ||
| 48 | |||
| 49 | int parse_readonly_exec(char *line) { | ||
| 50 | return parse_enable(line, &(SNUFFLEUPAGUS_G(config).config_readonly_exec->enable), &(SNUFFLEUPAGUS_G(config).config_readonly_exec->simulation)); | ||
| 51 | } | ||
| 52 | |||
| 53 | int parse_global(char *line) { | ||
| 54 | sp_config_functions sp_config_funcs_encryption_key[] = { | ||
| 55 | {parse_str, SP_TOKEN_ENCRYPTION_KEY, | ||
| 56 | &(SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key)}, | ||
| 57 | {0}}; | ||
| 58 | return parse_keywords(sp_config_funcs_encryption_key, line); | ||
| 59 | } | ||
| 60 | |||
| 61 | int parse_cookie_encryption(char *line) { | ||
| 62 | int ret = 0; | ||
| 63 | char *name = NULL; | ||
| 64 | |||
| 65 | sp_config_functions sp_config_funcs_cookie_encryption[] = { | ||
| 66 | {parse_str, SP_TOKEN_NAME, &name}, | ||
| 67 | {parse_int, SP_TOKEN_MASK_IPV4, | ||
| 68 | &(SNUFFLEUPAGUS_G(config).config_cookie_encryption->mask_ipv4)}, | ||
| 69 | {parse_int, SP_TOKEN_MASK_IPV6, | ||
| 70 | &(SNUFFLEUPAGUS_G(config).config_cookie_encryption->mask_ipv6)}, | ||
| 71 | {0}}; | ||
| 72 | |||
| 73 | ret = parse_keywords(sp_config_funcs_cookie_encryption, line); | ||
| 74 | if (0 != ret) { | ||
| 75 | return ret; | ||
| 76 | } | ||
| 77 | |||
| 78 | if (32 < SNUFFLEUPAGUS_G(config).config_cookie_encryption->mask_ipv4) { | ||
| 79 | SNUFFLEUPAGUS_G(config).config_cookie_encryption->mask_ipv4 = 32; | ||
| 80 | } | ||
| 81 | if (128 < SNUFFLEUPAGUS_G(config).config_cookie_encryption->mask_ipv6) { | ||
| 82 | SNUFFLEUPAGUS_G(config).config_cookie_encryption->mask_ipv6 = 128; | ||
| 83 | } | ||
| 84 | |||
| 85 | if (name) { | ||
| 86 | zend_hash_str_add_empty_element( | ||
| 87 | SNUFFLEUPAGUS_G(config).config_cookie_encryption->names, name, | ||
| 88 | strlen(name)); | ||
| 89 | } | ||
| 90 | return SUCCESS; | ||
| 91 | } | ||
| 92 | |||
| 93 | int parse_disabled_functions(char *line) { | ||
| 94 | int ret = 0; | ||
| 95 | bool enable = true, disable = false; | ||
| 96 | sp_disabled_function *df = pecalloc(sizeof(*df), 1, 1); | ||
| 97 | |||
| 98 | sp_config_functions sp_config_funcs_disabled_functions[] = { | ||
| 99 | {parse_empty, SP_TOKEN_ENABLE, &(enable)}, | ||
| 100 | {parse_empty, SP_TOKEN_DISABLE, &(disable)}, | ||
| 101 | {parse_str, SP_TOKEN_ALIAS, &(df->alias)}, | ||
| 102 | {parse_empty, SP_TOKEN_SIMULATION, &(df->simulation)}, | ||
| 103 | {parse_str, SP_TOKEN_FILENAME, &(df->filename)}, | ||
| 104 | {parse_regexp, SP_TOKEN_FILENAME_REGEXP, &(df->r_filename)}, | ||
| 105 | {parse_str, SP_TOKEN_FUNCTION, &(df->function)}, | ||
| 106 | {parse_regexp, SP_TOKEN_FUNCTION_REGEXP, &(df->r_function)}, | ||
| 107 | {parse_str, SP_TOKEN_DUMP, &(df->dump)}, | ||
| 108 | {parse_empty, SP_TOKEN_ALLOW, &(df->allow)}, | ||
| 109 | {parse_empty, SP_TOKEN_DROP, &(df->drop)}, | ||
| 110 | {parse_str, SP_TOKEN_HASH, &(df->hash)}, | ||
| 111 | {parse_str, SP_TOKEN_PARAM, &(df->param)}, | ||
| 112 | {parse_regexp, SP_TOKEN_VALUE_REGEXP, &(df->regexp)}, | ||
| 113 | {parse_str, SP_TOKEN_VALUE, &(df->value)}, | ||
| 114 | {parse_regexp, SP_TOKEN_PARAM_REGEXP, &(df->r_param)}, | ||
| 115 | {parse_php_type, SP_TOKEN_PARAM_TYPE, &(df->param_type)}, | ||
| 116 | {parse_str, SP_TOKEN_RET, &(df->ret)}, | ||
| 117 | {parse_cidr, SP_TOKEN_CIDR, &(df->cidr)}, | ||
| 118 | {parse_regexp, SP_TOKEN_RET_REGEXP, &(df->r_ret)}, | ||
| 119 | {parse_php_type, SP_TOKEN_RET_TYPE, &(df->ret_type)}, | ||
| 120 | {parse_str, SP_TOKEN_LOCAL_VAR, &(df->var)}, | ||
| 121 | {0}}; | ||
| 122 | |||
| 123 | ret = parse_keywords(sp_config_funcs_disabled_functions, line); | ||
| 124 | |||
| 125 | if (0 != ret) { | ||
| 126 | return ret; | ||
| 127 | } | ||
| 128 | |||
| 129 | if (true == disable){ | ||
| 130 | df->enable = false; | ||
| 131 | } else { | ||
| 132 | df->enable = true; | ||
| 133 | } | ||
| 134 | |||
| 135 | if (df->value && df->regexp) { | ||
| 136 | sp_log_err("config", | ||
| 137 | "Invalid configuration line: 'sp.disabled_functions%s':" | ||
| 138 | "'.value' and '.regexp' are mutually exclusives.", | ||
| 139 | line); | ||
| 140 | return -1; | ||
| 141 | } else if (df->r_function && df->function) { | ||
| 142 | sp_log_err("config", | ||
| 143 | "Invalid configuration line: 'sp.disabled_functions%s': " | ||
| 144 | "'.r_function' and '.function' are mutually exclusive.", | ||
| 145 | line); | ||
| 146 | return -1; | ||
| 147 | } else if (df->r_filename && df->filename) { | ||
| 148 | sp_log_err("config", | ||
| 149 | "Invalid configuration line: 'sp.disabled_functions%s':" | ||
| 150 | "'.r_filename' and '.filename' are mutually exclusive.", | ||
| 151 | line); | ||
| 152 | return -1; | ||
| 153 | } else if (df->r_param && df->param) { | ||
| 154 | sp_log_err("config", | ||
| 155 | "Invalid configuration line: 'sp.disabled_functions%s':" | ||
| 156 | "'.r_param' and '.param' are mutually exclusive.", | ||
| 157 | line); | ||
| 158 | return -1; | ||
| 159 | } else if (df->r_ret && df->ret) { | ||
| 160 | sp_log_err("config", | ||
| 161 | "Invalid configuration line: 'sp.disabled_functions%s':" | ||
| 162 | "'.r_ret' and '.ret' are mutually exclusive.", | ||
| 163 | line); | ||
| 164 | return -1; | ||
| 165 | } else if ((df->r_ret || df->ret) && (df->r_param || df->param)) { | ||
| 166 | sp_log_err("config", | ||
| 167 | "Invalid configuration line: 'sp.disabled_functions%s':" | ||
| 168 | "`ret` and `param` are mutually exclusives.", | ||
| 169 | line); | ||
| 170 | return -1; | ||
| 171 | } else if (!(df->r_function || df->function)) { | ||
| 172 | sp_log_err("config", | ||
| 173 | "Invalid configuration line: 'sp.disabled_functions%s':" | ||
| 174 | " must take a function name.", | ||
| 175 | line); | ||
| 176 | return -1; | ||
| 177 | } else if (!(df->allow ^ df->drop)) { | ||
| 178 | sp_log_err("config", | ||
| 179 | "Invalid configuration line: 'sp.disabled_functions%s': The " | ||
| 180 | "rule must either be a `drop` or and `allow` one.", | ||
| 181 | line); | ||
| 182 | return -1; | ||
| 183 | } | ||
| 184 | |||
| 185 | if (df->param && strchr(df->param, '[')) { // assume that this is an array | ||
| 186 | df->param_array_keys = sp_new_list(); | ||
| 187 | if (0 != array_to_list(&df->param, &df->param_array_keys)) { | ||
| 188 | pefree(df->param_array_keys, 1); | ||
| 189 | return -1; | ||
| 190 | } | ||
| 191 | df->param_is_array = 1; | ||
| 192 | } | ||
| 193 | |||
| 194 | if (df->var && strchr(df->var, '[')) { // assume that this is an array | ||
| 195 | df->var_array_keys = sp_new_list(); | ||
| 196 | if (0 != array_to_list(&df->var, &df->var_array_keys)) { | ||
| 197 | pefree(df->var_array_keys, 1); | ||
| 198 | return -1; | ||
| 199 | } | ||
| 200 | df->var_is_array = 1; | ||
| 201 | } | ||
| 202 | |||
| 203 | bool match = false; | ||
| 204 | const char *key[4] = {"include", "include_once", "require", "require_once"}; | ||
| 205 | for (size_t i = 0; i < 4; i++) { | ||
| 206 | if (df->r_function && true == is_regexp_matching(df->r_function, key[i])) { | ||
| 207 | match = true; | ||
| 208 | break; | ||
| 209 | } else if (df->function && 0 == strcmp(df->function, key[i])) { | ||
| 210 | match = true; | ||
| 211 | break; | ||
| 212 | } | ||
| 213 | } | ||
| 214 | if (true == match && df->regexp) { | ||
| 215 | sp_list_insert( | ||
| 216 | SNUFFLEUPAGUS_G(config).config_regexp_inclusion->regexp_inclusion, | ||
| 217 | df->regexp); | ||
| 218 | } else if (df->ret || df->r_ret || df->ret_type) { | ||
| 219 | sp_list_insert( | ||
| 220 | SNUFFLEUPAGUS_G(config).config_disabled_functions_ret->disabled_functions, | ||
| 221 | df); | ||
| 222 | } else { | ||
| 223 | sp_list_insert( | ||
| 224 | SNUFFLEUPAGUS_G(config).config_disabled_functions->disabled_functions, | ||
| 225 | df); | ||
| 226 | } | ||
| 227 | return ret; | ||
| 228 | } | ||
| 229 | |||
| 230 | int parse_upload_validation(char *line) { | ||
| 231 | bool disable = false, enable = false; | ||
| 232 | sp_config_functions sp_config_funcs_upload_validation[] = { | ||
| 233 | {parse_str, SP_TOKEN_UPLOAD_SCRIPT, | ||
| 234 | &(SNUFFLEUPAGUS_G(config).config_upload_validation->script)}, | ||
| 235 | {parse_empty, SP_TOKEN_SIMULATION, | ||
| 236 | &(SNUFFLEUPAGUS_G(config).config_upload_validation->simulation)}, | ||
| 237 | {parse_empty, SP_TOKEN_ENABLE, &(enable)}, | ||
| 238 | {parse_empty, SP_TOKEN_DISABLE, &(disable)}, | ||
| 239 | {0}}; | ||
| 240 | |||
| 241 | int ret = parse_keywords(sp_config_funcs_upload_validation, line); | ||
| 242 | |||
| 243 | if (0 != ret) { | ||
| 244 | return ret; | ||
| 245 | } | ||
| 246 | |||
| 247 | if (!(enable ^ disable)) { | ||
| 248 | sp_log_err("config", "A rule can't be enabled and disabled."); | ||
| 249 | return -1; | ||
| 250 | } | ||
| 251 | SNUFFLEUPAGUS_G(config).config_upload_validation->enable = enable; | ||
| 252 | |||
| 253 | char const *script = SNUFFLEUPAGUS_G(config).config_upload_validation->script; | ||
| 254 | |||
| 255 | if (!script) { | ||
| 256 | sp_log_err("config", "The `script` directive is mandatory in %s", | ||
| 257 | line); | ||
| 258 | return -1; | ||
| 259 | } else if (-1 == access(script, F_OK)) { | ||
| 260 | sp_log_err("config", "The `script` (%s) doesn't exist.", script); | ||
| 261 | return -1; | ||
| 262 | } else if (-1 == access(script, X_OK)) { | ||
| 263 | sp_log_err("config", "The `script` (%s) isn't executable.", script); | ||
| 264 | return -1; | ||
| 265 | } | ||
| 266 | |||
| 267 | return ret; | ||
| 268 | } | ||
diff --git a/src/sp_config_keywords.h b/src/sp_config_keywords.h new file mode 100644 index 0000000..40fac47 --- /dev/null +++ b/src/sp_config_keywords.h | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | #ifndef SP_CONFIG_KEYWORDS_H | ||
| 2 | #define SP_CONFIG_KEYWORDS_H | ||
| 3 | #include "php_snuffleupagus.h" | ||
| 4 | |||
| 5 | int parse_random(char *line); | ||
| 6 | int parse_disable_xxe(char *line); | ||
| 7 | int parse_auto_cookie_secure(char *line); | ||
| 8 | int parse_global_strict(char *line); | ||
| 9 | int parse_global(char *line) ; | ||
| 10 | int parse_cookie_encryption(char *line); | ||
| 11 | int parse_unserialize(char *line) ; | ||
| 12 | int parse_readonly_exec(char *line); | ||
| 13 | int parse_disabled_functions(char *line) ; | ||
| 14 | int parse_upload_validation(char *line); | ||
| 15 | |||
| 16 | #endif // __SP_CONFIG_KEYWORDS_H \ No newline at end of file | ||
diff --git a/src/sp_config_utils.c b/src/sp_config_utils.c new file mode 100644 index 0000000..e05e95e --- /dev/null +++ b/src/sp_config_utils.c | |||
| @@ -0,0 +1,211 @@ | |||
| 1 | #include "php_snuffleupagus.h" | ||
| 2 | |||
| 3 | static int validate_int(const char *value); | ||
| 4 | static int validate_str(const char *value); | ||
| 5 | |||
| 6 | static sp_pure int validate_int(const char *value) { | ||
| 7 | for (size_t i = 0; i < strlen(value); i++) { | ||
| 8 | if (!isdigit(value[i])) { | ||
| 9 | return -1; | ||
| 10 | } | ||
| 11 | } | ||
| 12 | return 0; | ||
| 13 | } | ||
| 14 | |||
| 15 | static sp_pure int validate_str(const char *value) { | ||
| 16 | int balance = 0; // ghetto [] validation | ||
| 17 | |||
| 18 | if (!strchr(value, '[')) { | ||
| 19 | return 0; | ||
| 20 | } | ||
| 21 | |||
| 22 | for (size_t i = 0; i < strlen(value); i++) { | ||
| 23 | if (value[i] == '[') { | ||
| 24 | balance++; | ||
| 25 | } else if (value[i] == ']') { | ||
| 26 | balance--; | ||
| 27 | } | ||
| 28 | if (balance < 0) { | ||
| 29 | return -1; | ||
| 30 | } | ||
| 31 | } | ||
| 32 | return balance != 0; | ||
| 33 | } | ||
| 34 | |||
| 35 | int parse_keywords(sp_config_functions *funcs, char *line) { | ||
| 36 | int value_len = 0; | ||
| 37 | const char *original_line = line; | ||
| 38 | for (size_t i = 0; funcs[i].func; i++) { | ||
| 39 | if (!strncmp(funcs[i].token, line, strlen(funcs[i].token))) { | ||
| 40 | line += strlen(funcs[i].token); | ||
| 41 | value_len = funcs[i].func(line, funcs[i].token, funcs[i].retval) + 1; | ||
| 42 | if (value_len == 0) { // bad parameter | ||
| 43 | return -1; | ||
| 44 | } | ||
| 45 | line += value_len; | ||
| 46 | i = -1; // we start the loop again | ||
| 47 | } | ||
| 48 | } | ||
| 49 | while (*line == ';' || *line == '\t' || *line == ' ') { | ||
| 50 | line++; | ||
| 51 | } | ||
| 52 | |||
| 53 | if (*line == '#') { | ||
| 54 | return 0; | ||
| 55 | } | ||
| 56 | |||
| 57 | if (*line) { | ||
| 58 | sp_log_err("config", "Trailing chars '%s' at the end of '%s'.", line, | ||
| 59 | original_line); | ||
| 60 | return -1; | ||
| 61 | } | ||
| 62 | return 0; | ||
| 63 | } | ||
| 64 | |||
| 65 | static char *get_string(size_t *consumed, char *restrict line, | ||
| 66 | const char *restrict keyword) { | ||
| 67 | enum { IN_ESCAPE, NONE } state = NONE; | ||
| 68 | char *original_line = line; | ||
| 69 | size_t j = 0; | ||
| 70 | |||
| 71 | char *ret = NULL; | ||
| 72 | if (NULL == line) { | ||
| 73 | goto err; | ||
| 74 | } | ||
| 75 | |||
| 76 | ret = pecalloc(sizeof(char), strlen(original_line) + 1, 1); | ||
| 77 | |||
| 78 | /* The first char of a string is always '"', since they MUST be quoted. */ | ||
| 79 | if ('"' == *line) { | ||
| 80 | line++; | ||
| 81 | } else { | ||
| 82 | goto err; | ||
| 83 | } | ||
| 84 | |||
| 85 | for (size_t i = 0; line[i] && j < strlen(original_line) - 2; i++) { | ||
| 86 | switch (line[i]) { | ||
| 87 | case '"': | ||
| 88 | /* A double quote at this point is either: | ||
| 89 | - at the very end of the string. | ||
| 90 | - escaped | ||
| 91 | */ | ||
| 92 | if ((state == NONE) && (line[i + 1] == SP_TOKEN_END_PARAM)) { | ||
| 93 | /* The `+2` if for | ||
| 94 | 1. the terminal double-quote | ||
| 95 | 2. the SP_TOKEN_END_PARAM | ||
| 96 | */ | ||
| 97 | *consumed = i + 2; | ||
| 98 | return ret; | ||
| 99 | } else if (state == IN_ESCAPE) { | ||
| 100 | break; // we're on an escped double quote | ||
| 101 | } else { | ||
| 102 | goto err; | ||
| 103 | } | ||
| 104 | case '\\': | ||
| 105 | if (state == NONE) { | ||
| 106 | state = IN_ESCAPE; | ||
| 107 | continue; | ||
| 108 | } | ||
| 109 | default: | ||
| 110 | break; | ||
| 111 | } | ||
| 112 | if (state == IN_ESCAPE) { | ||
| 113 | state = NONE; | ||
| 114 | } | ||
| 115 | ret[j++] = line[i]; | ||
| 116 | } | ||
| 117 | err: | ||
| 118 | sp_log_err("error", | ||
| 119 | "There is an issue with the parsing of '%s': it doesn't look like a valid string.", | ||
| 120 | original_line ? original_line : "NULL"); | ||
| 121 | line = NULL; | ||
| 122 | return NULL; | ||
| 123 | } | ||
| 124 | |||
| 125 | static char *get_misc(char *restrict line, const char *restrict keyword) { | ||
| 126 | size_t i = 0; | ||
| 127 | char *ret = pecalloc(sizeof(char), 1024, 1); | ||
| 128 | |||
| 129 | while (i < 1024 - 1 && line[i] && line[i] != SP_TOKEN_END_PARAM) { | ||
| 130 | ret[i] = line[i]; | ||
| 131 | i++; | ||
| 132 | } | ||
| 133 | |||
| 134 | if (line[i] != SP_TOKEN_END_PARAM) { | ||
| 135 | if (i >= 1024 - 1) { | ||
| 136 | sp_log_err("config", "The following line is too long: %s.", line); | ||
| 137 | } else { | ||
| 138 | sp_log_err("config", "Missing closing %c in line %s.", SP_TOKEN_END_PARAM, | ||
| 139 | line); | ||
| 140 | } | ||
| 141 | return NULL; | ||
| 142 | } else if (i == 0) { | ||
| 143 | sp_log_err("config", "The keyword %s%c is expecting a parameter.", | ||
| 144 | keyword, SP_TOKEN_END_PARAM); | ||
| 145 | return NULL; | ||
| 146 | } | ||
| 147 | return ret; | ||
| 148 | } | ||
| 149 | |||
| 150 | char *get_param(size_t *consumed, char *restrict line, sp_type type, | ||
| 151 | const char *restrict keyword) { | ||
| 152 | char *retval = NULL; | ||
| 153 | if (type == SP_TYPE_STR) { | ||
| 154 | retval = get_string(consumed, line, keyword); | ||
| 155 | } else { | ||
| 156 | retval = get_misc(line, keyword); | ||
| 157 | *consumed = retval ? strlen(retval) : 0; | ||
| 158 | } | ||
| 159 | |||
| 160 | if (retval) { | ||
| 161 | if (type == SP_TYPE_STR && 0 == validate_str(retval)) { | ||
| 162 | return retval; | ||
| 163 | } else if (type == SP_TYPE_INT && 0 == validate_int(retval)) { | ||
| 164 | return retval; | ||
| 165 | } | ||
| 166 | } | ||
| 167 | return NULL; | ||
| 168 | } | ||
| 169 | |||
| 170 | // FIXME this is leaking like hell @blotus | ||
| 171 | int array_to_list(char **name_ptr, sp_node_t **keys) { | ||
| 172 | int in_key = 0; | ||
| 173 | size_t i = 0; | ||
| 174 | char *name = *name_ptr; | ||
| 175 | char *key_name = ecalloc(strlen(name) + 1, 1); // im way too lazy for | ||
| 176 | // now | ||
| 177 | char *tmp = ecalloc(strlen(name) + 1, 1); | ||
| 178 | |||
| 179 | for (i = 0; name[i] != '['; i++) { | ||
| 180 | tmp[i] = name[i]; | ||
| 181 | } | ||
| 182 | tmp[i] = 0; | ||
| 183 | |||
| 184 | for (size_t j = 0; name[i]; i++) { | ||
| 185 | const char c = name[i]; | ||
| 186 | if (c == '[') { | ||
| 187 | if (in_key == 0) { | ||
| 188 | in_key = 1; | ||
| 189 | } else { | ||
| 190 | efree(key_name); | ||
| 191 | return -1; | ||
| 192 | } | ||
| 193 | } else if (c == ']') { | ||
| 194 | if (in_key == 0) { | ||
| 195 | efree(key_name); | ||
| 196 | return -1; | ||
| 197 | } else { | ||
| 198 | in_key = 0; | ||
| 199 | j = 0; | ||
| 200 | sp_list_insert(*keys, pestrdup(key_name, 1)); | ||
| 201 | memset(key_name, 0, strlen(name) + 1); | ||
| 202 | } | ||
| 203 | } else if (in_key == 1) { | ||
| 204 | key_name[j] = c; | ||
| 205 | j++; | ||
| 206 | } | ||
| 207 | } | ||
| 208 | efree(key_name); | ||
| 209 | *name_ptr = pestrdup(tmp, 1); | ||
| 210 | return in_key; | ||
| 211 | } | ||
diff --git a/src/sp_config_utils.h b/src/sp_config_utils.h new file mode 100644 index 0000000..f2f8fce --- /dev/null +++ b/src/sp_config_utils.h | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | #ifndef SP_CONFIG_UTILS | ||
| 2 | #define SP_CONFIG_UTILS | ||
| 3 | |||
| 4 | int parse_keywords(sp_config_functions *, char *); | ||
| 5 | char *get_param(size_t *, char *restrict, sp_type, const char *restrict); | ||
| 6 | int array_to_list(char **, sp_node_t **); | ||
| 7 | |||
| 8 | #endif /* SP_CONFIG_UTILS */ | ||
diff --git a/src/sp_cookie_encryption.c b/src/sp_cookie_encryption.c new file mode 100644 index 0000000..5248486 --- /dev/null +++ b/src/sp_cookie_encryption.c | |||
| @@ -0,0 +1,216 @@ | |||
| 1 | #include "php_snuffleupagus.h" | ||
| 2 | |||
| 3 | #include "ext/standard/url.h" | ||
| 4 | |||
| 5 | ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus) | ||
| 6 | |||
| 7 | static unsigned int nonce_d = 0; | ||
| 8 | |||
| 9 | static inline void generate_key(unsigned char *key) { | ||
| 10 | PHP_SHA256_CTX ctx; | ||
| 11 | const char *user_agent = sp_getenv("HTTP_USER_AGENT"); | ||
| 12 | const char *remote_addr = sp_getenv("REMOTE_ADDR"); | ||
| 13 | const char *encryption_key = | ||
| 14 | SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key; | ||
| 15 | |||
| 16 | /* 32 is the size of a SHA256. */ | ||
| 17 | assert(32 == crypto_secretbox_KEYBYTES); | ||
| 18 | |||
| 19 | PHP_SHA256Init(&ctx); | ||
| 20 | |||
| 21 | if (user_agent) { | ||
| 22 | PHP_SHA256Update(&ctx, (unsigned char *)user_agent, strlen(user_agent)); | ||
| 23 | } | ||
| 24 | |||
| 25 | if (remote_addr) { | ||
| 26 | char out[128]; | ||
| 27 | apply_mask_on_ip(out, remote_addr); | ||
| 28 | PHP_SHA256Update(&ctx, (unsigned char*)out, sizeof(out)); | ||
| 29 | } | ||
| 30 | |||
| 31 | if (encryption_key) { | ||
| 32 | PHP_SHA256Update(&ctx, (const unsigned char *)encryption_key, | ||
| 33 | strlen(encryption_key)); | ||
| 34 | } | ||
| 35 | |||
| 36 | PHP_SHA256Final((unsigned char *)key, &ctx); | ||
| 37 | } | ||
| 38 | |||
| 39 | int decrypt_cookie(zval *pDest, int num_args, va_list args, | ||
| 40 | zend_hash_key *hash_key) { | ||
| 41 | unsigned char key[crypto_secretbox_KEYBYTES] = {0}; | ||
| 42 | size_t value_len; | ||
| 43 | zend_string *debase64; | ||
| 44 | unsigned char *decrypted; | ||
| 45 | int ret = 0; | ||
| 46 | |||
| 47 | /* If the cookie isn't in the conf, it shouldn't be encrypted. */ | ||
| 48 | if (0 == | ||
| 49 | zend_hash_exists(SNUFFLEUPAGUS_G(config).config_cookie_encryption->names, | ||
| 50 | hash_key->key)) { | ||
| 51 | return ZEND_HASH_APPLY_KEEP; | ||
| 52 | } | ||
| 53 | |||
| 54 | generate_key(key); | ||
| 55 | |||
| 56 | value_len = php_url_decode(Z_STRVAL_P(pDest), Z_STRLEN_P(pDest)); | ||
| 57 | |||
| 58 | if (value_len == 0) { | ||
| 59 | return ZEND_HASH_APPLY_KEEP; | ||
| 60 | } | ||
| 61 | |||
| 62 | debase64 = php_base64_decode((unsigned char *)(Z_STRVAL_P(pDest)), value_len); | ||
| 63 | |||
| 64 | if (value_len < | ||
| 65 | crypto_secretbox_NONCEBYTES + crypto_secretbox_ZEROBYTES) { | ||
| 66 | sp_log_msg("cookie_encryption", LOG_DROP, | ||
| 67 | "Buffer underflow tentative detected in cookie encryption handling."); | ||
| 68 | return ZEND_HASH_APPLY_REMOVE; | ||
| 69 | } | ||
| 70 | |||
| 71 | decrypted = pecalloc(value_len, 1, 0); | ||
| 72 | |||
| 73 | ret = crypto_secretbox_open( | ||
| 74 | decrypted, | ||
| 75 | (unsigned char *)(ZSTR_VAL(debase64) + crypto_secretbox_NONCEBYTES), | ||
| 76 | ZSTR_LEN(debase64) - crypto_secretbox_NONCEBYTES, | ||
| 77 | (unsigned char *)ZSTR_VAL(debase64), key); | ||
| 78 | |||
| 79 | if (ret == -1) { | ||
| 80 | sp_log_msg("cookie_encryption", LOG_DROP, | ||
| 81 | "Something went wrong with the decryption of %s.", | ||
| 82 | ZSTR_VAL(hash_key->key)); | ||
| 83 | return ZEND_HASH_APPLY_REMOVE; | ||
| 84 | } | ||
| 85 | |||
| 86 | ZVAL_STRINGL(pDest, (char *)(decrypted + crypto_secretbox_ZEROBYTES), | ||
| 87 | ZSTR_LEN(debase64) - crypto_secretbox_NONCEBYTES - 1 - | ||
| 88 | crypto_secretbox_ZEROBYTES); | ||
| 89 | |||
| 90 | return ZEND_HASH_APPLY_KEEP; | ||
| 91 | } | ||
| 92 | |||
| 93 | /** | ||
| 94 | This function will return the `data` of length `data_len` encrypted in the | ||
| 95 | form | ||
| 96 | base64(nonce | encrypted_data) (with `|` being the concatenation | ||
| 97 | operation). | ||
| 98 | |||
| 99 | The `nonce` is time-based. | ||
| 100 | */ | ||
| 101 | static zend_string *encrypt_data(char *data, unsigned long long data_len) { | ||
| 102 | const size_t encrypted_msg_len = crypto_secretbox_ZEROBYTES + data_len + 1; | ||
| 103 | const size_t emsg_and_nonce_len = encrypted_msg_len + crypto_secretbox_NONCEBYTES; | ||
| 104 | |||
| 105 | unsigned char key[crypto_secretbox_KEYBYTES] = {0}; | ||
| 106 | unsigned char nonce[crypto_secretbox_NONCEBYTES] = {0}; | ||
| 107 | unsigned char *data_to_encrypt = pecalloc(encrypted_msg_len, 1, 0); | ||
| 108 | unsigned char *encrypted_data = pecalloc(emsg_and_nonce_len, 1, 1); | ||
| 109 | |||
| 110 | generate_key(key); | ||
| 111 | |||
| 112 | /* tweetnacl's API requires the message to be padded with | ||
| 113 | crypto_secretbox_ZEROBYTES zeroes. */ | ||
| 114 | memcpy(data_to_encrypt + crypto_secretbox_ZEROBYTES, data, data_len); | ||
| 115 | |||
| 116 | assert(sizeof(size_t) <= crypto_secretbox_NONCEBYTES); | ||
| 117 | |||
| 118 | nonce_d++; | ||
| 119 | sscanf((char*)nonce, "%ud", &nonce_d); | ||
| 120 | |||
| 121 | memcpy(encrypted_data, nonce, crypto_secretbox_NONCEBYTES); | ||
| 122 | crypto_secretbox(encrypted_data + crypto_secretbox_NONCEBYTES, | ||
| 123 | data_to_encrypt, encrypted_msg_len, nonce, key); | ||
| 124 | |||
| 125 | zend_string *z = php_base64_encode(encrypted_data, emsg_and_nonce_len); | ||
| 126 | sp_log_debug("cookie_encryption", "Cookie value:%s:", z->val); | ||
| 127 | return z; | ||
| 128 | } | ||
| 129 | |||
| 130 | PHP_FUNCTION(sp_setcookie) { | ||
| 131 | zval params[7] = { 0 }; | ||
| 132 | zend_string *name = NULL, *value = NULL, *path = NULL, *domain = NULL; | ||
| 133 | zend_long expires = 0; | ||
| 134 | zend_bool secure = 0, httponly = 0; | ||
| 135 | zval ret_val; | ||
| 136 | zval func_name; | ||
| 137 | |||
| 138 | ZEND_PARSE_PARAMETERS_START(1, 7) | ||
| 139 | Z_PARAM_STR(name) | ||
| 140 | Z_PARAM_OPTIONAL | ||
| 141 | Z_PARAM_STR(value) | ||
| 142 | Z_PARAM_LONG(expires) | ||
| 143 | Z_PARAM_STR(path) | ||
| 144 | Z_PARAM_STR(domain) | ||
| 145 | Z_PARAM_BOOL(secure) | ||
| 146 | Z_PARAM_BOOL(httponly) | ||
| 147 | ZEND_PARSE_PARAMETERS_END(); | ||
| 148 | |||
| 149 | /* If the request was issued over HTTPS, the cookie should be "secure" */ | ||
| 150 | if (SNUFFLEUPAGUS_G(config).config_auto_cookie_secure) { | ||
| 151 | const zval server_vars = PG(http_globals)[TRACK_VARS_SERVER]; | ||
| 152 | if (Z_TYPE(server_vars) == IS_ARRAY) { | ||
| 153 | const zval *is_https = | ||
| 154 | zend_hash_str_find(Z_ARRVAL(server_vars), "HTTPS", strlen("HTTPS")); | ||
| 155 | if (NULL != is_https) { | ||
| 156 | secure = 1; | ||
| 157 | } | ||
| 158 | } | ||
| 159 | } | ||
| 160 | |||
| 161 | /* If the cookie's value is encrypted, it won't be usable by | ||
| 162 | * javascript anyway. | ||
| 163 | */ | ||
| 164 | if (zend_hash_exists(SNUFFLEUPAGUS_G(config).config_cookie_encryption->names, | ||
| 165 | name) > 0) { | ||
| 166 | httponly = 1; | ||
| 167 | } | ||
| 168 | |||
| 169 | /* Shall we encrypt the cookie's value? */ | ||
| 170 | if (zend_hash_exists(SNUFFLEUPAGUS_G(config).config_cookie_encryption->names, | ||
| 171 | name) > 0 && value) { | ||
| 172 | zend_string *encrypted_data = encrypt_data(value->val, value->len); | ||
| 173 | ZVAL_STR_COPY(¶ms[1], encrypted_data); | ||
| 174 | zend_string_release(encrypted_data); | ||
| 175 | } else if (value) { | ||
| 176 | ZVAL_STR_COPY(¶ms[1], value); | ||
| 177 | } | ||
| 178 | |||
| 179 | ZVAL_STRING(&func_name, "setcookie"); | ||
| 180 | ZVAL_STR_COPY(¶ms[0], name); | ||
| 181 | ZVAL_LONG(¶ms[2], expires); | ||
| 182 | if (path) { | ||
| 183 | ZVAL_STR_COPY(¶ms[3], path); | ||
| 184 | } | ||
| 185 | if (domain) { | ||
| 186 | ZVAL_STR_COPY(¶ms[4], domain); | ||
| 187 | } | ||
| 188 | if (secure) { | ||
| 189 | ZVAL_LONG(¶ms[5], secure); | ||
| 190 | } | ||
| 191 | if (httponly) { | ||
| 192 | ZVAL_LONG(¶ms[6], httponly); | ||
| 193 | } | ||
| 194 | |||
| 195 | /* This is the _fun_ part: because PHP is utterly idiotic and nonsensical, | ||
| 196 | the `call_user_function` macro will __discard__ (yes) its first argument | ||
| 197 | (the hashtable), effectively calling functions from `CG(function_table)`. | ||
| 198 | This is why were replacing our hook with the original function, calling | ||
| 199 | the function, and then re-hooking it. */ | ||
| 200 | void (*handler)(INTERNAL_FUNCTION_PARAMETERS); | ||
| 201 | handler = zend_hash_str_find_ptr(SNUFFLEUPAGUS_G(sp_internal_functions_hook), "setcookie", | ||
| 202 | strlen("setcookie")); | ||
| 203 | zend_internal_function *func = zend_hash_str_find_ptr( | ||
| 204 | CG(function_table), "setcookie", strlen("setcookie")); | ||
| 205 | func->handler = handler; | ||
| 206 | |||
| 207 | call_user_function(CG(function_table), NULL, &func_name, &ret_val, 7, params); | ||
| 208 | |||
| 209 | func->handler = PHP_FN(sp_setcookie); | ||
| 210 | } | ||
| 211 | |||
| 212 | int hook_cookies() { | ||
| 213 | HOOK_FUNCTION("setcookie", sp_internal_functions_hook, PHP_FN(sp_setcookie), false); | ||
| 214 | |||
| 215 | return SUCCESS; | ||
| 216 | } | ||
diff --git a/src/sp_cookie_encryption.h b/src/sp_cookie_encryption.h new file mode 100644 index 0000000..9904738 --- /dev/null +++ b/src/sp_cookie_encryption.h | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | |||
| 2 | #ifndef __SP_COOKIE_ENCRYPTION | ||
| 3 | #define __SP_COOKIE_ENCRYPTION | ||
| 4 | |||
| 5 | #include "SAPI.h" | ||
| 6 | #include "tweetnacl.h" | ||
| 7 | |||
| 8 | #include "sp_utils.h" | ||
| 9 | |||
| 10 | #include "ext/hash/php_hash.h" | ||
| 11 | #include "ext/hash/php_hash_sha.h" | ||
| 12 | #include "ext/standard/base64.h" | ||
| 13 | |||
| 14 | int hook_cookies(); | ||
| 15 | int decrypt_cookie(zval *pDest, int num_args, va_list args, zend_hash_key *hash_key); | ||
| 16 | |||
| 17 | #endif /* __SP_COOKIE_ENCRYPTION */ | ||
diff --git a/src/sp_disable_xxe.c b/src/sp_disable_xxe.c new file mode 100644 index 0000000..d11b3d0 --- /dev/null +++ b/src/sp_disable_xxe.c | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | #include "php_snuffleupagus.h" | ||
| 2 | |||
| 3 | ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus) | ||
| 4 | |||
| 5 | PHP_FUNCTION(sp_libxml_disable_entity_loader) { RETURN_TRUE; } | ||
| 6 | |||
| 7 | int hook_libxml_disable_entity_loader() { | ||
| 8 | zval func_name; | ||
| 9 | zval hmac; | ||
| 10 | zval params[1]; | ||
| 11 | |||
| 12 | TSRMLS_FETCH(); | ||
| 13 | |||
| 14 | /* Call the php function here instead of re-implementing it is a bit | ||
| 15 | * ugly, but we do not want to introduce compile-time dependencies against | ||
| 16 | * libxml. */ | ||
| 17 | ZVAL_STRING(&func_name, "libxml_disable_entity_loader"); | ||
| 18 | ZVAL_STRING(¶ms[0], "true"); | ||
| 19 | call_user_function(CG(function_table), NULL, &func_name, &hmac, 1, params); | ||
| 20 | |||
| 21 | HOOK_FUNCTION("libxml_disable_entity_loader", sp_internal_functions_hook, | ||
| 22 | PHP_FN(sp_libxml_disable_entity_loader), false); | ||
| 23 | |||
| 24 | return SUCCESS; | ||
| 25 | } | ||
diff --git a/src/sp_disable_xxe.h b/src/sp_disable_xxe.h new file mode 100644 index 0000000..274c169 --- /dev/null +++ b/src/sp_disable_xxe.h | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | #ifndef __SP_DISABLE_XXE_H | ||
| 2 | #define __SP_DISABLE_XXE_H | ||
| 3 | |||
| 4 | int hook_libxml_disable_entity_loader(); | ||
| 5 | |||
| 6 | #endif /* __SP_DISABLE_XXE_H */ | ||
diff --git a/src/sp_disabled_functions.c b/src/sp_disabled_functions.c new file mode 100644 index 0000000..55d782b --- /dev/null +++ b/src/sp_disabled_functions.c | |||
| @@ -0,0 +1,356 @@ | |||
| 1 | #include "php_snuffleupagus.h" | ||
| 2 | |||
| 3 | #include "zend_execute.h" | ||
| 4 | #include "zend_hash.h" | ||
| 5 | |||
| 6 | ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus); | ||
| 7 | |||
| 8 | ZEND_COLD static zend_always_inline bool is_hash_matching( | ||
| 9 | const char* current_filename, | ||
| 10 | sp_disabled_function const* const config_node) { | ||
| 11 | char current_file_hash[SHA256_SIZE * 2]; | ||
| 12 | compute_hash(current_filename, current_file_hash); | ||
| 13 | return (0 == strncmp(current_file_hash, config_node->hash, SHA256_SIZE)); | ||
| 14 | } | ||
| 15 | |||
| 16 | static zend_always_inline char* get_complete_function_path( | ||
| 17 | zend_execute_data const* const execute_data) { | ||
| 18 | char const* class_name; | ||
| 19 | char const* const function_name = | ||
| 20 | ZSTR_VAL(execute_data->func->common.function_name); | ||
| 21 | char* complete_path_function = NULL; | ||
| 22 | |||
| 23 | class_name = get_active_class_name(NULL); | ||
| 24 | if (*class_name) { | ||
| 25 | const size_t len = strlen(class_name) + 2 + strlen(function_name) + 1; | ||
| 26 | complete_path_function = emalloc(len); | ||
| 27 | snprintf(complete_path_function, len, "%s::%s", class_name, function_name); | ||
| 28 | } else { | ||
| 29 | complete_path_function = estrdup(function_name); | ||
| 30 | } | ||
| 31 | return complete_path_function; | ||
| 32 | } | ||
| 33 | |||
| 34 | static bool is_local_var_matching(zend_execute_data *execute_data, const sp_disabled_function *const config_node) { | ||
| 35 | zend_execute_data *orig_execute_data = execute_data; | ||
| 36 | |||
| 37 | /*because execute_data points to hooked function data, | ||
| 38 | which we dont care about */ | ||
| 39 | zend_execute_data *current = execute_data->prev_execute_data; | ||
| 40 | zval *value = NULL; | ||
| 41 | |||
| 42 | while (current) { | ||
| 43 | zend_string *key = NULL; | ||
| 44 | EG(current_execute_data) = current; | ||
| 45 | zend_array *symtable = zend_rebuild_symbol_table(); | ||
| 46 | ZEND_HASH_FOREACH_STR_KEY_VAL(symtable, key, value) { | ||
| 47 | if (0 == strcmp(config_node->var, key->val)) { // is the var name right? | ||
| 48 | if (Z_TYPE_P(value) == IS_INDIRECT) { | ||
| 49 | value = Z_INDIRECT_P(value); | ||
| 50 | } | ||
| 51 | if (Z_TYPE_P(value) != IS_ARRAY) { | ||
| 52 | char *var_value_str = sp_convert_to_string(value); | ||
| 53 | if (true == sp_match_value(var_value_str, config_node->value, config_node->regexp)) { | ||
| 54 | efree(var_value_str); | ||
| 55 | EG(current_execute_data) = orig_execute_data; | ||
| 56 | return true; | ||
| 57 | } | ||
| 58 | efree(var_value_str); | ||
| 59 | } | ||
| 60 | else { | ||
| 61 | EG(current_execute_data) = orig_execute_data; | ||
| 62 | return sp_match_array_key_recurse(value, config_node->var_array_keys, config_node->value, NULL); | ||
| 63 | } | ||
| 64 | } | ||
| 65 | } | ||
| 66 | ZEND_HASH_FOREACH_END(); | ||
| 67 | current = current->prev_execute_data; | ||
| 68 | } | ||
| 69 | |||
| 70 | EG(current_execute_data) = orig_execute_data; | ||
| 71 | return false; | ||
| 72 | } | ||
| 73 | |||
| 74 | bool should_disable(zend_execute_data* execute_data) { | ||
| 75 | const char* current_filename = zend_get_executed_filename(TSRMLS_C); | ||
| 76 | const sp_node_t* config = | ||
| 77 | SNUFFLEUPAGUS_G(config).config_disabled_functions->disabled_functions; | ||
| 78 | const char* function_name = | ||
| 79 | ZSTR_VAL(execute_data->func->common.function_name); | ||
| 80 | char* complete_path_function; | ||
| 81 | char const* client_ip = sp_getenv("REMOTE_ADDR"); | ||
| 82 | |||
| 83 | if (!function_name) { | ||
| 84 | return false; | ||
| 85 | } | ||
| 86 | |||
| 87 | if (!config || !config->data) { | ||
| 88 | return false; | ||
| 89 | } | ||
| 90 | |||
| 91 | complete_path_function = get_complete_function_path(execute_data); | ||
| 92 | |||
| 93 | while (config) { | ||
| 94 | sp_disabled_function const* const config_node = | ||
| 95 | (sp_disabled_function*)(config->data); | ||
| 96 | const char* arg_name = NULL; | ||
| 97 | const char* arg_value_str = NULL; | ||
| 98 | |||
| 99 | if (false == config_node->enable) { | ||
| 100 | goto next; | ||
| 101 | } | ||
| 102 | |||
| 103 | if (config_node->function) { /* Litteral match against the function name. */ | ||
| 104 | if (0 != strcmp(config_node->function, complete_path_function)) { | ||
| 105 | goto next; | ||
| 106 | } | ||
| 107 | } else if (config_node->r_function) { | ||
| 108 | if (false == | ||
| 109 | is_regexp_matching(config_node->r_function, complete_path_function)) { | ||
| 110 | goto next; | ||
| 111 | } | ||
| 112 | } | ||
| 113 | if (config_node->var) { | ||
| 114 | if (false == is_local_var_matching(execute_data, config_node)) { | ||
| 115 | goto next; | ||
| 116 | } | ||
| 117 | } | ||
| 118 | |||
| 119 | if (config_node->filename) { /* Check the current file name. */ | ||
| 120 | if (0 != strcmp(current_filename, config_node->filename)) { | ||
| 121 | goto next; | ||
| 122 | } | ||
| 123 | } else if (config_node->r_filename) { | ||
| 124 | if (false == | ||
| 125 | is_regexp_matching(config_node->r_filename, current_filename)) { | ||
| 126 | goto next; | ||
| 127 | } | ||
| 128 | } | ||
| 129 | |||
| 130 | if (config_node->hash) { | ||
| 131 | if (false == is_hash_matching(current_filename, config_node)) { | ||
| 132 | goto next; | ||
| 133 | } | ||
| 134 | } | ||
| 135 | |||
| 136 | if (client_ip && config_node->cidr && | ||
| 137 | (false == cidr_match(client_ip, config_node->cidr))) { | ||
| 138 | goto next; | ||
| 139 | } | ||
| 140 | |||
| 141 | /* Check if we filter on parameter value*/ | ||
| 142 | if (config_node->param || config_node->r_param) { | ||
| 143 | const unsigned int nb_param = execute_data->func->common.num_args; | ||
| 144 | bool arg_matched = false; | ||
| 145 | |||
| 146 | for (unsigned int i = 0; i < nb_param; i++) { | ||
| 147 | arg_matched = false; | ||
| 148 | if (ZEND_USER_CODE(execute_data->func->type)) { // yay consistency | ||
| 149 | arg_name = ZSTR_VAL(execute_data->func->common.arg_info[i].name); | ||
| 150 | } else { | ||
| 151 | arg_name = execute_data->func->internal_function.arg_info[i].name; | ||
| 152 | } | ||
| 153 | |||
| 154 | const bool arg_matching = | ||
| 155 | config_node->param && (0 == strcmp(arg_name, config_node->param)); | ||
| 156 | const bool pcre_matching = | ||
| 157 | config_node->r_param && | ||
| 158 | (true == is_regexp_matching(config_node->r_param, arg_name)); | ||
| 159 | |||
| 160 | /* This is the parameter name we're looking for. */ | ||
| 161 | if (true == arg_matching || true == pcre_matching) { | ||
| 162 | zval* arg_value = ZEND_CALL_VAR_NUM(execute_data, i); | ||
| 163 | |||
| 164 | if (config_node->param_type) { // Are we matching on the `type`? | ||
| 165 | if (config_node->param_type == Z_TYPE_P(arg_value)) { | ||
| 166 | arg_matched = true; | ||
| 167 | break; | ||
| 168 | } | ||
| 169 | } else if (Z_TYPE_P(arg_value) == IS_ARRAY) { | ||
| 170 | arg_value_str = estrdup("Array"); | ||
| 171 | // match on arr -> match on all key content, if a key is an array, | ||
| 172 | // ignore it | ||
| 173 | // match on arr[foo] -> match only on key foo, if the key is an | ||
| 174 | // array, match on all keys content | ||
| 175 | if (config_node->param_is_array == true) { | ||
| 176 | if (true == sp_match_array_key_recurse( | ||
| 177 | arg_value, config_node->param_array_keys, | ||
| 178 | config_node->value, config_node->regexp)) { | ||
| 179 | arg_matched = true; | ||
| 180 | break; | ||
| 181 | } | ||
| 182 | } else { // match on all keys, but don't go into subarray | ||
| 183 | if (true == sp_match_array_key(arg_value, config_node->value, | ||
| 184 | config_node->regexp)) { | ||
| 185 | arg_matched = true; | ||
| 186 | break; | ||
| 187 | } | ||
| 188 | } | ||
| 189 | } else { | ||
| 190 | arg_value_str = sp_convert_to_string(arg_value); | ||
| 191 | if (true == sp_match_value(arg_value_str, config_node->value, | ||
| 192 | config_node->regexp)) { | ||
| 193 | arg_matched = true; | ||
| 194 | break; | ||
| 195 | } | ||
| 196 | } | ||
| 197 | } | ||
| 198 | } | ||
| 199 | if (false == arg_matched) { | ||
| 200 | goto next; | ||
| 201 | } | ||
| 202 | } | ||
| 203 | |||
| 204 | /* Everything matched.*/ | ||
| 205 | |||
| 206 | if (true == config_node->allow) { | ||
| 207 | goto allow; | ||
| 208 | } | ||
| 209 | |||
| 210 | sp_log_disable(complete_path_function, arg_name, arg_value_str, | ||
| 211 | config_node); | ||
| 212 | if (true == config_node->simulation) { | ||
| 213 | goto next; | ||
| 214 | } else { // We've got a match, the function won't be executed | ||
| 215 | efree(complete_path_function); | ||
| 216 | return true; | ||
| 217 | } | ||
| 218 | next: | ||
| 219 | config = config->next; | ||
| 220 | } | ||
| 221 | allow: | ||
| 222 | efree(complete_path_function); | ||
| 223 | return false; | ||
| 224 | } | ||
| 225 | |||
| 226 | static bool should_drop_on_ret(zval* return_value, | ||
| 227 | const zend_execute_data* const execute_data) { | ||
| 228 | const sp_node_t* config = | ||
| 229 | SNUFFLEUPAGUS_G(config).config_disabled_functions_ret->disabled_functions; | ||
| 230 | char* complete_path_function = get_complete_function_path(execute_data); | ||
| 231 | const char* current_filename = zend_get_executed_filename(TSRMLS_C); | ||
| 232 | |||
| 233 | if (!config || !config->data) { | ||
| 234 | return false; | ||
| 235 | } | ||
| 236 | |||
| 237 | while (config) { | ||
| 238 | char* ret_value_str = NULL; | ||
| 239 | sp_disabled_function const* const config_node = | ||
| 240 | (sp_disabled_function*)(config->data); | ||
| 241 | |||
| 242 | if (false == config_node->enable) { | ||
| 243 | goto next; | ||
| 244 | } | ||
| 245 | |||
| 246 | if (config_node->function) { | ||
| 247 | if (0 != strcmp(config_node->function, complete_path_function)) { | ||
| 248 | goto next; | ||
| 249 | } | ||
| 250 | } else if (config_node->r_function) { | ||
| 251 | if (false == | ||
| 252 | is_regexp_matching(config_node->r_function, complete_path_function)) { | ||
| 253 | goto next; | ||
| 254 | } | ||
| 255 | } | ||
| 256 | |||
| 257 | if (config_node->filename) { /* Check the current file name. */ | ||
| 258 | if (0 != strcmp(current_filename, config_node->filename)) { | ||
| 259 | goto next; | ||
| 260 | } | ||
| 261 | } else if (config_node->r_filename) { | ||
| 262 | if (false == | ||
| 263 | is_regexp_matching(config_node->r_filename, current_filename)) { | ||
| 264 | goto next; | ||
| 265 | } | ||
| 266 | } | ||
| 267 | |||
| 268 | if (config_node->hash) { | ||
| 269 | if (false == is_hash_matching(current_filename, config_node)) { | ||
| 270 | goto next; | ||
| 271 | } | ||
| 272 | } | ||
| 273 | |||
| 274 | ret_value_str = sp_convert_to_string(return_value); // FIXME memleak | ||
| 275 | |||
| 276 | bool match_type = (config_node->ret_type) && | ||
| 277 | (config_node->ret_type == Z_TYPE_P(return_value)); | ||
| 278 | bool match_value = (config_node->ret || config_node->r_ret) && | ||
| 279 | (true == sp_match_value(ret_value_str, config_node->ret, | ||
| 280 | config_node->r_ret)); | ||
| 281 | |||
| 282 | if (true == match_type || match_value) { | ||
| 283 | if (true == config_node->allow) { | ||
| 284 | efree(complete_path_function); | ||
| 285 | return false; | ||
| 286 | } | ||
| 287 | sp_log_disable_ret(complete_path_function, ret_value_str, config_node); | ||
| 288 | if (false == config_node->simulation) { | ||
| 289 | efree(complete_path_function); | ||
| 290 | return true; | ||
| 291 | } | ||
| 292 | } | ||
| 293 | next: | ||
| 294 | config = config->next; | ||
| 295 | } | ||
| 296 | efree(complete_path_function); | ||
| 297 | return false; | ||
| 298 | } | ||
| 299 | |||
| 300 | ZEND_FUNCTION(check_disabled_function) { | ||
| 301 | void (*orig_handler)(INTERNAL_FUNCTION_PARAMETERS); | ||
| 302 | const char* current_function_name = get_active_function_name(TSRMLS_C); | ||
| 303 | |||
| 304 | if (true == should_disable(execute_data)) { | ||
| 305 | return; | ||
| 306 | } | ||
| 307 | |||
| 308 | if ((orig_handler = zend_hash_str_find_ptr( | ||
| 309 | SNUFFLEUPAGUS_G(disabled_functions_hook), current_function_name, | ||
| 310 | strlen(current_function_name)))) { | ||
| 311 | orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); | ||
| 312 | if (true == should_drop_on_ret(return_value, execute_data)) { | ||
| 313 | zend_bailout(); | ||
| 314 | } | ||
| 315 | } else { | ||
| 316 | sp_log_err( | ||
| 317 | "disabled_functions", | ||
| 318 | "Unable to find the pointer to the original function '%s' in the " | ||
| 319 | "hashtable.\n", | ||
| 320 | current_function_name); | ||
| 321 | } | ||
| 322 | } | ||
| 323 | |||
| 324 | static int hook_functions(const sp_node_t* config) { | ||
| 325 | while (config && config->data) { | ||
| 326 | const char* function_name = ((sp_disabled_function*)config->data)->function; | ||
| 327 | const pcre* function_name_regexp = | ||
| 328 | ((sp_disabled_function*)config->data)->r_function; | ||
| 329 | |||
| 330 | if (NULL != function_name) { // hook function by name | ||
| 331 | HOOK_FUNCTION(function_name, disabled_functions_hook, | ||
| 332 | PHP_FN(check_disabled_function), false); | ||
| 333 | } else if (NULL != function_name_regexp) { // hook function by regexp | ||
| 334 | HOOK_FUNCTION_BY_REGEXP(function_name_regexp, disabled_functions_hook, | ||
| 335 | PHP_FN(check_disabled_function), false); | ||
| 336 | } else { | ||
| 337 | return FAILURE; | ||
| 338 | } | ||
| 339 | |||
| 340 | config = config->next; | ||
| 341 | } | ||
| 342 | return SUCCESS; | ||
| 343 | } | ||
| 344 | |||
| 345 | int hook_disabled_functions(void) { | ||
| 346 | TSRMLS_FETCH(); | ||
| 347 | |||
| 348 | int ret = SUCCESS; | ||
| 349 | |||
| 350 | ret |= hook_functions( | ||
| 351 | SNUFFLEUPAGUS_G(config).config_disabled_functions->disabled_functions); | ||
| 352 | ret |= hook_functions(SNUFFLEUPAGUS_G(config) | ||
| 353 | .config_disabled_functions_ret->disabled_functions); | ||
| 354 | |||
| 355 | return ret; | ||
| 356 | } | ||
diff --git a/src/sp_disabled_functions.h b/src/sp_disabled_functions.h new file mode 100644 index 0000000..680eabb --- /dev/null +++ b/src/sp_disabled_functions.h | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | #ifndef __SP_DISABLE_FUNCTIONS_H | ||
| 2 | #define __SP_DISABLE_FUNCTIONS_H | ||
| 3 | |||
| 4 | #include "ext/hash/php_hash.h" | ||
| 5 | #include "ext/hash/php_hash_sha.h" | ||
| 6 | #include "ext/standard/md5.h" | ||
| 7 | |||
| 8 | int hook_disabled_functions(); | ||
| 9 | bool should_disable(zend_execute_data* function_name); | ||
| 10 | |||
| 11 | #endif /* __SP_DISABLE_FUNCTIONS_H */ | ||
diff --git a/src/sp_execute.c b/src/sp_execute.c new file mode 100644 index 0000000..faf126c --- /dev/null +++ b/src/sp_execute.c | |||
| @@ -0,0 +1,100 @@ | |||
| 1 | #include "php_snuffleupagus.h" | ||
| 2 | |||
| 3 | #include <errno.h> | ||
| 4 | #include <string.h> | ||
| 5 | |||
| 6 | ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus); | ||
| 7 | |||
| 8 | static void (*orig_execute_ex)(zend_execute_data *execute_data); | ||
| 9 | static int (*orig_zend_stream_open)(const char *filename, | ||
| 10 | zend_file_handle *handle); | ||
| 11 | |||
| 12 | // FIXME handle symlink | ||
| 13 | ZEND_COLD static inline void terminate_if_writable(const char *filename) { | ||
| 14 | if (0 == access(filename, W_OK)) { | ||
| 15 | if (true == SNUFFLEUPAGUS_G(config).config_readonly_exec->simulation) { | ||
| 16 | sp_log_msg("readonly_exec", LOG_NOTICE, | ||
| 17 | "Attempted execution of a writable file (%s).", filename); | ||
| 18 | } else { | ||
| 19 | sp_log_msg("readonly_exec", LOG_DROP, | ||
| 20 | "Attempted execution of a writable file (%s).", filename); | ||
| 21 | sp_terminate(); | ||
| 22 | } | ||
| 23 | } else { | ||
| 24 | if (EACCES != errno) { | ||
| 25 | sp_log_err("Writable execution", "Error while accessing %s: %s", filename, | ||
| 26 | strerror(errno)); | ||
| 27 | } | ||
| 28 | } | ||
| 29 | } | ||
| 30 | |||
| 31 | static void check_inclusion_regexp(const char * const filename) { | ||
| 32 | if (SNUFFLEUPAGUS_G(config).config_regexp_inclusion->regexp_inclusion) { | ||
| 33 | const sp_node_t* config = SNUFFLEUPAGUS_G(config).config_regexp_inclusion->regexp_inclusion; | ||
| 34 | if (!config || !config->data) { | ||
| 35 | return; | ||
| 36 | } | ||
| 37 | while (config) { | ||
| 38 | pcre *config_node = (pcre*)(config->data); | ||
| 39 | if (false == is_regexp_matching(config_node, filename)) { | ||
| 40 | sp_log_msg("include", LOG_DROP, "Inclusion of a forbidden file (%s).", filename); | ||
| 41 | sp_terminate(); | ||
| 42 | } | ||
| 43 | config = config->next; | ||
| 44 | } | ||
| 45 | } | ||
| 46 | } | ||
| 47 | |||
| 48 | static void sp_execute_ex(zend_execute_data *execute_data) { | ||
| 49 | if (NULL == execute_data->func->common.function_name) { | ||
| 50 | goto execute; | ||
| 51 | } | ||
| 52 | |||
| 53 | if (true == should_disable(execute_data)) { | ||
| 54 | return; | ||
| 55 | } | ||
| 56 | |||
| 57 | if (execute_data->func->op_array.type == ZEND_EVAL_CODE) { | ||
| 58 | sp_log_debug("Currently in an eval\n"); | ||
| 59 | } | ||
| 60 | |||
| 61 | if (NULL != execute_data->func->op_array.filename) { | ||
| 62 | if (true == SNUFFLEUPAGUS_G(config).config_readonly_exec->enable) { | ||
| 63 | terminate_if_writable(ZSTR_VAL(execute_data->func->op_array.filename)); | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | execute: | ||
| 68 | orig_execute_ex(execute_data); | ||
| 69 | } | ||
| 70 | |||
| 71 | static int sp_stream_open(const char *filename, | ||
| 72 | zend_file_handle *handle) { | ||
| 73 | const zend_execute_data *data = EG(current_execute_data); | ||
| 74 | |||
| 75 | if ((NULL != data) && (NULL != data->opline) && | ||
| 76 | (ZEND_INCLUDE_OR_EVAL == data->opline->opcode)) { | ||
| 77 | if (true == SNUFFLEUPAGUS_G(config).config_readonly_exec->enable) { | ||
| 78 | terminate_if_writable(filename); | ||
| 79 | } | ||
| 80 | check_inclusion_regexp(filename); | ||
| 81 | } | ||
| 82 | return orig_zend_stream_open(filename, handle); | ||
| 83 | } | ||
| 84 | |||
| 85 | int hook_execute(void) { | ||
| 86 | TSRMLS_FETCH(); | ||
| 87 | |||
| 88 | /* zend_execute_ex is used for "classic" function calls */ | ||
| 89 | orig_execute_ex = zend_execute_ex; | ||
| 90 | zend_execute_ex = sp_execute_ex; | ||
| 91 | |||
| 92 | /* zend_stream_open_function is used FIXME */ | ||
| 93 | orig_zend_stream_open = zend_stream_open_function; | ||
| 94 | zend_stream_open_function = sp_stream_open; | ||
| 95 | |||
| 96 | /* zend_execute_internal is used for "indirect" functions call, | ||
| 97 | * like array_map or call_user_func. */ | ||
| 98 | |||
| 99 | return SUCCESS; | ||
| 100 | } | ||
diff --git a/src/sp_execute.h b/src/sp_execute.h new file mode 100644 index 0000000..8345736 --- /dev/null +++ b/src/sp_execute.h | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | #ifndef SP_EXECUTE_H | ||
| 2 | #define SP_EXECUTE_H | ||
| 3 | |||
| 4 | int hook_execute(void); | ||
| 5 | |||
| 6 | #endif /* SP_EXECUTE_H */ | ||
diff --git a/src/sp_harden_rand.c b/src/sp_harden_rand.c new file mode 100644 index 0000000..e0e35ff --- /dev/null +++ b/src/sp_harden_rand.c | |||
| @@ -0,0 +1,77 @@ | |||
| 1 | #include "php_snuffleupagus.h" | ||
| 2 | |||
| 3 | extern ZEND_API zend_class_entry *zend_ce_error; | ||
| 4 | |||
| 5 | ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus) | ||
| 6 | |||
| 7 | /* This function is needed because `rand` and `mt_rand` parameters | ||
| 8 | * are optional, while the ones from `random_int` aren't. */ | ||
| 9 | static void random_int_wrapper(INTERNAL_FUNCTION_PARAMETERS) { | ||
| 10 | zend_long min, max, result; | ||
| 11 | |||
| 12 | switch (EX_NUM_ARGS()) { | ||
| 13 | case 0: | ||
| 14 | min = 0; | ||
| 15 | max = PHP_MT_RAND_MAX; | ||
| 16 | break; | ||
| 17 | case 1: | ||
| 18 | ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_QUIET, 1, 1); | ||
| 19 | Z_PARAM_LONG(min); | ||
| 20 | ZEND_PARSE_PARAMETERS_END(); | ||
| 21 | max = PHP_MT_RAND_MAX; | ||
| 22 | break; | ||
| 23 | case 2: | ||
| 24 | default: | ||
| 25 | ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_QUIET, 0, 2); | ||
| 26 | Z_PARAM_LONG(min); | ||
| 27 | Z_PARAM_LONG(max); | ||
| 28 | ZEND_PARSE_PARAMETERS_END(); | ||
| 29 | } | ||
| 30 | |||
| 31 | if (min > max) { | ||
| 32 | if (php_random_int_throw(max, min, &result) == FAILURE) { | ||
| 33 | return; | ||
| 34 | } | ||
| 35 | } else { | ||
| 36 | if (php_random_int_throw(min, max, &result) == FAILURE) { | ||
| 37 | return; | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | RETURN_LONG(result); | ||
| 42 | } | ||
| 43 | |||
| 44 | PHP_FUNCTION(sp_rand) { | ||
| 45 | void (*orig_handler)(INTERNAL_FUNCTION_PARAMETERS); | ||
| 46 | |||
| 47 | if ((orig_handler = zend_hash_str_find_ptr(SNUFFLEUPAGUS_G(sp_internal_functions_hook), "rand", | ||
| 48 | strlen("rand")))) { | ||
| 49 | /* call the original `rand` function, | ||
| 50 | * since we might no be the only ones to hook it*/ | ||
| 51 | orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); | ||
| 52 | } | ||
| 53 | |||
| 54 | random_int_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU); | ||
| 55 | } | ||
| 56 | |||
| 57 | PHP_FUNCTION(sp_mt_rand) { | ||
| 58 | void (*orig_handler)(INTERNAL_FUNCTION_PARAMETERS); | ||
| 59 | |||
| 60 | if ((orig_handler = zend_hash_str_find_ptr(SNUFFLEUPAGUS_G(sp_internal_functions_hook), | ||
| 61 | "mt_rand", strlen("mt_rand")))) { | ||
| 62 | /* call the original `mt_rand` function, | ||
| 63 | * since we might no be the only ones to hook it*/ | ||
| 64 | orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); | ||
| 65 | } | ||
| 66 | |||
| 67 | random_int_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU); | ||
| 68 | } | ||
| 69 | |||
| 70 | int hook_rand() { | ||
| 71 | TSRMLS_FETCH(); | ||
| 72 | |||
| 73 | HOOK_FUNCTION("rand", sp_internal_functions_hook, PHP_FN(sp_rand), false); | ||
| 74 | HOOK_FUNCTION("mt_rand", sp_internal_functions_hook, PHP_FN(sp_mt_rand), false); | ||
| 75 | |||
| 76 | return SUCCESS; | ||
| 77 | } | ||
diff --git a/src/sp_harden_rand.h b/src/sp_harden_rand.h new file mode 100644 index 0000000..53ebdd0 --- /dev/null +++ b/src/sp_harden_rand.h | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | #ifndef __SP_HARDEN_RAND_H | ||
| 2 | #define __SP_HARDEN_RAND_H | ||
| 3 | |||
| 4 | #include "ext/standard/php_rand.h" | ||
| 5 | #include "ext/standard/php_random.h" | ||
| 6 | #include "zend_exceptions.h" | ||
| 7 | |||
| 8 | int hook_rand(); | ||
| 9 | |||
| 10 | #endif /* __SP_HARDEN_RAND_H */ | ||
diff --git a/src/sp_list.c b/src/sp_list.c new file mode 100644 index 0000000..04154b7 --- /dev/null +++ b/src/sp_list.c | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | #include "sp_list.h" | ||
| 2 | #include <stdio.h> | ||
| 3 | #include <stdlib.h> | ||
| 4 | #include "php_snuffleupagus.h" | ||
| 5 | |||
| 6 | void sp_list_free(sp_node_t *node) { | ||
| 7 | while(node) { | ||
| 8 | sp_node_t *tmp = node->next; | ||
| 9 | pefree(node, 1); | ||
| 10 | node = tmp; | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | sp_node_t *sp_new_list() { | ||
| 15 | sp_node_t *new = pecalloc(sizeof(*new), 1, 1); | ||
| 16 | new->next = new->data = new->head = NULL; | ||
| 17 | return new; | ||
| 18 | } | ||
| 19 | |||
| 20 | void sp_list_insert(sp_node_t *list, void *data) { | ||
| 21 | if (list->head == NULL) { | ||
| 22 | list->data = data; | ||
| 23 | list->next = NULL; | ||
| 24 | list->head = list; | ||
| 25 | } else { | ||
| 26 | sp_node_t *new = pecalloc(sizeof(*new), 1, 1); | ||
| 27 | |||
| 28 | new->data = data; | ||
| 29 | new->next = NULL; | ||
| 30 | new->head = list; | ||
| 31 | |||
| 32 | while (list->next) { | ||
| 33 | list = list->next; | ||
| 34 | } | ||
| 35 | list->next = new; | ||
| 36 | } | ||
| 37 | } | ||
diff --git a/src/sp_list.h b/src/sp_list.h new file mode 100644 index 0000000..48b11f6 --- /dev/null +++ b/src/sp_list.h | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | #ifndef SP_LIST_H | ||
| 2 | #define SP_LIST_H | ||
| 3 | |||
| 4 | typedef struct sp_node_s { | ||
| 5 | struct sp_node_s *next; | ||
| 6 | struct sp_node_s *head; | ||
| 7 | void *data; | ||
| 8 | |||
| 9 | } sp_node_t; | ||
| 10 | |||
| 11 | sp_node_t *sp_new_list(); | ||
| 12 | void sp_list_insert(sp_node_t *, void *); | ||
| 13 | void sp_list_free(sp_node_t *); | ||
| 14 | |||
| 15 | #endif | ||
diff --git a/src/sp_network_utils.c b/src/sp_network_utils.c new file mode 100644 index 0000000..28bc324 --- /dev/null +++ b/src/sp_network_utils.c | |||
| @@ -0,0 +1,159 @@ | |||
| 1 | #include <arpa/inet.h> | ||
| 2 | #include <netinet/in.h> | ||
| 3 | #include <sys/socket.h> | ||
| 4 | |||
| 5 | #include "php_snuffleupagus.h" | ||
| 6 | |||
| 7 | ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus) | ||
| 8 | |||
| 9 | static inline bool cidr4_match(const struct in_addr addr, | ||
| 10 | const struct in_addr net, uint8_t bits); | ||
| 11 | static inline bool cidr6_match(const struct in6_addr address, | ||
| 12 | const struct in6_addr network, uint8_t bits); | ||
| 13 | static inline int get_ip_version(const char *ip); | ||
| 14 | |||
| 15 | void apply_mask_on_ip(char *out, const char *const remote_addr) { | ||
| 16 | uint8_t mask4 = SNUFFLEUPAGUS_G(config).config_cookie_encryption->mask_ipv4; | ||
| 17 | uint8_t mask6 = SNUFFLEUPAGUS_G(config).config_cookie_encryption->mask_ipv6; | ||
| 18 | const int ip_version = get_ip_version(remote_addr); | ||
| 19 | |||
| 20 | memset(out, 0, 128); | ||
| 21 | |||
| 22 | if (ip_version == AF_INET) { | ||
| 23 | struct in_addr out4; | ||
| 24 | inet_pton(AF_INET, remote_addr, &out4); | ||
| 25 | const long n = out4.s_addr & htonl(0xFFFFFFFFu << (32 - mask4)); | ||
| 26 | out[0] = (n >> 24) & 0xFF; | ||
| 27 | out[1] = (n >> 16) & 0xFF; | ||
| 28 | out[2] = (n >> 8) & 0xFF; | ||
| 29 | out[3] = (n >> 0) & 0xFF; | ||
| 30 | } else if (ip_version == AF_INET6) { | ||
| 31 | inet_pton(AF_INET6, remote_addr, out); | ||
| 32 | uint32_t *p_ip = (uint32_t *)out; | ||
| 33 | while (32 < mask6) { | ||
| 34 | *p_ip = 0xFFFFFFFFu; | ||
| 35 | p_ip++; | ||
| 36 | mask6 -= 32; | ||
| 37 | } | ||
| 38 | if (0 != mask6) { | ||
| 39 | *p_ip = htonl(0xFFFFFFFFu << (32 - mask6)); | ||
| 40 | } | ||
| 41 | } else { | ||
| 42 | sp_log_err("ip_mask", "It seems that %s isn't a valid ip.", remote_addr); | ||
| 43 | } | ||
| 44 | } | ||
| 45 | |||
| 46 | /* http://fxr.watson.org/fxr/source/include/net/xfrm.h?v=linux-2.6#L840 */ | ||
| 47 | static inline bool cidr4_match(const struct in_addr addr, | ||
| 48 | const struct in_addr net, uint8_t bits) { | ||
| 49 | if (bits == 0) { // C99 6.5.7 (3): u32 << 32 is undefined behaviour | ||
| 50 | return true; | ||
| 51 | } | ||
| 52 | return !((addr.s_addr ^ net.s_addr) & htonl(0xFFFFFFFFu << (32 - bits))); | ||
| 53 | } | ||
| 54 | |||
| 55 | static inline bool cidr6_match(const struct in6_addr address, | ||
| 56 | const struct in6_addr network, uint8_t bits) { | ||
| 57 | //#ifdef LINUX | ||
| 58 | const uint32_t *a = address.s6_addr32; | ||
| 59 | const uint32_t *n = network.s6_addr32; | ||
| 60 | /* | ||
| 61 | #else | ||
| 62 | const uint32_t *a = address.__u6_addr.__u6_addr32; | ||
| 63 | const uint32_t *n = network.__u6_addr.__u6_addr32; | ||
| 64 | #endif | ||
| 65 | */ | ||
| 66 | int bits_whole, bits_incomplete; | ||
| 67 | bits_whole = bits >> 5; // number of whole u32 | ||
| 68 | bits_incomplete = bits & 0x1F; // number of bits in incomplete u32 | ||
| 69 | if (bits_whole) { | ||
| 70 | if (memcmp(a, n, bits_whole << 2)) { | ||
| 71 | return false; | ||
| 72 | } | ||
| 73 | } | ||
| 74 | if (bits_incomplete) { | ||
| 75 | uint32_t mask = htonl((0xFFFFFFFFu) << (32 - bits_incomplete)); | ||
| 76 | if ((a[bits_whole] ^ n[bits_whole]) & mask) { | ||
| 77 | return false; | ||
| 78 | } | ||
| 79 | } | ||
| 80 | return true; | ||
| 81 | } | ||
| 82 | |||
| 83 | static inline int get_ip_version(const char *ip) { | ||
| 84 | struct in_addr out4; | ||
| 85 | struct in6_addr out6; | ||
| 86 | int res = inet_pton(AF_INET, ip, &out4); | ||
| 87 | if (0 == res) { | ||
| 88 | if (1 == inet_pton(AF_INET6, ip, &out6)) { | ||
| 89 | return AF_INET6; | ||
| 90 | } else { | ||
| 91 | return -1; | ||
| 92 | } | ||
| 93 | } else if (1 == res) { | ||
| 94 | return AF_INET; | ||
| 95 | } else { | ||
| 96 | return -1; | ||
| 97 | } | ||
| 98 | } | ||
| 99 | |||
| 100 | // TODO factorise a bit this function | ||
| 101 | bool cidr_match(const char *ip, const sp_cidr *cidr) { | ||
| 102 | struct in_addr out4; | ||
| 103 | struct in6_addr out6; | ||
| 104 | |||
| 105 | switch (get_ip_version(ip)) { | ||
| 106 | case AF_INET: | ||
| 107 | if (AF_INET != cidr->ip_version) { | ||
| 108 | return false; | ||
| 109 | } | ||
| 110 | inet_pton(AF_INET, ip, &out4); | ||
| 111 | return cidr4_match(out4, cidr->ip.ipv4, cidr->mask); | ||
| 112 | case AF_INET6: | ||
| 113 | if (AF_INET6 != cidr->ip_version) { | ||
| 114 | return false; | ||
| 115 | } | ||
| 116 | inet_pton(AF_INET6, ip, &out6); | ||
| 117 | return cidr6_match(out6, cidr->ip.ipv6, cidr->mask); | ||
| 118 | default: | ||
| 119 | sp_log_err("cidr_match", "Weird ip (%s) family", ip); | ||
| 120 | break; | ||
| 121 | } | ||
| 122 | return false; | ||
| 123 | } | ||
| 124 | |||
| 125 | int get_ip_and_cidr(char *ip, sp_cidr *cidr) { | ||
| 126 | errno = 0; | ||
| 127 | char *mask = strchr(ip, '/'); | ||
| 128 | |||
| 129 | if (NULL == mask) { | ||
| 130 | sp_log_err("config", | ||
| 131 | "'%s' isn't a valid network mask, it seems that you forgot a '/'.", | ||
| 132 | ip); | ||
| 133 | return -1; | ||
| 134 | } | ||
| 135 | |||
| 136 | if (sscanf(mask + 1, "%hhu", &(cidr->mask)) != 1) { | ||
| 137 | sp_log_err("config", "'%s' isn't a valid network mask.", mask + 1); | ||
| 138 | return -1; | ||
| 139 | } | ||
| 140 | |||
| 141 | ip[mask - ip] = '\0'; // NULL the '/' char | ||
| 142 | |||
| 143 | cidr->ip_version = get_ip_version(ip); | ||
| 144 | |||
| 145 | if (AF_INET == cidr->ip_version) { | ||
| 146 | if (cidr->mask > 32) { | ||
| 147 | sp_log_err("config", "'%d' isn't a valid ipv4 mask.", cidr->mask); | ||
| 148 | return -1; | ||
| 149 | } | ||
| 150 | inet_pton(AF_INET, ip, &(cidr->ip.ipv4)); | ||
| 151 | } else if (AF_INET6 == cidr->ip_version) { | ||
| 152 | inet_pton(AF_INET6, ip, &(cidr->ip.ipv6)); | ||
| 153 | } else { | ||
| 154 | return -1; | ||
| 155 | } | ||
| 156 | |||
| 157 | ip[mask - ip] = '/'; | ||
| 158 | return 0; | ||
| 159 | } | ||
diff --git a/src/sp_network_utils.h b/src/sp_network_utils.h new file mode 100644 index 0000000..6b6ce92 --- /dev/null +++ b/src/sp_network_utils.h | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | #ifndef SP_NETWORK_UTILS_H | ||
| 2 | #define SP_NETWORK_UTILS_H | ||
| 3 | |||
| 4 | int get_ip_and_cidr(char *, sp_cidr *); | ||
| 5 | bool cidr_match(const char *, const sp_cidr *); | ||
| 6 | void apply_mask_on_ip(char *, const char * const); | ||
| 7 | |||
| 8 | #endif /*SP_NETWORK_UTILS_H*/ | ||
diff --git a/src/sp_unserialize.c b/src/sp_unserialize.c new file mode 100644 index 0000000..b5b67b4 --- /dev/null +++ b/src/sp_unserialize.c | |||
| @@ -0,0 +1,111 @@ | |||
| 1 | #include "php_snuffleupagus.h" | ||
| 2 | |||
| 3 | ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus) | ||
| 4 | |||
| 5 | PHP_FUNCTION(sp_serialize) { | ||
| 6 | void (*orig_handler)(INTERNAL_FUNCTION_PARAMETERS); | ||
| 7 | |||
| 8 | /* Call the original `serialize` function. */ | ||
| 9 | if ((orig_handler = zend_hash_str_find_ptr(SNUFFLEUPAGUS_G(sp_internal_functions_hook), | ||
| 10 | "serialize", 9))) { | ||
| 11 | orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); | ||
| 12 | } else { | ||
| 13 | sp_log_err("disabled_functions", | ||
| 14 | "Unable to find the pointer to the original function 'serialize' in " | ||
| 15 | "the hashtable.\n"); | ||
| 16 | } | ||
| 17 | |||
| 18 | /* Compute the HMAC of the textual representation of the serialized data*/ | ||
| 19 | zval func_name; | ||
| 20 | zval hmac; | ||
| 21 | zval params[3]; | ||
| 22 | |||
| 23 | ZVAL_STRING(&func_name, "hash_hmac"); | ||
| 24 | ZVAL_STRING(¶ms[0], "sha256"); | ||
| 25 | params[1] = *return_value; | ||
| 26 | ZVAL_STRING(¶ms[2], | ||
| 27 | SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key); | ||
| 28 | call_user_function(CG(function_table), NULL, &func_name, &hmac, 3, params); | ||
| 29 | |||
| 30 | size_t len = Z_STRLEN_P(return_value) + Z_STRLEN(hmac); | ||
| 31 | zend_string *res = zend_string_alloc(len, 0); | ||
| 32 | |||
| 33 | memcpy(ZSTR_VAL(res), Z_STRVAL_P(return_value), Z_STRLEN_P(return_value)); | ||
| 34 | memcpy(ZSTR_VAL(res) + Z_STRLEN_P(return_value), Z_STRVAL(hmac), | ||
| 35 | Z_STRLEN(hmac)); | ||
| 36 | ZSTR_VAL(res)[len] = '\0'; | ||
| 37 | |||
| 38 | /* Append the computed HMAC to the serialized data. */ | ||
| 39 | return_value->value.str = res; | ||
| 40 | return; | ||
| 41 | } | ||
| 42 | |||
| 43 | PHP_FUNCTION(sp_unserialize) { | ||
| 44 | void (*orig_handler)(INTERNAL_FUNCTION_PARAMETERS); | ||
| 45 | |||
| 46 | char *buf = NULL; | ||
| 47 | char *serialized_str = NULL; | ||
| 48 | char *hmac = NULL; | ||
| 49 | zval expected_hmac; | ||
| 50 | size_t buf_len = 0; | ||
| 51 | zval *opts = NULL; | ||
| 52 | |||
| 53 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|a", &buf, &buf_len, &opts) == | ||
| 54 | FAILURE) { | ||
| 55 | RETURN_FALSE; | ||
| 56 | } | ||
| 57 | |||
| 58 | /* 64 is the length of HMAC-256 */ | ||
| 59 | if (buf_len < 64) { | ||
| 60 | sp_log_msg("unserialize", LOG_DROP, "The serialized object is too small."); | ||
| 61 | RETURN_FALSE; | ||
| 62 | } | ||
| 63 | |||
| 64 | hmac = buf + buf_len - 64; | ||
| 65 | serialized_str = ecalloc(sizeof(*serialized_str) * (buf_len - 64 + 1), 1); | ||
| 66 | memcpy(serialized_str, buf, buf_len - 64); | ||
| 67 | |||
| 68 | zval func_name; | ||
| 69 | ZVAL_STRING(&func_name, "hash_hmac"); | ||
| 70 | |||
| 71 | zval params[3]; | ||
| 72 | ZVAL_STRING(¶ms[0], "sha256"); | ||
| 73 | ZVAL_STRING(¶ms[1], serialized_str); | ||
| 74 | ZVAL_STRING(¶ms[2], | ||
| 75 | SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key); | ||
| 76 | call_user_function(CG(function_table), NULL, &func_name, &expected_hmac, 3, | ||
| 77 | params); | ||
| 78 | |||
| 79 | unsigned int status = 0; | ||
| 80 | for (uint8_t i = 0; i < 64; i++) { | ||
| 81 | status |= (hmac[i] ^ (Z_STRVAL(expected_hmac))[i]); | ||
| 82 | } | ||
| 83 | |||
| 84 | if (0 == status) { | ||
| 85 | if ((orig_handler = zend_hash_str_find_ptr(SNUFFLEUPAGUS_G(sp_internal_functions_hook), | ||
| 86 | "unserialize", 11))) { | ||
| 87 | orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); | ||
| 88 | } | ||
| 89 | } else { | ||
| 90 | if ( true == SNUFFLEUPAGUS_G(config).config_unserialize->simulation) { | ||
| 91 | sp_log_msg("unserialize", LOG_NOTICE, "Invalid HMAC for %s", serialized_str); | ||
| 92 | if ((orig_handler = zend_hash_str_find_ptr(SNUFFLEUPAGUS_G(sp_internal_functions_hook), | ||
| 93 | "unserialize", 11))) { | ||
| 94 | orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); | ||
| 95 | } | ||
| 96 | } else { | ||
| 97 | sp_log_msg("unserialize", LOG_DROP, "Invalid HMAC for %s", serialized_str); | ||
| 98 | } | ||
| 99 | } | ||
| 100 | efree(serialized_str); | ||
| 101 | return; | ||
| 102 | } | ||
| 103 | |||
| 104 | int hook_serialize(void) { | ||
| 105 | TSRMLS_FETCH(); | ||
| 106 | |||
| 107 | HOOK_FUNCTION("serialize", sp_internal_functions_hook, PHP_FN(sp_serialize), false); | ||
| 108 | HOOK_FUNCTION("unserialize", sp_internal_functions_hook, PHP_FN(sp_unserialize), false); | ||
| 109 | |||
| 110 | return SUCCESS; | ||
| 111 | } | ||
diff --git a/src/sp_unserialize.h b/src/sp_unserialize.h new file mode 100644 index 0000000..557c60c --- /dev/null +++ b/src/sp_unserialize.h | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | #ifndef SP_UNSERIALIZE_H | ||
| 2 | #define SP_UNSERIALIZE_H | ||
| 3 | |||
| 4 | int hook_serialize(void); | ||
| 5 | |||
| 6 | PHP_FUNCTION(sp_serialize); | ||
| 7 | PHP_FUNCTION(sp_unserialize); | ||
| 8 | |||
| 9 | #endif /* SP_UNSERIALIZE_H */ | ||
diff --git a/src/sp_upload_validation.c b/src/sp_upload_validation.c new file mode 100644 index 0000000..bbd7eae --- /dev/null +++ b/src/sp_upload_validation.c | |||
| @@ -0,0 +1,92 @@ | |||
| 1 | #include "php_snuffleupagus.h" | ||
| 2 | #include "rfc1867.h" | ||
| 3 | |||
| 4 | ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus); | ||
| 5 | |||
| 6 | #define EFREE_3(env) \ | ||
| 7 | for (size_t i = 0; i < 4; i++) { \ | ||
| 8 | efree(env[i]); \ | ||
| 9 | } | ||
| 10 | |||
| 11 | void hook_upload() { | ||
| 12 | sp_rfc1867_orig_callback = php_rfc1867_callback; | ||
| 13 | php_rfc1867_callback = sp_rfc1867_callback; | ||
| 14 | } | ||
| 15 | |||
| 16 | int sp_rfc1867_callback(unsigned int event, void *event_data, void **extra) { | ||
| 17 | int retval = SUCCESS; | ||
| 18 | |||
| 19 | if (sp_rfc1867_orig_callback) { | ||
| 20 | retval = sp_rfc1867_orig_callback(event, event_data, extra); | ||
| 21 | } | ||
| 22 | |||
| 23 | if (event == MULTIPART_EVENT_END) { | ||
| 24 | zend_string *file_key __attribute__((unused)) = NULL; | ||
| 25 | zval *file; | ||
| 26 | pid_t pid; | ||
| 27 | |||
| 28 | sp_log_debug( | ||
| 29 | "Got %d files", | ||
| 30 | zend_hash_num_elements(Z_ARRVAL(PG(http_globals)[TRACK_VARS_FILES]))); | ||
| 31 | |||
| 32 | ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL(PG(http_globals)[TRACK_VARS_FILES]), | ||
| 33 | file_key, file) { // for each uploaded file | ||
| 34 | |||
| 35 | char *filename = | ||
| 36 | Z_STRVAL_P(zend_hash_str_find(Z_ARRVAL_P(file), "name", 4)); | ||
| 37 | char *tmp_name = | ||
| 38 | Z_STRVAL_P(zend_hash_str_find(Z_ARRVAL_P(file), "tmp_name", 8)); | ||
| 39 | size_t filesize = | ||
| 40 | Z_LVAL_P(zend_hash_str_find(Z_ARRVAL_P(file), "size", 4)); | ||
| 41 | char *cmd[3] = {0}; | ||
| 42 | char *env[5] = {0}; | ||
| 43 | |||
| 44 | sp_log_debug("Filename: %s\nTmpname: %s\nSize: %d\nError: %d\nScript: %s", | ||
| 45 | filename, tmp_name, filesize, | ||
| 46 | Z_LVAL_P(zend_hash_str_find(Z_ARRVAL_P(file), "error", 5)), | ||
| 47 | SNUFFLEUPAGUS_G(config).config_upload_validation->script); | ||
| 48 | |||
| 49 | cmd[0] = SNUFFLEUPAGUS_G(config).config_upload_validation->script; | ||
| 50 | cmd[1] = tmp_name; | ||
| 51 | cmd[2] = NULL; | ||
| 52 | |||
| 53 | spprintf(&env[0], 0, "SP_FILENAME=%s", filename); | ||
| 54 | spprintf(&env[1], 0, "SP_REMOTE_ADDR=%s", sp_getenv("REMOTE_ADDR")); | ||
| 55 | spprintf(&env[2], 0, "SP_CURRENT_FILE=%s", | ||
| 56 | zend_get_executed_filename(TSRMLS_C)); | ||
| 57 | spprintf(&env[3], 0, "SP_FILESIZE=%zu", filesize); | ||
| 58 | env[4] = NULL; | ||
| 59 | |||
| 60 | if ((pid = fork()) == 0) { | ||
| 61 | if (execve(SNUFFLEUPAGUS_G(config).config_upload_validation->script, | ||
| 62 | cmd, env) == -1) { | ||
| 63 | sp_log_err("upload_validation", "Could not call '%s' : %s", | ||
| 64 | SNUFFLEUPAGUS_G(config).config_upload_validation->script, | ||
| 65 | strerror(errno)); | ||
| 66 | EFREE_3(env); | ||
| 67 | exit(1); | ||
| 68 | } | ||
| 69 | } else if (pid == -1) { | ||
| 70 | sp_log_err("upload_validation", "Could not fork process : %s\n", | ||
| 71 | strerror(errno)); | ||
| 72 | EFREE_3(env); | ||
| 73 | continue; | ||
| 74 | } | ||
| 75 | |||
| 76 | EFREE_3(env); | ||
| 77 | int waitstatus; | ||
| 78 | wait(&waitstatus); | ||
| 79 | if (WEXITSTATUS(waitstatus) != 0) { // Nope | ||
| 80 | char *uri = sp_getenv("REQUEST_URI"); | ||
| 81 | int sim = SNUFFLEUPAGUS_G(config).config_upload_validation->simulation; | ||
| 82 | sp_log_msg("upload_valiation", sim?LOG_NOTICE:LOG_DROP, | ||
| 83 | "The upload of %s on %s was rejected.", filename, uri?uri:"?"); | ||
| 84 | if (!SNUFFLEUPAGUS_G(config).config_upload_validation->simulation) { | ||
| 85 | zend_bailout(); | ||
| 86 | } | ||
| 87 | } | ||
| 88 | } | ||
| 89 | ZEND_HASH_FOREACH_END(); | ||
| 90 | } | ||
| 91 | return retval; | ||
| 92 | } | ||
diff --git a/src/sp_upload_validation.h b/src/sp_upload_validation.h new file mode 100644 index 0000000..3d59527 --- /dev/null +++ b/src/sp_upload_validation.h | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | #ifndef __SP_UPLOAD_VALIDATION_H__ | ||
| 2 | #define __SP_UPLOAD_VALIDATION_H__ | ||
| 3 | |||
| 4 | void hook_upload(); | ||
| 5 | |||
| 6 | int (*sp_rfc1867_orig_callback)(unsigned int event, void *event_data, void **extra); | ||
| 7 | int sp_rfc1867_callback(unsigned int event, void *event_data, void **extra); | ||
| 8 | |||
| 9 | #endif | ||
diff --git a/src/sp_utils.c b/src/sp_utils.c new file mode 100644 index 0000000..087f431 --- /dev/null +++ b/src/sp_utils.c | |||
| @@ -0,0 +1,425 @@ | |||
| 1 | #include "php_snuffleupagus.h" | ||
| 2 | |||
| 3 | #include <fcntl.h> | ||
| 4 | #include <stdio.h> | ||
| 5 | #include <stdlib.h> | ||
| 6 | #include <string.h> | ||
| 7 | #include <unistd.h> | ||
| 8 | |||
| 9 | static inline void _sp_log_err(const char* fmt, ...) { | ||
| 10 | char* msg; | ||
| 11 | va_list args; | ||
| 12 | |||
| 13 | va_start(args, fmt); | ||
| 14 | vspprintf(&msg, 0, fmt, args); | ||
| 15 | va_end(args); | ||
| 16 | php_log_err(msg); | ||
| 17 | } | ||
| 18 | |||
| 19 | void sp_log_msg(char const *feature, char const *level, const char* fmt, ...) { | ||
| 20 | char* msg; | ||
| 21 | va_list args; | ||
| 22 | |||
| 23 | va_start(args, fmt); | ||
| 24 | vspprintf(&msg, 0, fmt, args); | ||
| 25 | va_end(args); | ||
| 26 | |||
| 27 | char const * const client_ip = sp_getenv("REMOTE_ADDR"); | ||
| 28 | _sp_log_err("[snuffleupagus][%s][%s][%s] %s", client_ip?client_ip:"0.0.0.0", | ||
| 29 | feature, level, msg); | ||
| 30 | } | ||
| 31 | |||
| 32 | int compute_hash(const char* const filename, char* file_hash) { | ||
| 33 | unsigned char buf[1024]; | ||
| 34 | unsigned char digest[SHA256_SIZE]; | ||
| 35 | PHP_SHA256_CTX context; | ||
| 36 | size_t n; | ||
| 37 | |||
| 38 | php_stream* stream = | ||
| 39 | php_stream_open_wrapper(filename, "rb", REPORT_ERRORS, NULL); | ||
| 40 | if (!stream) { | ||
| 41 | sp_log_err("hash_computation", "Can not open the file %s to compute its hash.\n", filename); | ||
| 42 | return -1; | ||
| 43 | } | ||
| 44 | |||
| 45 | PHP_SHA256Init(&context); | ||
| 46 | while ((n = php_stream_read(stream, (char*)buf, sizeof(buf))) > 0) { | ||
| 47 | PHP_SHA256Update(&context, buf, n); | ||
| 48 | } | ||
| 49 | PHP_SHA256Final(digest, &context); | ||
| 50 | php_stream_close(stream); | ||
| 51 | make_digest_ex(file_hash, digest, SHA256_SIZE); | ||
| 52 | return 0; | ||
| 53 | } | ||
| 54 | |||
| 55 | static void construct_filename(char* filename, const char* folder) { | ||
| 56 | time_t t = time(NULL); | ||
| 57 | struct tm* tm = localtime(&t); // FIXME use `localtime_r` instead | ||
| 58 | struct timeval tval; | ||
| 59 | struct stat st = {0}; | ||
| 60 | |||
| 61 | if (-1 == stat(folder, &st)) { | ||
| 62 | mkdir(folder, 0700); | ||
| 63 | } | ||
| 64 | |||
| 65 | memcpy(filename, folder, strlen(folder)); | ||
| 66 | strcat(filename, "sp_dump_"); | ||
| 67 | strftime(filename + strlen(filename), 27, "%F_%T:", tm); | ||
| 68 | gettimeofday(&tval, NULL); | ||
| 69 | sprintf(filename + strlen(filename), "%04ld", tval.tv_usec); | ||
| 70 | strcat(filename, "_"); | ||
| 71 | |||
| 72 | char* remote_addr = getenv("REMOTE_ADDR"); | ||
| 73 | if (remote_addr) { | ||
| 74 | strcat(filename, remote_addr); | ||
| 75 | } else { | ||
| 76 | strcat(filename, "0.0.0.0"); | ||
| 77 | } | ||
| 78 | strcat(filename, ".dump"); | ||
| 79 | } | ||
| 80 | |||
| 81 | int sp_log_request(const char* folder) { | ||
| 82 | FILE* file; | ||
| 83 | const char* current_filename = zend_get_executed_filename(TSRMLS_C); | ||
| 84 | const int current_line = zend_get_executed_lineno(TSRMLS_C); | ||
| 85 | char filename[MAX_FOLDER_LEN] = {0}; | ||
| 86 | const struct { | ||
| 87 | const char* str; | ||
| 88 | const int key; | ||
| 89 | } zones[] = {{"GET", TRACK_VARS_GET}, {"POST", TRACK_VARS_POST}, | ||
| 90 | {"COOKIE", TRACK_VARS_COOKIE}, {"SERVER", TRACK_VARS_SERVER}, | ||
| 91 | {"ENV", TRACK_VARS_ENV}, {NULL, 0}}; | ||
| 92 | |||
| 93 | construct_filename(filename, folder); | ||
| 94 | if (NULL == (file = fopen(filename, "a"))) { | ||
| 95 | sp_log_err("request_logging", "Unable to open %s", filename); | ||
| 96 | return -1; | ||
| 97 | } | ||
| 98 | |||
| 99 | fprintf(file, "%s:%d\n", current_filename, current_line); | ||
| 100 | for (size_t i = 0; i < (sizeof(zones) / sizeof(zones[0])) - 1; i++) { | ||
| 101 | zval* variable_value; | ||
| 102 | zend_string* variable_key; | ||
| 103 | size_t params_len = strlen(zones[i].str) + 1; | ||
| 104 | char* param; | ||
| 105 | size_t size_max = 2048; | ||
| 106 | |||
| 107 | if (Z_TYPE(PG(http_globals)[zones[i].key]) == IS_UNDEF) { | ||
| 108 | continue; | ||
| 109 | } | ||
| 110 | |||
| 111 | const HashTable* ht = Z_ARRVAL(PG(http_globals)[zones[i].key]); | ||
| 112 | |||
| 113 | // Compute the size of the allocation | ||
| 114 | ZEND_HASH_FOREACH_STR_KEY_VAL(ht, variable_key, variable_value) { | ||
| 115 | params_len += snprintf(NULL, 0, "%s=%s&", ZSTR_VAL(variable_key), | ||
| 116 | Z_STRVAL_P(variable_value)); | ||
| 117 | } | ||
| 118 | ZEND_HASH_FOREACH_END(); | ||
| 119 | |||
| 120 | params_len = params_len>size_max?size_max:params_len; | ||
| 121 | |||
| 122 | #define NCAT_AND_DEC(a, b, c) strncat(a, b, c); c -= strlen(b); | ||
| 123 | |||
| 124 | // Allocate and copy the data | ||
| 125 | // FIXME Why are we even allocating? | ||
| 126 | param = pecalloc(params_len, 1, 0); | ||
| 127 | NCAT_AND_DEC(param, zones[i].str, params_len); | ||
| 128 | NCAT_AND_DEC(param, ":", params_len); | ||
| 129 | ZEND_HASH_FOREACH_STR_KEY_VAL(ht, variable_key, variable_value) { | ||
| 130 | NCAT_AND_DEC(param, ZSTR_VAL(variable_key), params_len); | ||
| 131 | NCAT_AND_DEC(param, "=", params_len); | ||
| 132 | NCAT_AND_DEC(param, Z_STRVAL_P(variable_value), params_len); | ||
| 133 | NCAT_AND_DEC(param, "&", params_len); | ||
| 134 | } | ||
| 135 | ZEND_HASH_FOREACH_END(); | ||
| 136 | |||
| 137 | param[strlen(param) - 1] = '\0'; | ||
| 138 | |||
| 139 | fputs(param, file); | ||
| 140 | fputs("\n", file); | ||
| 141 | } | ||
| 142 | fclose(file); | ||
| 143 | |||
| 144 | #undef CAT_AND_DEC | ||
| 145 | return 0; | ||
| 146 | } | ||
| 147 | |||
| 148 | static char *zv_str_to_char(zval *zv) { | ||
| 149 | zval copy; | ||
| 150 | char *ret; | ||
| 151 | |||
| 152 | |||
| 153 | ZVAL_ZVAL(©, zv, 1, 0); | ||
| 154 | // str = zend_string_dup(Z_STR_P(zv), 0); | ||
| 155 | for (size_t i = 0; i < Z_STRLEN(copy); i++) { | ||
| 156 | if (Z_STRVAL(copy)[i] == '\0') { | ||
| 157 | Z_STRVAL(copy)[i] = '0'; | ||
| 158 | } | ||
| 159 | } | ||
| 160 | ret = estrdup(Z_STRVAL(copy)); | ||
| 161 | // zend_string_release(str); | ||
| 162 | return ret; | ||
| 163 | } | ||
| 164 | |||
| 165 | |||
| 166 | char* sp_convert_to_string(zval* zv) { | ||
| 167 | switch (Z_TYPE_P(zv)) { | ||
| 168 | case IS_FALSE: | ||
| 169 | return estrdup("FALSE"); | ||
| 170 | case IS_TRUE: | ||
| 171 | return estrdup("TRUE"); | ||
| 172 | case IS_NULL: | ||
| 173 | return estrdup("NULL"); | ||
| 174 | case IS_LONG: { | ||
| 175 | char *msg; | ||
| 176 | spprintf(&msg, 0, ZEND_LONG_FMT, Z_LVAL_P(zv)); | ||
| 177 | return msg; | ||
| 178 | } | ||
| 179 | case IS_DOUBLE: { | ||
| 180 | char *msg; | ||
| 181 | spprintf(&msg, 0, "%f", Z_DVAL_P(zv)); | ||
| 182 | return msg; | ||
| 183 | } | ||
| 184 | case IS_STRING:{ | ||
| 185 | return zv_str_to_char(zv); | ||
| 186 | } | ||
| 187 | case IS_OBJECT: | ||
| 188 | return estrdup("OBJECT"); | ||
| 189 | case IS_ARRAY: | ||
| 190 | return estrdup("ARRAY"); | ||
| 191 | case IS_RESOURCE: | ||
| 192 | return estrdup("RESOURCE"); | ||
| 193 | } | ||
| 194 | return estrdup(""); | ||
| 195 | } | ||
| 196 | |||
| 197 | bool sp_match_value(const char* value, const char* to_match, const pcre* rx) { | ||
| 198 | if (to_match) { | ||
| 199 | if (0 == strcmp(value, to_match)) { | ||
| 200 | return true; | ||
| 201 | } | ||
| 202 | } else if (rx) { | ||
| 203 | int substrvec[30]; | ||
| 204 | int ret = pcre_exec(rx, NULL, value, strlen(value), 0, 0, substrvec, 30); | ||
| 205 | |||
| 206 | if (ret < 0) { | ||
| 207 | if (ret != PCRE_ERROR_NOMATCH) { | ||
| 208 | sp_log_err("regexp", "Something went wrong with a regexp."); | ||
| 209 | return false; | ||
| 210 | } | ||
| 211 | return false; | ||
| 212 | } | ||
| 213 | return true; | ||
| 214 | } | ||
| 215 | return false; | ||
| 216 | } | ||
| 217 | |||
| 218 | void sp_log_disable(const char* restrict path, const char* restrict arg_name, | ||
| 219 | const char* restrict arg_value, | ||
| 220 | const sp_disabled_function* config_node) { | ||
| 221 | const char* dump = config_node->dump; | ||
| 222 | const char* alias = config_node->alias; | ||
| 223 | const int sim = config_node->simulation; | ||
| 224 | if (arg_name) { | ||
| 225 | if (alias) { | ||
| 226 | sp_log_msg("disabled_function", sim?LOG_NOTICE:LOG_DROP, | ||
| 227 | "The call to the function '%s' in %s:%d has been disabled, " | ||
| 228 | "because its argument '%s' content (%s) matched the rule '%s'.", | ||
| 229 | path, zend_get_executed_filename(TSRMLS_C), | ||
| 230 | zend_get_executed_lineno(TSRMLS_C), arg_name, arg_value?arg_value:"?", | ||
| 231 | alias); | ||
| 232 | } else { | ||
| 233 | sp_log_msg("disabled_function", sim?LOG_NOTICE:LOG_DROP, | ||
| 234 | "The call to the function '%s' in %s:%d has been disabled, " | ||
| 235 | "because its argument '%s' content (%s) matched a rule.", | ||
| 236 | path, zend_get_executed_filename(TSRMLS_C), | ||
| 237 | zend_get_executed_lineno(TSRMLS_C), arg_name, | ||
| 238 | arg_value?arg_value:"?"); | ||
| 239 | } | ||
| 240 | } else { | ||
| 241 | if (alias) { | ||
| 242 | sp_log_msg("disabled_function", sim?LOG_NOTICE:LOG_DROP, | ||
| 243 | "The call to the function '%s' in %s:%d has been disabled, " | ||
| 244 | "because of the the rule '%s'.",path, | ||
| 245 | zend_get_executed_filename(TSRMLS_C), | ||
| 246 | zend_get_executed_lineno(TSRMLS_C), alias); | ||
| 247 | } else { | ||
| 248 | sp_log_msg("disabled_function", sim?LOG_NOTICE:LOG_DROP, | ||
| 249 | "The call to the function '%s' in %s:%d has been disabled.", | ||
| 250 | path, zend_get_executed_filename(TSRMLS_C), | ||
| 251 | zend_get_executed_lineno(TSRMLS_C)); | ||
| 252 | } | ||
| 253 | } | ||
| 254 | if (dump) { | ||
| 255 | sp_log_request(config_node->dump); | ||
| 256 | } | ||
| 257 | } | ||
| 258 | |||
| 259 | void sp_log_disable_ret(const char* restrict path, | ||
| 260 | const char* restrict ret_value, | ||
| 261 | const sp_disabled_function* config_node) { | ||
| 262 | const char* dump = config_node->dump; | ||
| 263 | const char* alias = config_node->alias; | ||
| 264 | const int sim = config_node->simulation; | ||
| 265 | if (alias) { | ||
| 266 | sp_log_msg("disabled_function", sim?LOG_NOTICE:LOG_DROP, | ||
| 267 | "The execution has been aborted in %s:%d, " | ||
| 268 | "because the function '%s' returned '%s', which matched the rule '%s'.", | ||
| 269 | zend_get_executed_filename(TSRMLS_C), | ||
| 270 | zend_get_executed_lineno(TSRMLS_C), path, ret_value?ret_value:"?", alias); | ||
| 271 | } else { | ||
| 272 | sp_log_msg("disabled_function", sim?LOG_NOTICE:LOG_DROP, | ||
| 273 | "The execution has been aborted in %s:%d, " | ||
| 274 | "because the return value (%s) of the function '%s' matched a rule.", | ||
| 275 | zend_get_executed_filename(TSRMLS_C), | ||
| 276 | zend_get_executed_lineno(TSRMLS_C), ret_value?ret_value:"?", path); | ||
| 277 | } | ||
| 278 | if (dump) { | ||
| 279 | sp_log_request(dump); | ||
| 280 | } | ||
| 281 | } | ||
| 282 | |||
| 283 | int sp_match_array_key(const zval* zv, const char* to_match, const pcre* rx) { | ||
| 284 | zend_string* key; | ||
| 285 | zval* value; | ||
| 286 | char* arg_value_str; | ||
| 287 | |||
| 288 | ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(zv), key, value) { | ||
| 289 | if (Z_TYPE_P(value) == IS_ARRAY) { | ||
| 290 | continue; | ||
| 291 | } | ||
| 292 | arg_value_str = sp_convert_to_string(value); | ||
| 293 | if (!sp_match_value(arg_value_str, to_match, rx)) { | ||
| 294 | efree(arg_value_str); | ||
| 295 | continue; | ||
| 296 | } else { | ||
| 297 | efree(arg_value_str); | ||
| 298 | return 1; | ||
| 299 | } | ||
| 300 | } | ||
| 301 | ZEND_HASH_FOREACH_END(); | ||
| 302 | |||
| 303 | (void)key; // silence a compiler warning | ||
| 304 | |||
| 305 | return 0; | ||
| 306 | } | ||
| 307 | |||
| 308 | int sp_match_array_key_recurse(const zval* arr, sp_node_t* keys, | ||
| 309 | const char* to_match, const pcre* rx) { | ||
| 310 | zend_string* key; | ||
| 311 | zval* value; | ||
| 312 | sp_node_t* current = keys; | ||
| 313 | if (current == NULL) { | ||
| 314 | return 0; | ||
| 315 | } | ||
| 316 | ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(arr), key, value) { | ||
| 317 | if (Z_TYPE_P(value) == IS_ARRAY && !strcmp(ZSTR_VAL(key), current->data)) { | ||
| 318 | return sp_match_array_key_recurse(value, current->next, to_match, rx); | ||
| 319 | } | ||
| 320 | if (!strcmp(ZSTR_VAL(key), current->data) && current->next == NULL) { | ||
| 321 | if (!to_match && !rx) { | ||
| 322 | return 1; | ||
| 323 | } | ||
| 324 | if (Z_TYPE_P(value) == IS_ARRAY) { | ||
| 325 | return sp_match_array_key(value, to_match, rx); | ||
| 326 | } else { | ||
| 327 | char *value_str = sp_convert_to_string(value); | ||
| 328 | if (sp_match_value(value_str, to_match, rx)) { | ||
| 329 | efree(value_str); | ||
| 330 | return 1; | ||
| 331 | } else { | ||
| 332 | efree (value_str); | ||
| 333 | return 0; | ||
| 334 | } | ||
| 335 | } | ||
| 336 | } | ||
| 337 | } | ||
| 338 | ZEND_HASH_FOREACH_END(); | ||
| 339 | return 0; | ||
| 340 | } | ||
| 341 | |||
| 342 | zend_always_inline char* sp_getenv(char* var) { | ||
| 343 | if (sapi_module.getenv) { | ||
| 344 | return sapi_module.getenv(ZEND_STRL(var)); | ||
| 345 | } else { | ||
| 346 | return getenv(var); | ||
| 347 | } | ||
| 348 | } | ||
| 349 | |||
| 350 | zend_always_inline int is_regexp_matching(const pcre* regexp, const char* str) { | ||
| 351 | int vec[30]; | ||
| 352 | int ret = pcre_exec(regexp, NULL, str, strlen(str), 0, 0, vec, sizeof(vec)); | ||
| 353 | if (ret < 0) { | ||
| 354 | if (ret != PCRE_ERROR_NOMATCH) { | ||
| 355 | sp_log_err("regexp", "Something went wrong with a regexp."); | ||
| 356 | } | ||
| 357 | return false; | ||
| 358 | } | ||
| 359 | return true; | ||
| 360 | } | ||
| 361 | |||
| 362 | int hook_function(const char* original_name, HashTable* hook_table, | ||
| 363 | void (*new_function)(INTERNAL_FUNCTION_PARAMETERS), | ||
| 364 | bool hook_execution_table) { | ||
| 365 | zend_internal_function* func; | ||
| 366 | HashTable *ht = hook_execution_table==true?EG(function_table):CG(function_table); | ||
| 367 | |||
| 368 | /* The `mb` module likes to hook functions, like strlen->mb_strlen, | ||
| 369 | * so we have to hook both of them. */ | ||
| 370 | if (0 == strncmp(original_name, "mb_", 3)) { | ||
| 371 | CG(compiler_options) |= ZEND_COMPILE_NO_BUILTIN_STRLEN; | ||
| 372 | if (zend_hash_str_find(ht, | ||
| 373 | VAR_AND_LEN(original_name + 3))) { | ||
| 374 | hook_function(original_name + 3, hook_table, new_function, hook_execution_table); | ||
| 375 | } | ||
| 376 | } else { // TODO this can be moved somewhere else to gain some marginal perfs | ||
| 377 | CG(compiler_options) |= ZEND_COMPILE_NO_BUILTIN_STRLEN; | ||
| 378 | char* mb_name = pecalloc(strlen(original_name) + 3 + 1, 1, 0); | ||
| 379 | memcpy(mb_name, "mb_", 3); | ||
| 380 | memcpy(mb_name + 3, VAR_AND_LEN(original_name)); | ||
| 381 | if (zend_hash_str_find(CG(function_table), VAR_AND_LEN(mb_name))) { | ||
| 382 | hook_function(mb_name, hook_table, new_function, hook_execution_table); | ||
| 383 | } | ||
| 384 | } | ||
| 385 | |||
| 386 | if ((func = zend_hash_str_find_ptr(CG(function_table), | ||
| 387 | VAR_AND_LEN(original_name)))) { | ||
| 388 | if (func->handler == new_function) { | ||
| 389 | /* Success !*/ | ||
| 390 | } else if (zend_hash_str_add_new_ptr((hook_table), | ||
| 391 | VAR_AND_LEN(original_name), | ||
| 392 | func->handler) == NULL) { | ||
| 393 | sp_log_err("function_pointer_saving", | ||
| 394 | "Could not save function pointer for %s", original_name); | ||
| 395 | return FAILURE; | ||
| 396 | } else { | ||
| 397 | func->handler = new_function; | ||
| 398 | } | ||
| 399 | } | ||
| 400 | return SUCCESS; | ||
| 401 | } | ||
| 402 | |||
| 403 | int hook_regexp(const pcre* regexp, HashTable* hook_table, | ||
| 404 | void (*new_function)(INTERNAL_FUNCTION_PARAMETERS), | ||
| 405 | bool hook_execution_table) { | ||
| 406 | zend_string* key; | ||
| 407 | HashTable *ht = hook_execution_table==true?EG(function_table):CG(function_table); | ||
| 408 | |||
| 409 | ZEND_HASH_FOREACH_STR_KEY(ht, key) { | ||
| 410 | if (key) { | ||
| 411 | int vec[30]; | ||
| 412 | int ret = pcre_exec(regexp, NULL, key->val, key->len, 0, 0, vec, 30); | ||
| 413 | if (ret < 0) { /* Error or no match*/ | ||
| 414 | if (PCRE_ERROR_NOMATCH != ret) { | ||
| 415 | sp_log_err("pcre", "Runtime error with pcre, error code: %d", ret); | ||
| 416 | return FAILURE; | ||
| 417 | } | ||
| 418 | continue; | ||
| 419 | } | ||
| 420 | hook_function(key->val, hook_table, new_function, hook_execution_table); | ||
| 421 | } | ||
| 422 | } | ||
| 423 | ZEND_HASH_FOREACH_END(); | ||
| 424 | return SUCCESS; | ||
| 425 | } | ||
diff --git a/src/sp_utils.h b/src/sp_utils.h new file mode 100644 index 0000000..37dd2c0 --- /dev/null +++ b/src/sp_utils.h | |||
| @@ -0,0 +1,68 @@ | |||
| 1 | #ifndef SP_UTILS_H | ||
| 2 | #define SP_UTILS_H | ||
| 3 | |||
| 4 | #include "sp_config.h" | ||
| 5 | #include "sp_list.h" | ||
| 6 | |||
| 7 | #if defined(__GNUC__) | ||
| 8 | # if __GNUC__ >= 3 | ||
| 9 | # define sp_pure __attribute__((pure)) | ||
| 10 | # define sp_const __attribute__((const)) | ||
| 11 | # else | ||
| 12 | # define sp_pure | ||
| 13 | # define sp_const | ||
| 14 | # endif | ||
| 15 | #endif | ||
| 16 | /* The dump filename are of the form | ||
| 17 | * `sp_dump_DATE_IPADDR.dump`, with: | ||
| 18 | * - DATE being the output of asctime, 26 chars long | ||
| 19 | * - IP_ADDR being an IP adress, with a maximum size of 15 | ||
| 20 | * | ||
| 21 | * We keep one char for the terminal \0, and one for the leading slash. | ||
| 22 | */ | ||
| 23 | |||
| 24 | #define MAX_FOLDER_LEN \ | ||
| 25 | PATH_MAX - 1 - sizeof("sp_dump_") - 26 - sizeof("_") - 15 - \ | ||
| 26 | sizeof(".dump") - 1 | ||
| 27 | |||
| 28 | #define VAR_AND_LEN(var) var, strlen(var) | ||
| 29 | |||
| 30 | #define SHA256_SIZE 32 | ||
| 31 | |||
| 32 | #define HOOK_FUNCTION(original_name, hook_table, new_function, execution) \ | ||
| 33 | hook_function(original_name, SNUFFLEUPAGUS_G(hook_table), new_function, execution) | ||
| 34 | |||
| 35 | #define HOOK_FUNCTION_BY_REGEXP(regexp, hook_table, new_function, execution) \ | ||
| 36 | hook_regexp(regexp, SNUFFLEUPAGUS_G(hook_table), new_function, execution) | ||
| 37 | |||
| 38 | #define LOG_NOTICE "notice" | ||
| 39 | #define LOG_DROP "drop" | ||
| 40 | #define LOG_DEBUG "debug" | ||
| 41 | #define LOG_ERROR "error" | ||
| 42 | |||
| 43 | #define sp_log_err(feature, ...) sp_log_msg(feature, LOG_ERROR, __VA_ARGS__) | ||
| 44 | #ifdef SP_DEBUG | ||
| 45 | #define sp_log_debug(...) sp_log_msg("DEBUG", LOG_DEBUG, __VA_ARGS__) | ||
| 46 | #else | ||
| 47 | #define sp_log_debug(...) | ||
| 48 | #endif | ||
| 49 | |||
| 50 | void sp_log_msg(char const *feature, char const *level, const char* fmt, ...); | ||
| 51 | int compute_hash(const char *const filename, char *file_hash); | ||
| 52 | char *sp_convert_to_string(zval *); | ||
| 53 | bool sp_match_value(const char *, const char *, const pcre *); | ||
| 54 | int sp_match_array_key(const zval *, const char *, const pcre *); | ||
| 55 | int sp_match_array_key_recurse(const zval *, sp_node_t *, const char *, | ||
| 56 | const pcre *); | ||
| 57 | void sp_log_disable(const char *restrict, const char *restrict, | ||
| 58 | const char *restrict, const sp_disabled_function *); | ||
| 59 | void sp_log_disable_ret(const char *restrict, const char *restrict, | ||
| 60 | const sp_disabled_function *); | ||
| 61 | char *sp_getenv(char *); | ||
| 62 | int is_regexp_matching(const pcre *, const char *); | ||
| 63 | int hook_function(const char *, HashTable *, | ||
| 64 | void (*)(INTERNAL_FUNCTION_PARAMETERS), bool); | ||
| 65 | int hook_regexp(const pcre *, HashTable *, | ||
| 66 | void (*)(INTERNAL_FUNCTION_PARAMETERS), bool); | ||
| 67 | |||
| 68 | #endif /* SP_UTILS_H */ | ||
diff --git a/src/tests/broken_conf.phpt b/src/tests/broken_conf.phpt new file mode 100644 index 0000000..ae0ef6e --- /dev/null +++ b/src/tests/broken_conf.phpt | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | --TEST-- | ||
| 2 | Broken configuration | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/broken_conf.ini | ||
| 7 | --FILE-- | ||
| 8 | --EXPECT-- | ||
| 9 | [snuffleupagus][0.0.0.0][config][error] Invalid configuration prefix for 'this is a broken line'. | ||
| 10 | |||
diff --git a/src/tests/broken_conf2.phpt b/src/tests/broken_conf2.phpt new file mode 100644 index 0000000..88a2232 --- /dev/null +++ b/src/tests/broken_conf2.phpt | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | --TEST-- | ||
| 2 | Broken configuration | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/broken_conf2.ini | ||
| 7 | --FILE-- | ||
| 8 | --EXPECT-- | ||
| 9 | [snuffleupagus][0.0.0.0][config][error] Invalid configuration section 'sp.wrong'. | ||
diff --git a/src/tests/broken_conf_config_regexp.phpt b/src/tests/broken_conf_config_regexp.phpt new file mode 100644 index 0000000..75bc603 --- /dev/null +++ b/src/tests/broken_conf_config_regexp.phpt | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | --TEST-- | ||
| 2 | Broken configuration | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/broken_config_regexp.ini | ||
| 7 | --FILE-- | ||
| 8 | --EXPECT-- | ||
| 9 | [snuffleupagus][0.0.0.0][config][error] Failed to compile '*.': nothing to repeat. | ||
| 10 | [snuffleupagus][0.0.0.0][config][error] '.filename_r()' is expecting a valid regexp, and not '"*."'. | ||
diff --git a/src/tests/broken_conf_enable_disable.phpt b/src/tests/broken_conf_enable_disable.phpt new file mode 100644 index 0000000..2f3fe19 --- /dev/null +++ b/src/tests/broken_conf_enable_disable.phpt | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | --TEST-- | ||
| 2 | Global strict mode | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/borken_conf_enable_disable.ini | ||
| 7 | --FILE-- | ||
| 8 | --EXPECTF-- | ||
| 9 | [snuffleupagus][0.0.0.0][config][error] A rule can't be enabled and disabled. | ||
diff --git a/src/tests/broken_conf_expecting_bool.phpt b/src/tests/broken_conf_expecting_bool.phpt new file mode 100644 index 0000000..80e1b61 --- /dev/null +++ b/src/tests/broken_conf_expecting_bool.phpt | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | --TEST-- | ||
| 2 | Bad boolean value in configuration | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/broken_conf_expecting_bool.ini | ||
| 7 | --FILE-- | ||
| 8 | --EXPECT-- | ||
| 9 | [snuffleupagus][0.0.0.0][config][error] Trailing chars '337);' at the end of '.enable(1337);'. | ||
diff --git a/src/tests/broken_conf_expecting_int.phpt b/src/tests/broken_conf_expecting_int.phpt new file mode 100644 index 0000000..e806337 --- /dev/null +++ b/src/tests/broken_conf_expecting_int.phpt | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | --TEST-- | ||
| 2 | Bad integer value in configuration | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/broken_conf_expecting_int.ini | ||
| 7 | --FILE-- | ||
| 8 | --EXPECT-- | ||
| 9 | [snuffleupagus][0.0.0.0][error][error] .mask_ipv4() is expecting a valid integer. | ||
diff --git a/src/tests/broken_conf_invalid_cidr.phpt b/src/tests/broken_conf_invalid_cidr.phpt new file mode 100644 index 0000000..515091b --- /dev/null +++ b/src/tests/broken_conf_invalid_cidr.phpt | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | --TEST-- | ||
| 2 | Broken configuration | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/broken_conf_invalid_cidr.ini | ||
| 7 | --FILE-- | ||
| 8 | --EXPECT-- | ||
| 9 | [snuffleupagus][0.0.0.0][config][error] '42' isn't a valid ipv4 mask. | ||
diff --git a/src/tests/broken_conf_invalid_cidr6.phpt b/src/tests/broken_conf_invalid_cidr6.phpt new file mode 100644 index 0000000..d20cfcd --- /dev/null +++ b/src/tests/broken_conf_invalid_cidr6.phpt | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | --TEST-- | ||
| 2 | Broken configuration | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/broken_conf_invalid_cidr6.ini | ||
| 7 | --FILE-- | ||
| 8 | --EXPECT-- | ||
| 9 | [snuffleupagus][0.0.0.0][config][error] 'ZZZ' isn't a valid network mask. | ||
diff --git a/src/tests/broken_conf_invalid_cidr6_no_slash.phpt b/src/tests/broken_conf_invalid_cidr6_no_slash.phpt new file mode 100644 index 0000000..de70a05 --- /dev/null +++ b/src/tests/broken_conf_invalid_cidr6_no_slash.phpt | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | --TEST-- | ||
| 2 | Broken configuration, invalid cidr for ipv6 because there is no `/` in it | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/broken_conf_invalid_cidr6_no_slash.ini | ||
| 7 | --FILE-- | ||
| 8 | --EXPECT-- | ||
| 9 | [snuffleupagus][0.0.0.0][config][error] '2001:0db8:0000:0000:0000:ff00:0042:8329' isn't a valid network mask, it seems that you forgot a '/'. | ||
diff --git a/src/tests/broken_conf_invalid_cidr6_too_big.phpt b/src/tests/broken_conf_invalid_cidr6_too_big.phpt new file mode 100644 index 0000000..47d4a5d --- /dev/null +++ b/src/tests/broken_conf_invalid_cidr6_too_big.phpt | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | --TEST-- | ||
| 2 | Broken configuration, cidr for ipv6 is too big, that will `mod` to 25. | ||
| 3 | (13337%128 = 25) | ||
| 4 | --SKIPIF-- | ||
| 5 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 6 | --INI-- | ||
| 7 | sp.configuration_file={PWD}/config/broken_conf_invalid_cidr6_too_big.ini | ||
| 8 | --FILE-- | ||
| 9 | --EXPECT-- | ||
diff --git a/src/tests/broken_conf_invalid_cidr_value.phpt b/src/tests/broken_conf_invalid_cidr_value.phpt new file mode 100644 index 0000000..712f123 --- /dev/null +++ b/src/tests/broken_conf_invalid_cidr_value.phpt | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | --TEST-- | ||
| 2 | Broken configuration, invalid cidr value | ||
| 3 | (13337%128 = 25) | ||
| 4 | --SKIPIF-- | ||
| 5 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 6 | --INI-- | ||
| 7 | sp.configuration_file={PWD}/config/broken_conf_invalid_cidr_value.ini | ||
| 8 | --FILE-- | ||
| 9 | --EXPECT-- | ||
| 10 | [snuffleupagus][0.0.0.0][error][error] There is an issue with the parsing of '"': it doesn't look like a valid string. | ||
| 11 | [snuffleupagus][0.0.0.0][config][error] " doesn't contain a valid cidr. | ||
diff --git a/src/tests/broken_conf_invalid_type.phpt b/src/tests/broken_conf_invalid_type.phpt new file mode 100644 index 0000000..29d2ff5 --- /dev/null +++ b/src/tests/broken_conf_invalid_type.phpt | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | --TEST-- | ||
| 2 | Broken conf with wrong type | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/broken_conf_invalid_type.ini | ||
| 7 | --FILE-- | ||
| 8 | --EXPECTF-- | ||
| 9 | [snuffleupagus][0.0.0.0][error][error] There is an issue with the parsing of '"totally_wrong"_type")': it doesn't look like a valid string. | ||
diff --git a/src/tests/broken_conf_line_empty_string.phpt b/src/tests/broken_conf_line_empty_string.phpt new file mode 100644 index 0000000..c4334b9 --- /dev/null +++ b/src/tests/broken_conf_line_empty_string.phpt | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | --TEST-- | ||
| 2 | Configuration line with an empty string | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/broken_conf_line_empty_string.ini | ||
| 7 | --FILE-- | ||
| 8 | --EXPECT-- | ||
| 9 | [snuffleupagus][0.0.0.0][error][error] There is an issue with the parsing of '': it doesn't look like a valid string. | ||
diff --git a/src/tests/broken_conf_line_no_closing.phpt b/src/tests/broken_conf_line_no_closing.phpt new file mode 100644 index 0000000..07c94e4 --- /dev/null +++ b/src/tests/broken_conf_line_no_closing.phpt | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | --TEST-- | ||
| 2 | Configuration line without closing parenthese | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/broken_conf_line_no_closing.ini | ||
| 7 | --FILE-- | ||
| 8 | --EXPECT-- | ||
| 9 | [snuffleupagus][0.0.0.0][error][error] There is an issue with the parsing of '"123"': it doesn't look like a valid string. | ||
diff --git a/src/tests/broken_conf_line_too_long.phpt b/src/tests/broken_conf_line_too_long.phpt new file mode 100644 index 0000000..8e82708 --- /dev/null +++ b/src/tests/broken_conf_line_too_long.phpt | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | --TEST-- | ||
| 2 | Line too long in configuration | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/broken_conf_line_too_long.ini | ||
| 7 | --FILE-- | ||
| 8 | --EXPECT-- | ||
| 9 | [snuffleupagus][0.0.0.0][config][error] The following line is too long: 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111);. | ||
| 10 | [snuffleupagus][0.0.0.0][error][error] .mask_ipv4() is expecting a valid integer. | ||
diff --git a/src/tests/broken_conf_lots_of_quotes.phpt b/src/tests/broken_conf_lots_of_quotes.phpt new file mode 100644 index 0000000..e877cfa --- /dev/null +++ b/src/tests/broken_conf_lots_of_quotes.phpt | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | --TEST-- | ||
| 2 | Configuration line with too many quotes | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/broken_conf_lots_of_quotes.ini | ||
| 7 | --FILE-- | ||
| 8 | --EXPECT-- | ||
| 9 | [snuffleupagus][0.0.0.0][error][error] There is an issue with the parsing of '"this\"is a weird\"\"\"cookie\"name"");': it doesn't look like a valid string. | ||
diff --git a/src/tests/broken_conf_mutually_exclusive.phpt b/src/tests/broken_conf_mutually_exclusive.phpt new file mode 100644 index 0000000..9de7e5a --- /dev/null +++ b/src/tests/broken_conf_mutually_exclusive.phpt | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | --TEST-- | ||
| 2 | Broken configuration | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/broken_conf_mutually_exclusive.ini | ||
| 7 | --FILE-- | ||
| 8 | --EXPECT-- | ||
| 9 | [snuffleupagus][0.0.0.0][config][error] Invalid configuration line: 'sp.disabled_functions.function("system").param("id").value("42").value_r("^id$").drop();':'.value' and '.regexp' are mutually exclusives. \ No newline at end of file | ||
diff --git a/src/tests/broken_conf_mutually_exclusive2.phpt b/src/tests/broken_conf_mutually_exclusive2.phpt new file mode 100644 index 0000000..9d3ea36 --- /dev/null +++ b/src/tests/broken_conf_mutually_exclusive2.phpt | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | --TEST-- | ||
| 2 | Broken configuration | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/broken_conf_mutually_exclusive2.ini | ||
| 7 | --FILE-- | ||
| 8 | --EXPECT-- | ||
| 9 | [snuffleupagus][0.0.0.0][config][error] Invalid configuration line: 'sp.disabled_functions.function("system").function_r("system").param("id").value("42").drop();': '.r_function' and '.function' are mutually exclusive. \ No newline at end of file | ||
diff --git a/src/tests/broken_conf_mutually_exclusive3.phpt b/src/tests/broken_conf_mutually_exclusive3.phpt new file mode 100644 index 0000000..58686a3 --- /dev/null +++ b/src/tests/broken_conf_mutually_exclusive3.phpt | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | --TEST-- | ||
| 2 | Broken configuration | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/broken_conf_mutually_exclusive3.ini | ||
| 7 | --FILE-- | ||
| 8 | --EXPECT-- | ||
| 9 | [snuffleupagus][0.0.0.0][config][error] Invalid configuration line: 'sp.disabled_functions.function("system").param("id").value("42").filename_r("^id$").filename("pouet.txt").drop();':'.r_filename' and '.filename' are mutually exclusive. \ No newline at end of file | ||
diff --git a/src/tests/broken_conf_mutually_exclusive4.phpt b/src/tests/broken_conf_mutually_exclusive4.phpt new file mode 100644 index 0000000..d854380 --- /dev/null +++ b/src/tests/broken_conf_mutually_exclusive4.phpt | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | --TEST-- | ||
| 2 | Broken configuration | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/broken_conf_mutually_exclusive4.ini | ||
| 7 | --FILE-- | ||
| 8 | --EXPECT-- | ||
| 9 | [snuffleupagus][0.0.0.0][config][error] Invalid configuration line: 'sp.disabled_functions.function("system").param("id").value("42").param_r("^id$").drop();':'.r_param' and '.param' are mutually exclusive. \ No newline at end of file | ||
diff --git a/src/tests/broken_conf_mutually_exclusive5.phpt b/src/tests/broken_conf_mutually_exclusive5.phpt new file mode 100644 index 0000000..a265c30 --- /dev/null +++ b/src/tests/broken_conf_mutually_exclusive5.phpt | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | --TEST-- | ||
| 2 | Broken configuration | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/broken_conf_mutually_exclusive5.ini | ||
| 7 | --FILE-- | ||
| 8 | --EXPECT-- | ||
| 9 | [snuffleupagus][0.0.0.0][config][error] Invalid configuration line: 'sp.disabled_functions.function("system").ret("0").drop().ret_r("^0$");':'.r_ret' and '.ret' are mutually exclusive. \ No newline at end of file | ||
diff --git a/src/tests/broken_conf_mutually_exclusive6.phpt b/src/tests/broken_conf_mutually_exclusive6.phpt new file mode 100644 index 0000000..d0cdb85 --- /dev/null +++ b/src/tests/broken_conf_mutually_exclusive6.phpt | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | --TEST-- | ||
| 2 | Broken configuration | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/broken_conf_mutually_exclusive6.ini | ||
| 7 | --FILE-- | ||
| 8 | --EXPECT-- | ||
| 9 | [snuffleupagus][0.0.0.0][config][error] Invalid configuration line: 'sp.disabled_functions.function("system").param("id").value("42").ret_r("^0$").drop();':`ret` and `param` are mutually exclusives. \ No newline at end of file | ||
diff --git a/src/tests/broken_conf_mutually_exclusive7.phpt b/src/tests/broken_conf_mutually_exclusive7.phpt new file mode 100644 index 0000000..c9a3513 --- /dev/null +++ b/src/tests/broken_conf_mutually_exclusive7.phpt | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | --TEST-- | ||
| 2 | Broken configuration | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/broken_conf_mutually_exclusive7.ini | ||
| 7 | --FILE-- | ||
| 8 | --EXPECT-- | ||
| 9 | [snuffleupagus][0.0.0.0][config][error] Invalid configuration line: 'sp.disabled_functions.function("system").ret("0").drop().allow();': The rule must either be a `drop` or and `allow` one. \ No newline at end of file | ||
diff --git a/src/tests/broken_conf_mutually_exclusive8.phpt b/src/tests/broken_conf_mutually_exclusive8.phpt new file mode 100644 index 0000000..7c5baee --- /dev/null +++ b/src/tests/broken_conf_mutually_exclusive8.phpt | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | --TEST-- | ||
| 2 | Broken configuration | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/broken_conf_mutually_exclusive8.ini | ||
| 7 | --FILE-- | ||
| 8 | --EXPECT-- | ||
| 9 | [snuffleupagus][0.0.0.0][config][error] Invalid configuration line: 'sp.disabled_functions.ret("0").drop();': must take a function name. \ No newline at end of file | ||
diff --git a/src/tests/broken_conf_no_closing_misc.phpt b/src/tests/broken_conf_no_closing_misc.phpt new file mode 100644 index 0000000..1d1e112 --- /dev/null +++ b/src/tests/broken_conf_no_closing_misc.phpt | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | --TEST-- | ||
| 2 | Configuration line without closing parenthese, misc | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/broken_conf_no_closing_misc.ini | ||
| 7 | --FILE-- | ||
| 8 | --EXPECT-- | ||
| 9 | [snuffleupagus][0.0.0.0][config][error] Missing closing ) in line 123. | ||
| 10 | [snuffleupagus][0.0.0.0][error][error] .mask_ipv4() is expecting a valid integer. | ||
diff --git a/src/tests/broken_conf_weird_keyword.phpt b/src/tests/broken_conf_weird_keyword.phpt new file mode 100644 index 0000000..5293791 --- /dev/null +++ b/src/tests/broken_conf_weird_keyword.phpt | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | --TEST-- | ||
| 2 | Bad config, unknown keyword | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/broken_conf_weird_keyword.ini | ||
| 7 | --FILE-- | ||
| 8 | --EXPECT-- | ||
| 9 | [snuffleupagus][0.0.0.0][config][error] Trailing chars '.not_a_valid_keyword("test");' at the end of '.enable().not_a_valid_keyword("test");'. \ No newline at end of file | ||
diff --git a/src/tests/broken_conf_wrong_quotes.phpt b/src/tests/broken_conf_wrong_quotes.phpt new file mode 100644 index 0000000..b6324fe --- /dev/null +++ b/src/tests/broken_conf_wrong_quotes.phpt | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | --TEST-- | ||
| 2 | Configuration line with too many quotes | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/broken_conf_wrong_quotes.ini | ||
| 7 | --FILE-- | ||
| 8 | --EXPECT-- | ||
| 9 | [snuffleupagus][0.0.0.0][error][error] There is an issue with the parsing of '"\)': it doesn't look like a valid string. | ||
diff --git a/src/tests/broken_conf_wrong_type.phpt b/src/tests/broken_conf_wrong_type.phpt new file mode 100644 index 0000000..338ca3a --- /dev/null +++ b/src/tests/broken_conf_wrong_type.phpt | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | --TEST-- | ||
| 2 | Broken conf with wrong type | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/broken_conf_wrong_type.ini | ||
| 7 | --FILE-- | ||
| 8 | --EXPECTF-- | ||
| 9 | [snuffleupagus][0.0.0.0][error][error] .ret_type() is expecting a valid php type ('false', 'true', 'array'. 'object', 'long', 'double', 'null', 'resource', 'reference', 'undef'). | ||
diff --git a/src/tests/broken_regexp.phpt b/src/tests/broken_regexp.phpt new file mode 100644 index 0000000..cbfef7d --- /dev/null +++ b/src/tests/broken_regexp.phpt | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | --TEST-- | ||
| 2 | Broken regexp | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/broken_regexp.ini | ||
| 7 | --FILE-- | ||
| 8 | --EXPECTF-- | ||
| 9 | [snuffleupagus][0.0.0.0][config][error] '.value_r()' is expecting a valid regexp, and not '"^$["'. | ||
diff --git a/src/tests/config/borken_conf_enable_disable.ini b/src/tests/config/borken_conf_enable_disable.ini new file mode 100644 index 0000000..4e95294 --- /dev/null +++ b/src/tests/config/borken_conf_enable_disable.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.global_strict.disable().enable(); | |||
diff --git a/src/tests/config/broken_conf.ini b/src/tests/config/broken_conf.ini new file mode 100644 index 0000000..0595320 --- /dev/null +++ b/src/tests/config/broken_conf.ini | |||
| @@ -0,0 +1 @@ | |||
| this is a broken line | |||
diff --git a/src/tests/config/broken_conf2.ini b/src/tests/config/broken_conf2.ini new file mode 100644 index 0000000..fdb6b8f --- /dev/null +++ b/src/tests/config/broken_conf2.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.wrong | |||
diff --git a/src/tests/config/broken_conf_expecting_bool.ini b/src/tests/config/broken_conf_expecting_bool.ini new file mode 100644 index 0000000..51c28b2 --- /dev/null +++ b/src/tests/config/broken_conf_expecting_bool.ini | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | # this is an example of broken conf | ||
| 2 | |||
| 3 | |||
| 4 | ; this is another comment | ||
| 5 | sp.harden_random.enable(1337); | ||
diff --git a/src/tests/config/broken_conf_expecting_int.ini b/src/tests/config/broken_conf_expecting_int.ini new file mode 100644 index 0000000..8e2efea --- /dev/null +++ b/src/tests/config/broken_conf_expecting_int.ini | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | sp.global.secret_key("abcdef"); | ||
| 2 | sp.cookie_encryption.cookie("super_cookie").mask_ipv4(abc); | ||
diff --git a/src/tests/config/broken_conf_invalid_cidr.ini b/src/tests/config/broken_conf_invalid_cidr.ini new file mode 100644 index 0000000..0cdc695 --- /dev/null +++ b/src/tests/config/broken_conf_invalid_cidr.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.disable_functions.function("system").drop().cidr("127.0.0.1/42"); | |||
diff --git a/src/tests/config/broken_conf_invalid_cidr6.ini b/src/tests/config/broken_conf_invalid_cidr6.ini new file mode 100644 index 0000000..e5a120c --- /dev/null +++ b/src/tests/config/broken_conf_invalid_cidr6.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.disable_functions.function("system").drop().cidr("2001:0db8:0000:0000:0000:ff00:0042:8329/ZZZ"); | |||
diff --git a/src/tests/config/broken_conf_invalid_cidr6_no_slash.ini b/src/tests/config/broken_conf_invalid_cidr6_no_slash.ini new file mode 100644 index 0000000..e4cf835 --- /dev/null +++ b/src/tests/config/broken_conf_invalid_cidr6_no_slash.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.disable_functions.function("system").drop().cidr("2001:0db8:0000:0000:0000:ff00:0042:8329"); | |||
diff --git a/src/tests/config/broken_conf_invalid_cidr6_too_big.ini b/src/tests/config/broken_conf_invalid_cidr6_too_big.ini new file mode 100644 index 0000000..417dee7 --- /dev/null +++ b/src/tests/config/broken_conf_invalid_cidr6_too_big.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.disable_functions.function("system").drop().cidr("2001:0db8:0000:0000:0000:ff00:0042:8329/13337"); | |||
diff --git a/src/tests/config/broken_conf_invalid_cidr_value.ini b/src/tests/config/broken_conf_invalid_cidr_value.ini new file mode 100644 index 0000000..733e889 --- /dev/null +++ b/src/tests/config/broken_conf_invalid_cidr_value.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.disable_functions.function("system").drop().cidr(" | |||
diff --git a/src/tests/config/broken_conf_invalid_type.ini b/src/tests/config/broken_conf_invalid_type.ini new file mode 100644 index 0000000..b2cd8cd --- /dev/null +++ b/src/tests/config/broken_conf_invalid_type.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.disable_functions.function("strpos").ret_type("totally_wrong"_type") | |||
diff --git a/src/tests/config/broken_conf_line_empty_string.ini b/src/tests/config/broken_conf_line_empty_string.ini new file mode 100644 index 0000000..74d0e5a --- /dev/null +++ b/src/tests/config/broken_conf_line_empty_string.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.cookie_encryption.mask_ipv4(123).cookie( | |||
diff --git a/src/tests/config/broken_conf_line_no_closing.ini b/src/tests/config/broken_conf_line_no_closing.ini new file mode 100644 index 0000000..bcac291 --- /dev/null +++ b/src/tests/config/broken_conf_line_no_closing.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.cookie_encryption.mask_ipv4(123).cookie("123" | |||
diff --git a/src/tests/config/broken_conf_line_too_long.ini b/src/tests/config/broken_conf_line_too_long.ini new file mode 100644 index 0000000..ed057a5 --- /dev/null +++ b/src/tests/config/broken_conf_line_too_long.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.cookie_encryption.cookie("super_cookie").mask_ipv4(1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111); | |||
diff --git a/src/tests/config/broken_conf_lots_of_quotes.ini b/src/tests/config/broken_conf_lots_of_quotes.ini new file mode 100644 index 0000000..dfd48e7 --- /dev/null +++ b/src/tests/config/broken_conf_lots_of_quotes.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.cookie_encryption.mask_ipv4(123).cookie("this\"is a weird\"\"\"cookie\"name""); | |||
diff --git a/src/tests/config/broken_conf_mutually_exclusive.ini b/src/tests/config/broken_conf_mutually_exclusive.ini new file mode 100644 index 0000000..af1d505 --- /dev/null +++ b/src/tests/config/broken_conf_mutually_exclusive.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.disable_functions.function("system").param("id").value("42").value_r("^id$").drop(); | |||
diff --git a/src/tests/config/broken_conf_mutually_exclusive2.ini b/src/tests/config/broken_conf_mutually_exclusive2.ini new file mode 100644 index 0000000..29b21d4 --- /dev/null +++ b/src/tests/config/broken_conf_mutually_exclusive2.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.disable_functions.function("system").function_r("system").param("id").value("42").drop(); | |||
diff --git a/src/tests/config/broken_conf_mutually_exclusive3.ini b/src/tests/config/broken_conf_mutually_exclusive3.ini new file mode 100644 index 0000000..556de08 --- /dev/null +++ b/src/tests/config/broken_conf_mutually_exclusive3.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.disable_functions.function("system").param("id").value("42").filename_r("^id$").filename("pouet.txt").drop(); | |||
diff --git a/src/tests/config/broken_conf_mutually_exclusive4.ini b/src/tests/config/broken_conf_mutually_exclusive4.ini new file mode 100644 index 0000000..d212ad4 --- /dev/null +++ b/src/tests/config/broken_conf_mutually_exclusive4.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.disable_functions.function("system").param("id").value("42").param_r("^id$").drop(); | |||
diff --git a/src/tests/config/broken_conf_mutually_exclusive5.ini b/src/tests/config/broken_conf_mutually_exclusive5.ini new file mode 100644 index 0000000..5b64079 --- /dev/null +++ b/src/tests/config/broken_conf_mutually_exclusive5.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.disable_functions.function("system").ret("0").drop().ret_r("^0$"); | |||
diff --git a/src/tests/config/broken_conf_mutually_exclusive6.ini b/src/tests/config/broken_conf_mutually_exclusive6.ini new file mode 100644 index 0000000..d08ee58 --- /dev/null +++ b/src/tests/config/broken_conf_mutually_exclusive6.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.disable_functions.function("system").param("id").value("42").ret_r("^0$").drop(); | |||
diff --git a/src/tests/config/broken_conf_mutually_exclusive7.ini b/src/tests/config/broken_conf_mutually_exclusive7.ini new file mode 100644 index 0000000..645c26c --- /dev/null +++ b/src/tests/config/broken_conf_mutually_exclusive7.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.disable_functions.function("system").ret("0").drop().allow(); | |||
diff --git a/src/tests/config/broken_conf_mutually_exclusive8.ini b/src/tests/config/broken_conf_mutually_exclusive8.ini new file mode 100644 index 0000000..b08ef57 --- /dev/null +++ b/src/tests/config/broken_conf_mutually_exclusive8.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.disable_functions.ret("0").drop(); | |||
diff --git a/src/tests/config/broken_conf_no_closing_misc.ini b/src/tests/config/broken_conf_no_closing_misc.ini new file mode 100644 index 0000000..2cb79a8 --- /dev/null +++ b/src/tests/config/broken_conf_no_closing_misc.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.cookie_encryption.cookie("123").mask_ipv4(123 | |||
diff --git a/src/tests/config/broken_conf_to_few_args.ini b/src/tests/config/broken_conf_to_few_args.ini new file mode 100644 index 0000000..89e19be --- /dev/null +++ b/src/tests/config/broken_conf_to_few_args.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.harden_random.enable(); | |||
diff --git a/src/tests/config/broken_conf_weird_keyword.ini b/src/tests/config/broken_conf_weird_keyword.ini new file mode 100644 index 0000000..bf5e7f5 --- /dev/null +++ b/src/tests/config/broken_conf_weird_keyword.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.harden_random.enable().not_a_valid_keyword("test"); | |||
diff --git a/src/tests/config/broken_conf_wrong_quotes.ini b/src/tests/config/broken_conf_wrong_quotes.ini new file mode 100644 index 0000000..c8cc949 --- /dev/null +++ b/src/tests/config/broken_conf_wrong_quotes.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.cookie_encryption.mask_ipv4(123).cookie("\) | |||
diff --git a/src/tests/config/broken_conf_wrong_type.ini b/src/tests/config/broken_conf_wrong_type.ini new file mode 100644 index 0000000..6ecca6a --- /dev/null +++ b/src/tests/config/broken_conf_wrong_type.ini | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | sp.disable_functions.function("strpos").ret_type("undef").drop().alias("Return value is undef"); | ||
| 2 | sp.disable_functions.function("strpos").ret_type("null").drop().alias("Return value is null"); | ||
| 3 | sp.disable_functions.function("strpos").ret_type("object").drop().alias("Return value is object"); | ||
| 4 | sp.disable_functions.function("strpos").ret_type("reference").drop().alias("Return value is reference"); | ||
| 5 | sp.disable_functions.function("strpos").ret_type("totally_wrong_type").drop().alias("Return value is FALSE"); | ||
diff --git a/src/tests/config/broken_config_regexp.ini b/src/tests/config/broken_config_regexp.ini new file mode 100644 index 0000000..efad83e --- /dev/null +++ b/src/tests/config/broken_config_regexp.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.disable_functions.function_r("^system$").filename_r("*.").drop(); | |||
diff --git a/src/tests/config/broken_regexp.ini b/src/tests/config/broken_regexp.ini new file mode 100644 index 0000000..8e1f69a --- /dev/null +++ b/src/tests/config/broken_regexp.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.disable_functions.function("AwesomeClass::method3").param("a").drop().value_r("^$["); | |||
diff --git a/src/tests/config/config_disable_writable.ini b/src/tests/config/config_disable_writable.ini new file mode 100644 index 0000000..9f90601 --- /dev/null +++ b/src/tests/config/config_disable_writable.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.readonly_exec.enable(); | |||
diff --git a/src/tests/config/config_disable_writable_disabled.ini b/src/tests/config/config_disable_writable_disabled.ini new file mode 100644 index 0000000..6a33437 --- /dev/null +++ b/src/tests/config/config_disable_writable_disabled.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.readonly_exec.disable(); | |||
diff --git a/src/tests/config/config_disable_writable_simulation.ini b/src/tests/config/config_disable_writable_simulation.ini new file mode 100644 index 0000000..52a43ba --- /dev/null +++ b/src/tests/config/config_disable_writable_simulation.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.readonly_exec.enable().simulation(); | |||
diff --git a/src/tests/config/config_disabled_functions_filename_r.ini b/src/tests/config/config_disabled_functions_filename_r.ini new file mode 100644 index 0000000..b92f136 --- /dev/null +++ b/src/tests/config/config_disabled_functions_filename_r.ini | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | sp.disable_functions.function_r("^system$").filename_r("\\.txt$").drop(); | ||
| 2 | sp.disable_functions.function_r("^shell_exec$").filename_r("\\.php$").drop(); | ||
diff --git a/src/tests/config/config_disabled_functions_method.ini b/src/tests/config/config_disabled_functions_method.ini new file mode 100644 index 0000000..4d088d2 --- /dev/null +++ b/src/tests/config/config_disabled_functions_method.ini | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | sp.disable_functions.function("AwesomeClass::method1").drop(); | ||
| 2 | sp.disable_functions.function("method2").drop(); | ||
| 3 | sp.disable_functions.function("AwesomeClass::method3").param("a").value("pouet").drop(); | ||
diff --git a/src/tests/config/config_disabled_functions_name_r.ini b/src/tests/config/config_disabled_functions_name_r.ini new file mode 100644 index 0000000..3f7178e --- /dev/null +++ b/src/tests/config/config_disabled_functions_name_r.ini | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | sp.disable_functions.function_r("^not_system$").ret("42").drop(); | ||
| 2 | sp.disable_functions.function_r("^system$").ret("1337").drop(); | ||
diff --git a/src/tests/config/config_disabled_functions_name_type.ini b/src/tests/config/config_disabled_functions_name_type.ini new file mode 100644 index 0000000..2b433df --- /dev/null +++ b/src/tests/config/config_disabled_functions_name_type.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.disable_functions.function_r("^strcmp$").param("str1").param_type("array").drop(); | |||
diff --git a/src/tests/config/config_disabled_functions_namespace.ini b/src/tests/config/config_disabled_functions_namespace.ini new file mode 100644 index 0000000..d09b81b --- /dev/null +++ b/src/tests/config/config_disabled_functions_namespace.ini | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | sp.disable_functions.function("strcmp").drop(); | ||
| 2 | sp.disable_functions.function("my_super_namespace::my_function").drop(); | ||
diff --git a/src/tests/config/config_disabled_functions_nul_byte.ini b/src/tests/config/config_disabled_functions_nul_byte.ini new file mode 100644 index 0000000..7994583 --- /dev/null +++ b/src/tests/config/config_disabled_functions_nul_byte.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.disable_functions.function("system").param("command").value_r("id").drop(); \ No newline at end of file | |||
diff --git a/src/tests/config/config_disabled_functions_param.ini b/src/tests/config/config_disabled_functions_param.ini new file mode 100644 index 0000000..7363781 --- /dev/null +++ b/src/tests/config/config_disabled_functions_param.ini | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | sp.disable_functions.function("system").param("command").value_r("^id$").alias("1").drop(); | ||
| 2 | sp.disable_functions.function("array_sum").param("array").value_r("^8$").alias("2").drop(); | ||
| 3 | sp.disable_functions.function("shell_exec").param("cmd").value("id").alias("3").drop(); | ||
| 4 | sp.disable_functions.function("shell_exec").param("cmd").value("bla").alias("4").drop(); | ||
| 5 | sp.disable_functions.function("strcmp").param("str1").value("bla").alias("5").drop().simulation(); | ||
| 6 | sp.disable_functions.function("strncmp").param("str1").value("bla").drop().simulation(); | ||
diff --git a/src/tests/config/config_disabled_functions_param_alias.ini b/src/tests/config/config_disabled_functions_param_alias.ini new file mode 100644 index 0000000..f8d9f43 --- /dev/null +++ b/src/tests/config/config_disabled_functions_param_alias.ini | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | sp.disable_functions.function("system").alias("1").drop(); | ||
| 2 | sp.disable_functions.function("shell_exec").alias("2").drop().simulation(); | ||
diff --git a/src/tests/config/config_disabled_functions_param_allow.ini b/src/tests/config/config_disabled_functions_param_allow.ini new file mode 100644 index 0000000..e349b38 --- /dev/null +++ b/src/tests/config/config_disabled_functions_param_allow.ini | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | sp.disable_functions.function("system").param("command").value("echo win").filename("test.php").drop(); | ||
| 2 | sp.disable_functions.function("system").param("command").value("echo win").allow(); | ||
| 3 | sp.disable_functions.function("system").drop(); | ||
diff --git a/src/tests/config/config_disabled_functions_param_array.ini b/src/tests/config/config_disabled_functions_param_array.ini new file mode 100644 index 0000000..7b71692 --- /dev/null +++ b/src/tests/config/config_disabled_functions_param_array.ini | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | sp.disable_functions.function("foo").param("arr").value("abcd").alias("1").drop(); | ||
| 2 | sp.disable_functions.function("foo").param("arr[bla]").value("abcdef").alias("2").drop(); | ||
| 3 | sp.disable_functions.function("foo").param("arr[test]").alias("3").drop(); | ||
| 4 | sp.disable_functions.function("foo").param("arr[test2][foo][lol]").value("aaa").alias("4").drop(); | ||
diff --git a/src/tests/config/config_disabled_functions_param_int.ini b/src/tests/config/config_disabled_functions_param_int.ini new file mode 100644 index 0000000..2552f0a --- /dev/null +++ b/src/tests/config/config_disabled_functions_param_int.ini | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | sp.disable_functions.function("foobar").param("id").value("42").drop(); | ||
| 2 | sp.disable_functions.function("foobar").param("id").value_r("^1337").drop(); | ||
diff --git a/src/tests/config/config_disabled_functions_param_r.ini b/src/tests/config/config_disabled_functions_param_r.ini new file mode 100644 index 0000000..d9f6692 --- /dev/null +++ b/src/tests/config/config_disabled_functions_param_r.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.disable_functions.function("system").param_r("^command$").value("id").drop(); | |||
diff --git a/src/tests/config/config_disabled_functions_param_runtime.ini b/src/tests/config/config_disabled_functions_param_runtime.ini new file mode 100644 index 0000000..641bd0a --- /dev/null +++ b/src/tests/config/config_disabled_functions_param_runtime.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.disable_functions.function("test").param("param").value_r("1337").drop(); | |||
diff --git a/src/tests/config/config_disabled_functions_param_str_representation.ini b/src/tests/config/config_disabled_functions_param_str_representation.ini new file mode 100644 index 0000000..7171a30 --- /dev/null +++ b/src/tests/config/config_disabled_functions_param_str_representation.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.disable_functions.function("var_export").param("var").value("bla").drop(); | |||
diff --git a/src/tests/config/config_disabled_functions_require.ini b/src/tests/config/config_disabled_functions_require.ini new file mode 100644 index 0000000..474fada --- /dev/null +++ b/src/tests/config/config_disabled_functions_require.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.disable_functions.function("require").param("").value_r("meh$").drop(); | |||
diff --git a/src/tests/config/config_disabled_functions_ret_allow.ini b/src/tests/config/config_disabled_functions_ret_allow.ini new file mode 100644 index 0000000..1884227 --- /dev/null +++ b/src/tests/config/config_disabled_functions_ret_allow.ini | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | sp.disable_functions.function("strpos").hash("70b33f3eaf585b245640bb2c92445d0040b2bcb31395aa25dede9f2df4dbcbe8").allow(); | ||
| 2 | sp.disable_functions.function("strpos").drop(); | ||
diff --git a/src/tests/config/config_disabled_functions_ret_allow_value.ini b/src/tests/config/config_disabled_functions_ret_allow_value.ini new file mode 100644 index 0000000..e179819 --- /dev/null +++ b/src/tests/config/config_disabled_functions_ret_allow_value.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.disable_functions.function("strpos").ret("0").allow(); | |||
diff --git a/src/tests/config/config_disabled_functions_ret_right_hash.ini b/src/tests/config/config_disabled_functions_ret_right_hash.ini new file mode 100644 index 0000000..6f49177 --- /dev/null +++ b/src/tests/config/config_disabled_functions_ret_right_hash.ini | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | sp.disable_functions.function("system").ret("1").drop(); | ||
| 2 | sp.disable_functions.function("system").ret("1337").hash("123456789597a81a2b862cdb49920e2cba2e5979a3fc374c58c803e8f5c99a10").drop(); | ||
| 3 | sp.disable_functions.function("system").ret("1338").hash("522a976fa597a81a2b862cdb49920e2cba2e5979a3fc374c58c803e8f5c99a10").drop(); | ||
| 4 | sp.disable_functions.function("system").ret("1337").hash("522a976fa597a81a2b862cdb49920e2cba2e5979a3fc374c58c803e8f5c99a10").drop(); | ||
diff --git a/src/tests/config/config_disabled_functions_ret_simulation.ini b/src/tests/config/config_disabled_functions_ret_simulation.ini new file mode 100644 index 0000000..ee46c4b --- /dev/null +++ b/src/tests/config/config_disabled_functions_ret_simulation.ini | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | sp.disable_functions.function("strpos").ret("0").simulation().drop(); | ||
| 2 | sp.disable_functions.function("stripos").ret("0").simulation().drop().alias("1"); | ||
| 3 | sp.disable_functions.function("strcmp").ret("0").drop(); | ||
diff --git a/src/tests/config/config_disabled_functions_right_hash.ini b/src/tests/config/config_disabled_functions_right_hash.ini new file mode 100644 index 0000000..fab68fa --- /dev/null +++ b/src/tests/config/config_disabled_functions_right_hash.ini | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | sp.disable_functions.function("system").hash("1337c3ad8cf096272cd0e78768af3b11325f498de5c2c36f40adc43643af378a").allow(); | ||
| 2 | sp.disable_functions.function("system").hash("d259c3ad8cf096272cd0e78768af3b11325f498de5c2c36f40adc43643af378a").allow(); | ||
| 3 | sp.disable_functions.function("system").drop(); \ No newline at end of file | ||
diff --git a/src/tests/config/config_disabled_user_functions.ini b/src/tests/config/config_disabled_user_functions.ini new file mode 100644 index 0000000..15cbccc --- /dev/null +++ b/src/tests/config/config_disabled_user_functions.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.disable_functions.function("my_super_function").drop(); | |||
diff --git a/src/tests/config/config_encrypted_cookies.ini b/src/tests/config/config_encrypted_cookies.ini new file mode 100644 index 0000000..710e863 --- /dev/null +++ b/src/tests/config/config_encrypted_cookies.ini | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | sp.global.secret_key("abcdef"); | ||
| 2 | sp.cookie_encryption.cookie("super_cookie").mask_ipv4(8).mask_ipv6(2); | ||
| 3 | sp.auto_cookie_secure.enable(); | ||
diff --git a/src/tests/config/config_noncore_function_hooking.ini b/src/tests/config/config_noncore_function_hooking.ini new file mode 100644 index 0000000..88f2acf --- /dev/null +++ b/src/tests/config/config_noncore_function_hooking.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.disable_functions.function("custom_fun").drop(); | |||
diff --git a/src/tests/config/config_rand_harden_disabled.ini b/src/tests/config/config_rand_harden_disabled.ini new file mode 100644 index 0000000..b9cd227 --- /dev/null +++ b/src/tests/config/config_rand_harden_disabled.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.harden_random.disable(); | |||
diff --git a/src/tests/config/config_serialize.ini b/src/tests/config/config_serialize.ini new file mode 100644 index 0000000..f2c1699 --- /dev/null +++ b/src/tests/config/config_serialize.ini | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | sp.global.secret_key("abcdef"); | ||
| 2 | sp.unserialize_hmac.enable(); \ No newline at end of file | ||
diff --git a/src/tests/config/config_serialize_sim.ini b/src/tests/config/config_serialize_sim.ini new file mode 100644 index 0000000..7f015e0 --- /dev/null +++ b/src/tests/config/config_serialize_sim.ini | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | sp.global.secret_key("abcdef"); | ||
| 2 | sp.unserialize_hmac.enable().simulation(); | ||
diff --git a/src/tests/config/disable_xxe.ini b/src/tests/config/disable_xxe.ini new file mode 100644 index 0000000..bc9d1f2 --- /dev/null +++ b/src/tests/config/disable_xxe.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.disable_xxe.enable(); | |||
diff --git a/src/tests/config/disable_xxe_disable.ini b/src/tests/config/disable_xxe_disable.ini new file mode 100644 index 0000000..bb1e432 --- /dev/null +++ b/src/tests/config/disable_xxe_disable.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.disable_xxe.disable(); | |||
diff --git a/src/tests/config/disabled_function_local_var.ini b/src/tests/config/disabled_function_local_var.ini new file mode 100644 index 0000000..64d98dc --- /dev/null +++ b/src/tests/config/disabled_function_local_var.ini | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | sp.disable_functions.function("phpinfo").var("b").value("1337").drop(); | ||
| 2 | sp.disable_functions.function("strlen").var("a").value("1337").drop(); | ||
diff --git a/src/tests/config/disabled_function_super_global_var.ini b/src/tests/config/disabled_function_super_global_var.ini new file mode 100644 index 0000000..e0c87e1 --- /dev/null +++ b/src/tests/config/disabled_function_super_global_var.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.disable_functions.function("strlen").var("_GET[bla]").value("test2").drop(); | |||
diff --git a/src/tests/config/disabled_functions.ini b/src/tests/config/disabled_functions.ini new file mode 100644 index 0000000..cf54164 --- /dev/null +++ b/src/tests/config/disabled_functions.ini | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | sp.disable_functions.function("system").drop(); | ||
| 2 | sp.disable_functions.function("vprintf").hash("123456789").drop(); | ||
| 3 | sp.disable_functions.function("printf").disable().drop(); | ||
| 4 | sp.disable_functions.function("printf").simulation().drop(); | ||
| 5 | sp.disable_functions.function("print").disable().drop(); # this is a comment | ||
| 6 | sp.disable_functions.function_r("^var_dump$").drop(); | ||
| 7 | sp.disable_functions.function("sprintf").filename("wrong file name").drop(); | ||
diff --git a/src/tests/config/disabled_functions_cidr.ini b/src/tests/config/disabled_functions_cidr.ini new file mode 100644 index 0000000..9e527ba --- /dev/null +++ b/src/tests/config/disabled_functions_cidr.ini | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | sp.disable_functions.function("system").drop().cidr("127.0.0.1/8"); | ||
| 2 | sp.disable_functions.function("printf").drop().cidr("10.0.0.1/8"); | ||
| 3 | sp.disable_functions.function("strpos").drop().cidr("2001:0db8:0000:0000:0000:ff00:0042:8329/24"); | ||
| 4 | sp.disable_functions.function("printf").drop().cidr("2002:0db8:0000:0000:0000:ff00:0042:8329/24"); | ||
diff --git a/src/tests/config/disabled_functions_mb.ini b/src/tests/config/disabled_functions_mb.ini new file mode 100644 index 0000000..b6afd97 --- /dev/null +++ b/src/tests/config/disabled_functions_mb.ini | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | sp.disable_functions.function("strlen").drop(); | ||
| 2 | sp.disable_functions.function("mb_strlen").drop(); | ||
diff --git a/src/tests/config/disabled_functions_ret.ini b/src/tests/config/disabled_functions_ret.ini new file mode 100644 index 0000000..2b769a9 --- /dev/null +++ b/src/tests/config/disabled_functions_ret.ini | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | sp.disable_functions.function("testFunction").ret("0").drop().disable(); | ||
| 2 | sp.disable_functions.function("strpos").ret("0").drop().filename_r(".*\\.php"); | ||
| 3 | sp.disable_functions.function_r("str[ia]pos").ret_r("^[^a-z]+$").drop(); | ||
| 4 | sp.disable_functions.function_r("stripos").ret_r("^[^a-z]+").drop(); | ||
| 5 | sp.disable_functions.function("Bob::a").ret("0").drop(); | ||
diff --git a/src/tests/config/disabled_functions_ret_type.ini b/src/tests/config/disabled_functions_ret_type.ini new file mode 100644 index 0000000..56c8e57 --- /dev/null +++ b/src/tests/config/disabled_functions_ret_type.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.disable_functions.function("strpos").ret_type("false").drop().alias("Return value is FALSE"); | |||
diff --git a/src/tests/config/disabled_functions_ret_type_double.ini b/src/tests/config/disabled_functions_ret_type_double.ini new file mode 100644 index 0000000..a1239d8 --- /dev/null +++ b/src/tests/config/disabled_functions_ret_type_double.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.disable_functions.function("cos").ret_type("double").drop().alias("Return value is a double"); | |||
diff --git a/src/tests/config/disabled_functions_ret_type_long.ini b/src/tests/config/disabled_functions_ret_type_long.ini new file mode 100644 index 0000000..6cccd4d --- /dev/null +++ b/src/tests/config/disabled_functions_ret_type_long.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.disable_functions.function("strlen").ret_type("long").drop().alias("Return value is a long"); | |||
diff --git a/src/tests/config/disabled_functions_ret_type_resource.ini b/src/tests/config/disabled_functions_ret_type_resource.ini new file mode 100644 index 0000000..e81cf2c --- /dev/null +++ b/src/tests/config/disabled_functions_ret_type_resource.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.disable_functions.function("fopen").ret_type("resource").drop().alias("Return value is a resource"); | |||
diff --git a/src/tests/config/disabled_functions_ret_type_str.ini b/src/tests/config/disabled_functions_ret_type_str.ini new file mode 100644 index 0000000..b3ff050 --- /dev/null +++ b/src/tests/config/disabled_functions_ret_type_str.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.disable_functions.function("substr").ret_type("string").drop().alias("Return value is a string"); | |||
diff --git a/src/tests/config/disabled_functions_ret_type_true.ini b/src/tests/config/disabled_functions_ret_type_true.ini new file mode 100644 index 0000000..02a37dd --- /dev/null +++ b/src/tests/config/disabled_functions_ret_type_true.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.disable_functions.function("is_numeric").ret_type("true").drop().alias("Return value is a true"); | |||
diff --git a/src/tests/config/disabled_functions_retval.ini b/src/tests/config/disabled_functions_retval.ini new file mode 100644 index 0000000..20422e4 --- /dev/null +++ b/src/tests/config/disabled_functions_retval.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.disable_functions.function("str_repeat").ret("fufufu").drop(); | |||
diff --git a/src/tests/config/disabled_functions_retval_rx.ini b/src/tests/config/disabled_functions_retval_rx.ini new file mode 100644 index 0000000..ca2bce3 --- /dev/null +++ b/src/tests/config/disabled_functions_retval_rx.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.disable_functions.function("str_repeat").ret_r("(fu){3}").drop(); | |||
diff --git a/src/tests/config/disabled_functions_zero_cidr.ini b/src/tests/config/disabled_functions_zero_cidr.ini new file mode 100644 index 0000000..bba1af9 --- /dev/null +++ b/src/tests/config/disabled_functions_zero_cidr.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.disable_functions.function("system").drop().cidr("0.0.0.0/0"); | |||
diff --git a/src/tests/config/dump_request.ini b/src/tests/config/dump_request.ini new file mode 100644 index 0000000..8c595f9 --- /dev/null +++ b/src/tests/config/dump_request.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.disable_functions.function("system").drop().dump("./dump_results/"); | |||
diff --git a/src/tests/config/dump_request_invalid_folder.ini b/src/tests/config/dump_request_invalid_folder.ini new file mode 100644 index 0000000..b5ae154 --- /dev/null +++ b/src/tests/config/dump_request_invalid_folder.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.disable_functions.function("system").drop().dump("/root/NON_EXISTENT/FOLDER/PLEASE/"); | |||
diff --git a/src/tests/config/empty.ini b/src/tests/config/empty.ini new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/tests/config/empty.ini | |||
diff --git a/src/tests/config/empty_conf.ini b/src/tests/config/empty_conf.ini new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/tests/config/empty_conf.ini | |||
diff --git a/src/tests/config/encryption_key_only.ini b/src/tests/config/encryption_key_only.ini new file mode 100644 index 0000000..7de4438 --- /dev/null +++ b/src/tests/config/encryption_key_only.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.global.secret_key("abcdef"); | |||
diff --git a/src/tests/config/global_strict.ini b/src/tests/config/global_strict.ini new file mode 100644 index 0000000..2bc2bdc --- /dev/null +++ b/src/tests/config/global_strict.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.global_strict.enable(); | |||
diff --git a/src/tests/config/global_strict_disabled.ini b/src/tests/config/global_strict_disabled.ini new file mode 100644 index 0000000..2e68471 --- /dev/null +++ b/src/tests/config/global_strict_disabled.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.global_strict.disable(); | |||
diff --git a/src/tests/config/harden_rand.ini b/src/tests/config/harden_rand.ini new file mode 100644 index 0000000..89e19be --- /dev/null +++ b/src/tests/config/harden_rand.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.harden_random.enable(); | |||
diff --git a/src/tests/config/upload_validation.ini b/src/tests/config/upload_validation.ini new file mode 100644 index 0000000..0646134 --- /dev/null +++ b/src/tests/config/upload_validation.ini | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | sp.upload_validation.script("tests/upload_ko.sh"); | ||
| 2 | sp.upload_validation.enable(); | ||
diff --git a/src/tests/config/upload_validation_invalid.ini b/src/tests/config/upload_validation_invalid.ini new file mode 100644 index 0000000..7a638a1 --- /dev/null +++ b/src/tests/config/upload_validation_invalid.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.upload_validation.script("./tests/data/upload_invalid.sh").enable(); | |||
diff --git a/src/tests/config/upload_validation_ko.ini b/src/tests/config/upload_validation_ko.ini new file mode 100644 index 0000000..b15977f --- /dev/null +++ b/src/tests/config/upload_validation_ko.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.upload_validation.script("./tests/data/upload_ko.sh").enable(); | |||
diff --git a/src/tests/config/upload_validation_ko_simulation.ini b/src/tests/config/upload_validation_ko_simulation.ini new file mode 100644 index 0000000..da56439 --- /dev/null +++ b/src/tests/config/upload_validation_ko_simulation.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.upload_validation.script("./tests/data/upload_ko.sh").enable().simulation(); | |||
diff --git a/src/tests/config/upload_validation_no_exist.ini b/src/tests/config/upload_validation_no_exist.ini new file mode 100644 index 0000000..24f81a5 --- /dev/null +++ b/src/tests/config/upload_validation_no_exist.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.upload_validation.script("fufufufufu").enable(); | |||
diff --git a/src/tests/config/upload_validation_non_exec.ini b/src/tests/config/upload_validation_non_exec.ini new file mode 100644 index 0000000..bdf0a57 --- /dev/null +++ b/src/tests/config/upload_validation_non_exec.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.upload_validation.script("tests/data/upload_no_exec.sh").enable(); | |||
diff --git a/src/tests/config/upload_validation_ok.ini b/src/tests/config/upload_validation_ok.ini new file mode 100644 index 0000000..5df8db8 --- /dev/null +++ b/src/tests/config/upload_validation_ok.ini | |||
| @@ -0,0 +1 @@ | |||
| sp.upload_validation.script("./tests/data/upload_ok.sh").enable(); | |||
diff --git a/src/tests/data/upload_invalid.sh b/src/tests/data/upload_invalid.sh new file mode 100755 index 0000000..e5eb0c6 --- /dev/null +++ b/src/tests/data/upload_invalid.sh | |||
| @@ -0,0 +1 @@ | |||
| lulz | |||
diff --git a/src/tests/data/upload_ko.sh b/src/tests/data/upload_ko.sh new file mode 100755 index 0000000..c4cacdc --- /dev/null +++ b/src/tests/data/upload_ko.sh | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | #!/bin/sh | ||
| 2 | exit 1; | ||
diff --git a/src/tests/data/upload_no_exec.sh b/src/tests/data/upload_no_exec.sh new file mode 100644 index 0000000..6b9cafa --- /dev/null +++ b/src/tests/data/upload_no_exec.sh | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | #!/bin/sh | ||
| 2 | exit 0; | ||
diff --git a/src/tests/data/upload_ok.sh b/src/tests/data/upload_ok.sh new file mode 100755 index 0000000..6b9cafa --- /dev/null +++ b/src/tests/data/upload_ok.sh | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | #!/bin/sh | ||
| 2 | exit 0; | ||
diff --git a/src/tests/deny_writable_execution.phpt b/src/tests/deny_writable_execution.phpt new file mode 100644 index 0000000..2870561 --- /dev/null +++ b/src/tests/deny_writable_execution.phpt | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | --TEST-- | ||
| 2 | Readonly execution attempt | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php | ||
| 5 | if (!extension_loaded("snuffleupagus")) print "skip"; | ||
| 6 | |||
| 7 | $filename = __DIR__ . '/test.txt'; | ||
| 8 | |||
| 9 | @unlink($filename); | ||
| 10 | |||
| 11 | file_put_contents($filename, 'a'); | ||
| 12 | chmod($filename, 0400); | ||
| 13 | |||
| 14 | if (is_writable($filename)) print "skip"; | ||
| 15 | @unlink($filename); | ||
| 16 | ?> | ||
| 17 | --INI-- | ||
| 18 | sp.configuration_file={PWD}/config/config_disable_writable.ini | ||
| 19 | --FILE-- | ||
| 20 | <?php | ||
| 21 | $dir = __DIR__; | ||
| 22 | |||
| 23 | // just in case | ||
| 24 | @unlink("$dir/non_writable_file.txt"); | ||
| 25 | @unlink("$dir/writable_file.txt"); | ||
| 26 | |||
| 27 | file_put_contents("$dir/non_writable_file.txt", '<?php echo "Code execution within a non-writable file.\n";'); | ||
| 28 | file_put_contents("$dir/writable_file.txt", '<?php echo "Code execution within a writable file.\n";'); | ||
| 29 | chmod("$dir/non_writable_file.txt", 0400); | ||
| 30 | chmod("$dir/writable_file.txt", 0777); | ||
| 31 | include "$dir/non_writable_file.txt"; | ||
| 32 | include "$dir/writable_file.txt"; | ||
| 33 | ?> | ||
| 34 | --EXPECTF-- | ||
| 35 | Code execution within a non-writable file. | ||
| 36 | [snuffleupagus][0.0.0.0][readonly_exec][drop] Attempted execution of a writable file (%a/writable_file.txt). | ||
| 37 | --CLEAN-- | ||
| 38 | <?php | ||
| 39 | $dir = __DIR__; | ||
| 40 | chmod("$dir/non_writable_file.txt", 0777); | ||
| 41 | chmod("$dir/writable_file.txt", 0777); | ||
| 42 | unlink("$dir/non_writable_file.txt"); | ||
| 43 | unlink("$dir/writable_file.txt"); | ||
| 44 | ?> \ No newline at end of file | ||
diff --git a/src/tests/deny_writable_execution_disabled.phpt b/src/tests/deny_writable_execution_disabled.phpt new file mode 100644 index 0000000..6d1233b --- /dev/null +++ b/src/tests/deny_writable_execution_disabled.phpt | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | --TEST-- | ||
| 2 | Readonly execution attempt | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_disable_writable_disabled.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | $dir = __DIR__; | ||
| 10 | |||
| 11 | // just in case | ||
| 12 | @unlink("$dir/non_writable_file.txt"); | ||
| 13 | @unlink("$dir/writable_file.txt"); | ||
| 14 | |||
| 15 | file_put_contents("$dir/writable_file.txt", '<?php echo "Code execution within a writable file.\n";'); | ||
| 16 | file_put_contents("$dir/non_writable_file.txt", '<?php echo "Code execution within a non-writable file.\n";'); | ||
| 17 | chmod("$dir/writable_file.txt", 0777); | ||
| 18 | chmod("$dir/non_writable_file.txt", 0400); | ||
| 19 | include "$dir/writable_file.txt"; | ||
| 20 | include "$dir/non_writable_file.txt"; | ||
| 21 | ?> | ||
| 22 | --EXPECT-- | ||
| 23 | Code execution within a writable file. | ||
| 24 | Code execution within a non-writable file. | ||
| 25 | --CLEAN-- | ||
| 26 | <?php | ||
| 27 | $dir = __DIR__; | ||
| 28 | chmod("$dir/non_writable_file.txt", 0777); | ||
| 29 | chmod("$dir/writable_file.txt", 0777); | ||
| 30 | unlink("$dir/non_writable_file.txt"); | ||
| 31 | unlink("$dir/writable_file.txt"); | ||
| 32 | ?> \ No newline at end of file | ||
diff --git a/src/tests/deny_writable_execution_simulation.phpt b/src/tests/deny_writable_execution_simulation.phpt new file mode 100644 index 0000000..3278be8 --- /dev/null +++ b/src/tests/deny_writable_execution_simulation.phpt | |||
| @@ -0,0 +1,45 @@ | |||
| 1 | --TEST-- | ||
| 2 | Readonly execution attempt (simulation mode) | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php | ||
| 5 | if (!extension_loaded("snuffleupagus")) print "skip"; | ||
| 6 | |||
| 7 | $filename = __DIR__ . '/test.txt'; | ||
| 8 | |||
| 9 | @unlink($filename); | ||
| 10 | |||
| 11 | file_put_contents($filename, 'a'); | ||
| 12 | chmod($filename, 0400); | ||
| 13 | |||
| 14 | if (is_writable($filename)) print "skip";; | ||
| 15 | @unlink($filename); | ||
| 16 | ?> | ||
| 17 | --INI-- | ||
| 18 | sp.configuration_file={PWD}/config/config_disable_writable_simulation.ini | ||
| 19 | --FILE-- | ||
| 20 | <?php | ||
| 21 | $dir = __DIR__; | ||
| 22 | |||
| 23 | // just in case | ||
| 24 | @unlink("$dir/non_writable_file.txt"); | ||
| 25 | @unlink("$dir/writable_file.txt"); | ||
| 26 | |||
| 27 | file_put_contents("$dir/writable_file.txt", '<?php echo "Code execution within a writable file.\n";'); | ||
| 28 | file_put_contents("$dir/non_writable_file.txt", '<?php echo "Code execution within a non-writable file.\n";'); | ||
| 29 | chmod("$dir/writable_file.txt", 0777); | ||
| 30 | chmod("$dir/non_writable_file.txt", 0400); | ||
| 31 | include "$dir/writable_file.txt"; | ||
| 32 | include "$dir/non_writable_file.txt"; | ||
| 33 | ?> | ||
| 34 | --EXPECTF-- | ||
| 35 | [snuffleupagus][0.0.0.0][readonly_exec][notice] Attempted execution of a writable file (%a/writable_file.txt). | ||
| 36 | Code execution within a writable file. | ||
| 37 | Code execution within a non-writable file. | ||
| 38 | --CLEAN-- | ||
| 39 | <?php | ||
| 40 | $dir = __DIR__; | ||
| 41 | chmod("$dir/non_writable_file.txt", 0777); | ||
| 42 | chmod("$dir/writable_file.txt", 0777); | ||
| 43 | unlink("$dir/non_writable_file.txt"); | ||
| 44 | unlink("$dir/writable_file.txt"); | ||
| 45 | ?> \ No newline at end of file | ||
diff --git a/src/tests/disable_xxe_dom.phpt b/src/tests/disable_xxe_dom.phpt new file mode 100644 index 0000000..47f3db3 --- /dev/null +++ b/src/tests/disable_xxe_dom.phpt | |||
| @@ -0,0 +1,71 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable XXE | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php | ||
| 5 | if (!extension_loaded("snuffleupagus")) die "skip"; | ||
| 6 | if (!extension_loaded("dom")) die "skip"; | ||
| 7 | ?> | ||
| 8 | --INI-- | ||
| 9 | extension=`php-config --extension-dir`/dom.so | ||
| 10 | sp.configuration_file={PWD}/config/disable_xxe.ini | ||
| 11 | --FILE-- | ||
| 12 | <?php | ||
| 13 | $dir = __DIR__; | ||
| 14 | $content = 'WARNING, external entity loaded!'; | ||
| 15 | file_put_contents('content.txt', $content); | ||
| 16 | |||
| 17 | $xml = <<<EOD | ||
| 18 | <?xml version="1.0"?> | ||
| 19 | <!DOCTYPE root | ||
| 20 | [ | ||
| 21 | <!ENTITY foo SYSTEM "file://$dir/content.txt"> | ||
| 22 | ]> | ||
| 23 | <test><testing>&foo;</testing></test> | ||
| 24 | EOD; | ||
| 25 | |||
| 26 | file_put_contents('content.xml', $xml); | ||
| 27 | |||
| 28 | libxml_disable_entity_loader(true); | ||
| 29 | $dom = new DOMDocument('1.0'); | ||
| 30 | $dom->loadXML($xml, LIBXML_DTDATTR|LIBXML_DTDLOAD|LIBXML_NOENT); | ||
| 31 | printf("libxml_disable_entity to true: %s\n", $dom->getElementsByTagName('testing')->item(0)->nodeValue); | ||
| 32 | |||
| 33 | libxml_disable_entity_loader(false); | ||
| 34 | $dom = new DOMDocument('1.0'); | ||
| 35 | $dom->loadXML($xml, LIBXML_DTDATTR|LIBXML_DTDLOAD|LIBXML_NOENT); | ||
| 36 | printf("libxml_disable_entity to false: %s\n", $dom->getElementsByTagName('testing')->item(0)->nodeValue); | ||
| 37 | |||
| 38 | $xml = "<test><testing>foo</testing></test>"; | ||
| 39 | file_put_contents('content.xml', $xml); | ||
| 40 | |||
| 41 | libxml_disable_entity_loader(false); | ||
| 42 | $dom = new DOMDocument('1.0'); | ||
| 43 | $dom->loadXML($xml, LIBXML_DTDATTR|LIBXML_DTDLOAD|LIBXML_NOENT); | ||
| 44 | printf("without xxe: %s", $dom->getElementsByTagName('testing')->item(0)->nodeValue); | ||
| 45 | |||
| 46 | ?> | ||
| 47 | --EXPECTF-- | ||
| 48 | Warning: DOMDocument::loadXML(): I/O warning : failed to load external entity "file://%a/content.txt" in %a/disable_xxe_dom.php on line %d | ||
| 49 | |||
| 50 | Warning: DOMDocument::loadXML(): Failure to process entity foo in Entity, line: %d in %a/disable_xxe_dom.php on line %d | ||
| 51 | |||
| 52 | Warning: DOMDocument::loadXML(): Entity 'foo' not defined in Entity, line: %d in %a/disable_xxe_dom.php on line %d | ||
| 53 | |||
| 54 | Notice: Trying to get property of non-object in %a/disable_xxe_dom.php on line %d | ||
| 55 | libxml_disable_entity to true: | ||
| 56 | |||
| 57 | Warning: DOMDocument::loadXML(): I/O warning : failed to load external entity "file://%a/content.txt" in %a/disable_xxe_dom.php on line %d | ||
| 58 | |||
| 59 | Warning: DOMDocument::loadXML(): Failure to process entity foo in Entity, line: %d in %a/disable_xxe_dom.php on line %d | ||
| 60 | |||
| 61 | Warning: DOMDocument::loadXML(): Entity 'foo' not defined in Entity, line: %d in %a/disable_xxe_dom.php on line %d | ||
| 62 | |||
| 63 | Notice: Trying to get property of non-object in %a/disable_xxe_dom.php on line %d | ||
| 64 | libxml_disable_entity to false: | ||
| 65 | without xxe: foo | ||
| 66 | --CLEAN-- | ||
| 67 | <?php | ||
| 68 | $dir = __DIR__; | ||
| 69 | unlink($dir . "content.xml"); | ||
| 70 | unlink($dir . "content.txt"); | ||
| 71 | ?> | ||
diff --git a/src/tests/disable_xxe_dom_disabled.phpt b/src/tests/disable_xxe_dom_disabled.phpt new file mode 100644 index 0000000..b89b595 --- /dev/null +++ b/src/tests/disable_xxe_dom_disabled.phpt | |||
| @@ -0,0 +1,56 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable XXE | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php | ||
| 5 | if (!extension_loaded("snuffleupagus")) die "skip"; | ||
| 6 | if (!extension_loaded("dom")) die "skip"; | ||
| 7 | ?> | ||
| 8 | --INI-- | ||
| 9 | extension=`php-config --extension-dir`/dom.so | ||
| 10 | sp.configuration_file={PWD}/config/disable_xxe_disable.ini | ||
| 11 | --FILE-- | ||
| 12 | <?php | ||
| 13 | $dir = __DIR__; | ||
| 14 | $content = '<content>WARNING, external entity loaded!</content>'; | ||
| 15 | file_put_contents($dir . '/content.txt', $content); | ||
| 16 | |||
| 17 | $xml = <<<EOD | ||
| 18 | <?xml version="1.0"?> | ||
| 19 | <!DOCTYPE root | ||
| 20 | [ | ||
| 21 | <!ENTITY foo SYSTEM "file://$dir/content.txt"> | ||
| 22 | ]> | ||
| 23 | <test><testing>&foo;</testing></test> | ||
| 24 | EOD; | ||
| 25 | |||
| 26 | file_put_contents($dir . '/content.xml', $xml); | ||
| 27 | |||
| 28 | libxml_disable_entity_loader(true); | ||
| 29 | $dom = new DOMDocument('1.0'); | ||
| 30 | $dom->loadXML($xml, LIBXML_DTDATTR|LIBXML_DTDLOAD|LIBXML_NOENT); | ||
| 31 | printf("libxml_disable_entity to true: %s\n", $dom->getElementsByTagName('testing')->item(0)->nodeValue); | ||
| 32 | |||
| 33 | libxml_disable_entity_loader(false); | ||
| 34 | $dom = new DOMDocument('1.0'); | ||
| 35 | $dom->loadXML($xml, LIBXML_DTDATTR|LIBXML_DTDLOAD|LIBXML_NOENT); | ||
| 36 | printf("libxml_disable_entity to false: %s\n", $dom->getElementsByTagName('testing')->item(0)->nodeValue); | ||
| 37 | |||
| 38 | $xml = "<test><testing>foo</testing></test>"; | ||
| 39 | file_put_contents('content.xml', $xml); | ||
| 40 | |||
| 41 | libxml_disable_entity_loader(false); | ||
| 42 | $dom = new DOMDocument('1.0'); | ||
| 43 | $dom->loadXML($xml, LIBXML_DTDATTR|LIBXML_DTDLOAD|LIBXML_NOENT); | ||
| 44 | printf("without xxe: %s", $dom->getElementsByTagName('testing')->item(0)->nodeValue); | ||
| 45 | |||
| 46 | ?> | ||
| 47 | --EXPECTF-- | ||
| 48 | libxml_disable_entity to true: WARNING, external entity loaded! | ||
| 49 | libxml_disable_entity to false: WARNING, external entity loaded! | ||
| 50 | without xxe: foo | ||
| 51 | --CLEAN-- | ||
| 52 | <?php | ||
| 53 | $dir = __DIR__; | ||
| 54 | unlink($dir . "/content.xml"); | ||
| 55 | unlink($dir . "/content.txt"); | ||
| 56 | ?> | ||
diff --git a/src/tests/disable_xxe_simplexml.phpt b/src/tests/disable_xxe_simplexml.phpt new file mode 100644 index 0000000..54404a3 --- /dev/null +++ b/src/tests/disable_xxe_simplexml.phpt | |||
| @@ -0,0 +1,52 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable XXE | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php | ||
| 5 | if (!extension_loaded("snuffleupagus")) die "skip"; | ||
| 6 | if (!extension_loaded("simplexml")) die "skip"; | ||
| 7 | ?> | ||
| 8 | --INI-- | ||
| 9 | extension=`php-config --extension-dir`/simplexml.so | ||
| 10 | sp.configuration_file={PWD}/config/disable_xxe.ini | ||
| 11 | --FILE-- | ||
| 12 | <?php | ||
| 13 | $dir = __DIR__; | ||
| 14 | $content = 'WARNING, external entity loaded!'; | ||
| 15 | file_put_contents('content.txt', $content); | ||
| 16 | |||
| 17 | $xml = <<<EOD | ||
| 18 | <?xml version="1.0"?> | ||
| 19 | <!DOCTYPE root | ||
| 20 | [ | ||
| 21 | <!ENTITY foo SYSTEM "file://$dir/content.txt"> | ||
| 22 | ]> | ||
| 23 | <test><testing>&foo;</testing></test> | ||
| 24 | EOD; | ||
| 25 | |||
| 26 | file_put_contents('content.xml', $xml); | ||
| 27 | |||
| 28 | libxml_disable_entity_loader(true); | ||
| 29 | $doc = new SimpleXMLElement($xml); | ||
| 30 | printf("libxml_disable_entity to true: %s\n", $doc->testing); | ||
| 31 | |||
| 32 | libxml_disable_entity_loader(false); | ||
| 33 | $doc = new SimpleXMLElement($xml); | ||
| 34 | printf("libxml_disable_entity to false: %s\n", $doc->testing); | ||
| 35 | |||
| 36 | $xml = "<test><testing>foo</testing></test>"; | ||
| 37 | file_put_contents('content.xml', $xml); | ||
| 38 | |||
| 39 | $doc = new SimpleXMLElement($xml); | ||
| 40 | printf("without xxe: %s", $doc->testing); | ||
| 41 | |||
| 42 | ?> | ||
| 43 | --EXPECT-- | ||
| 44 | libxml_disable_entity to true: | ||
| 45 | libxml_disable_entity to false: | ||
| 46 | without xxe: foo | ||
| 47 | --CLEAN-- | ||
| 48 | <?php | ||
| 49 | $dir = __DIR__; | ||
| 50 | unlink($dir . "/content.xml"); | ||
| 51 | unlink($dir . "/content.txt"); | ||
| 52 | ?> | ||
diff --git a/src/tests/disable_xxe_simplexml_oop.phpt b/src/tests/disable_xxe_simplexml_oop.phpt new file mode 100644 index 0000000..62762eb --- /dev/null +++ b/src/tests/disable_xxe_simplexml_oop.phpt | |||
| @@ -0,0 +1,52 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable XXE | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php | ||
| 5 | if (!extension_loaded("snuffleupagus")) die "skip"; | ||
| 6 | if (!extension_loaded("simplexml")) die "skip"; | ||
| 7 | ?> | ||
| 8 | --INI-- | ||
| 9 | extension=`php-config --extension-dir`/simplexml.so | ||
| 10 | sp.configuration_file={PWD}/config/disable_xxe.ini | ||
| 11 | --FILE-- | ||
| 12 | <?php | ||
| 13 | $dir = __DIR__; | ||
| 14 | $content = 'WARNING, external entity loaded!'; | ||
| 15 | file_put_contents('content.txt', $content); | ||
| 16 | |||
| 17 | $xml = <<<EOD | ||
| 18 | <?xml version="1.0"?> | ||
| 19 | <!DOCTYPE root | ||
| 20 | [ | ||
| 21 | <!ENTITY foo SYSTEM "file://$dir/content.txt"> | ||
| 22 | ]> | ||
| 23 | <test><testing>&foo;</testing></test> | ||
| 24 | EOD; | ||
| 25 | |||
| 26 | file_put_contents('content.xml', $xml); | ||
| 27 | |||
| 28 | libxml_disable_entity_loader(true); | ||
| 29 | $doc = simplexml_load_string($xml); | ||
| 30 | printf("libxml_disable_entity to true: %s\n", $doc->testing); | ||
| 31 | |||
| 32 | libxml_disable_entity_loader(false); | ||
| 33 | $doc = simplexml_load_string($xml); | ||
| 34 | printf("libxml_disable_entity to false: %s\n", $doc->testing); | ||
| 35 | |||
| 36 | $xml = "<test><testing>foo</testing></test>"; | ||
| 37 | file_put_contents('content.xml', $xml); | ||
| 38 | |||
| 39 | $doc = simplexml_load_string($xml); | ||
| 40 | printf("without xxe: %s", $doc->testing); | ||
| 41 | |||
| 42 | ?> | ||
| 43 | --EXPECT-- | ||
| 44 | libxml_disable_entity to true: | ||
| 45 | libxml_disable_entity to false: | ||
| 46 | without xxe: foo | ||
| 47 | --CLEAN-- | ||
| 48 | <?php | ||
| 49 | $dir = __DIR__; | ||
| 50 | unlink($dir . "/content.xml"); | ||
| 51 | unlink($dir . "/content.txt"); | ||
| 52 | ?> | ||
diff --git a/src/tests/disable_xxe_xml_parse.phpt b/src/tests/disable_xxe_xml_parse.phpt new file mode 100644 index 0000000..944bc38 --- /dev/null +++ b/src/tests/disable_xxe_xml_parse.phpt | |||
| @@ -0,0 +1,104 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable XXE | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php | ||
| 5 | if (!extension_loaded("snuffleupagus")) die "skip"; | ||
| 6 | if (!extension_loaded("xml")) die "skip"; | ||
| 7 | ?> | ||
| 8 | --INI-- | ||
| 9 | extension=`php-config --extension-dir`/xml.so | ||
| 10 | sp.configuration_file={PWD}/config/disable_xxe.ini | ||
| 11 | --FILE-- | ||
| 12 | <?php | ||
| 13 | $dir = __DIR__; | ||
| 14 | $content = 'WARNING, external entity loaded!'; | ||
| 15 | file_put_contents('content.txt', $content); | ||
| 16 | |||
| 17 | $xml = <<<EOD | ||
| 18 | <?xml version="1.0"?> | ||
| 19 | <!DOCTYPE root | ||
| 20 | [ | ||
| 21 | <!ENTITY foo SYSTEM "file://$dir/content.txt"> | ||
| 22 | ]> | ||
| 23 | <test><testing>&foo;</testing></test> | ||
| 24 | EOD; | ||
| 25 | |||
| 26 | file_put_contents('content.xml', $xml); | ||
| 27 | |||
| 28 | function create_parser() { | ||
| 29 | $parser = xml_parser_create(); | ||
| 30 | xml_set_element_handler( | ||
| 31 | $parser, | ||
| 32 | function($parser, $name, array $attributes) { | ||
| 33 | var_dump($name); | ||
| 34 | echo "\n"; | ||
| 35 | var_dump($attributes); | ||
| 36 | }, | ||
| 37 | function($parser, $name) { | ||
| 38 | var_dump($name); | ||
| 39 | } | ||
| 40 | ); | ||
| 41 | |||
| 42 | xml_set_character_data_handler( | ||
| 43 | $parser, | ||
| 44 | function ($parser, $text){ | ||
| 45 | echo 'text' . $text; | ||
| 46 | } | ||
| 47 | ); | ||
| 48 | |||
| 49 | return $parser; | ||
| 50 | } | ||
| 51 | |||
| 52 | libxml_disable_entity_loader(true); | ||
| 53 | $parser = create_parser(); | ||
| 54 | $doc = xml_parse($parser, $xml, true); | ||
| 55 | xml_parser_free($parser); | ||
| 56 | |||
| 57 | libxml_disable_entity_loader(false); | ||
| 58 | $parser = create_parser(); | ||
| 59 | $doc = xml_parse($parser, $xml, true); | ||
| 60 | xml_parser_free($parser); | ||
| 61 | |||
| 62 | $xml = "<test><testing>foo</testing></test>"; | ||
| 63 | file_put_contents('content.xml', $xml); | ||
| 64 | $parser = create_parser(); | ||
| 65 | $doc = xml_parse($parser, $xml, true); | ||
| 66 | xml_parser_free($parser); | ||
| 67 | |||
| 68 | --EXPECT-- | ||
| 69 | string(4) "TEST" | ||
| 70 | |||
| 71 | array(0) { | ||
| 72 | } | ||
| 73 | string(7) "TESTING" | ||
| 74 | |||
| 75 | array(0) { | ||
| 76 | } | ||
| 77 | string(7) "TESTING" | ||
| 78 | string(4) "TEST" | ||
| 79 | string(4) "TEST" | ||
| 80 | |||
| 81 | array(0) { | ||
| 82 | } | ||
| 83 | string(7) "TESTING" | ||
| 84 | |||
| 85 | array(0) { | ||
| 86 | } | ||
| 87 | string(7) "TESTING" | ||
| 88 | string(4) "TEST" | ||
| 89 | string(4) "TEST" | ||
| 90 | |||
| 91 | array(0) { | ||
| 92 | } | ||
| 93 | string(7) "TESTING" | ||
| 94 | |||
| 95 | array(0) { | ||
| 96 | } | ||
| 97 | textfoostring(7) "TESTING" | ||
| 98 | string(4) "TEST" | ||
| 99 | --CLEAN-- | ||
| 100 | <?php | ||
| 101 | $dir = __DIR__; | ||
| 102 | unlink($dir . "/content.xml"); | ||
| 103 | unlink($dir . "/content.txt"); | ||
| 104 | ?> | ||
diff --git a/src/tests/disabled_function_local_var.phpt b/src/tests/disabled_function_local_var.phpt new file mode 100644 index 0000000..3142039 --- /dev/null +++ b/src/tests/disabled_function_local_var.phpt | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable functions - match on a local variable | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/disabled_function_local_var.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | $a = 1338; | ||
| 10 | function test(){ | ||
| 11 | echo strlen("id") . "\n"; | ||
| 12 | } | ||
| 13 | echo "Value of a: $a\n"; | ||
| 14 | test(); | ||
| 15 | |||
| 16 | $a = 1337; | ||
| 17 | echo "Value of a: $a\n"; | ||
| 18 | test(); | ||
| 19 | ?> | ||
| 20 | --EXPECTF-- | ||
| 21 | Value of a: 1338 | ||
| 22 | 2 | ||
| 23 | Value of a: 1337 | ||
| 24 | [snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'strlen' in %a/tests/disabled_function_local_var.php:%d has been disabled. \ No newline at end of file | ||
diff --git a/src/tests/disabled_function_super_global_var.phpt b/src/tests/disabled_function_super_global_var.phpt new file mode 100644 index 0000000..d41897a --- /dev/null +++ b/src/tests/disabled_function_super_global_var.phpt | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable functions - match on a super global | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/disabled_function_super_global_var.ini | ||
| 7 | --GET-- | ||
| 8 | bla=test | ||
| 9 | --FILE-- | ||
| 10 | <?php | ||
| 11 | function test(){ | ||
| 12 | echo strlen($_GET['bla']) . "\n"; | ||
| 13 | } | ||
| 14 | test(); | ||
| 15 | $_GET['bla'] = 'test2'; | ||
| 16 | test(); | ||
| 17 | ?> | ||
| 18 | --EXPECTF-- | ||
| 19 | 4 | ||
| 20 | [snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'strlen' in %s/tests/disabled_function_super_global_var.php:%d has been disabled. | ||
diff --git a/src/tests/disabled_functions.phpt b/src/tests/disabled_functions.phpt new file mode 100644 index 0000000..37da911 --- /dev/null +++ b/src/tests/disabled_functions.phpt | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable functions | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/disabled_functions.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | system("id"); | ||
| 10 | printf("printf in simulation mode\n"); | ||
| 11 | print("print in disabled mode\n"); | ||
| 12 | var_dump("this is a super test"); | ||
| 13 | echo strpos("pouet", "o"); | ||
| 14 | ?> | ||
| 15 | --EXPECTF-- | ||
| 16 | [snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'system' in %a/tests/disabled_functions.php:%d has been disabled. | ||
| 17 | [snuffleupagus][0.0.0.0][disabled_function][notice] The call to the function 'printf' in %a/tests/disabled_functions.php:%d has been disabled. | ||
| 18 | printf in simulation mode | ||
| 19 | print in disabled mode | ||
| 20 | [snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'var_dump' in %a/tests/disabled_functions.php:%d has been disabled. | ||
| 21 | 1 | ||
diff --git a/src/tests/disabled_functions_cidr.phpt b/src/tests/disabled_functions_cidr.phpt new file mode 100644 index 0000000..5b13107 --- /dev/null +++ b/src/tests/disabled_functions_cidr.phpt | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable functions | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --ENV-- | ||
| 6 | return <<<EOF | ||
| 7 | REMOTE_ADDR=127.0.0.1 | ||
| 8 | EOF; | ||
| 9 | --INI-- | ||
| 10 | sp.configuration_file={PWD}/config/disabled_functions_cidr.ini | ||
| 11 | --FILE-- | ||
| 12 | <?php | ||
| 13 | system("echo 42"); | ||
| 14 | printf("1337"); | ||
| 15 | ?> | ||
| 16 | --EXPECTF-- | ||
| 17 | [snuffleupagus][127.0.0.1][disabled_function][drop] The call to the function 'system' in %a/tests/disabled_functions_cidr.php:2 has been disabled. | ||
| 18 | 1337 | ||
diff --git a/src/tests/disabled_functions_cidr_6.phpt b/src/tests/disabled_functions_cidr_6.phpt new file mode 100644 index 0000000..f2c5f5a --- /dev/null +++ b/src/tests/disabled_functions_cidr_6.phpt | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable functions | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --ENV-- | ||
| 6 | return <<<EOF | ||
| 7 | REMOTE_ADDR=2001:0db8:0000:0000:0000:ff00:0042:8328 | ||
| 8 | EOF; | ||
| 9 | --INI-- | ||
| 10 | sp.configuration_file={PWD}/config/disabled_functions_cidr.ini | ||
| 11 | --FILE-- | ||
| 12 | <?php | ||
| 13 | strpos("a", "b"); | ||
| 14 | printf(1337); | ||
| 15 | ?> | ||
| 16 | --EXPECTF-- | ||
| 17 | [snuffleupagus][2001:0db8:0000:0000:0000:ff00:0042:8328][disabled_function][drop] The call to the function 'strpos' in %a/tests/disabled_functions_cidr_6.php:2 has been disabled. | ||
| 18 | 1337 | ||
diff --git a/src/tests/disabled_functions_filename_r.phpt b/src/tests/disabled_functions_filename_r.phpt new file mode 100644 index 0000000..ed46802 --- /dev/null +++ b/src/tests/disabled_functions_filename_r.phpt | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable functions - filename regexp | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_disabled_functions_filename_r.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | system("echo 42"); | ||
| 10 | shell_exec("echo 43"); | ||
| 11 | ?> | ||
| 12 | --EXPECTF-- | ||
| 13 | 42 | ||
| 14 | [snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'shell_exec' in %a/tests/disabled_functions_filename_r.php:%d has been disabled. \ No newline at end of file | ||
diff --git a/src/tests/disabled_functions_mb.phpt b/src/tests/disabled_functions_mb.phpt new file mode 100644 index 0000000..7089063 --- /dev/null +++ b/src/tests/disabled_functions_mb.phpt | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable functions | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/disabled_functions_mb.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | echo strlen("id"); | ||
| 10 | ?> | ||
| 11 | --EXPECTF-- | ||
| 12 | [snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'strlen' in %a/tests/disabled_functions_mb.php:2 has been disabled. | ||
diff --git a/src/tests/disabled_functions_method.phpt b/src/tests/disabled_functions_method.phpt new file mode 100644 index 0000000..33651b7 --- /dev/null +++ b/src/tests/disabled_functions_method.phpt | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable functions | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_disabled_functions_method.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | class AwesomeClass { | ||
| 10 | function method1($a) { | ||
| 11 | echo "method1:" . $a . "\n"; | ||
| 12 | } | ||
| 13 | function method2($a) { | ||
| 14 | echo "method2:" . $a . "\n"; | ||
| 15 | } | ||
| 16 | function method3($a) { | ||
| 17 | echo "method3:" . $a . "\n"; | ||
| 18 | } | ||
| 19 | } | ||
| 20 | |||
| 21 | $c = new AwesomeClass(); | ||
| 22 | $c->method1("pif"); | ||
| 23 | $c->method2("paf"); | ||
| 24 | $c->method3("pouet"); | ||
| 25 | ?> | ||
| 26 | --EXPECTF-- | ||
| 27 | [snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'AwesomeClass::method1' in %a/tests/disabled_functions_method.php:4 has been disabled. | ||
| 28 | method2:paf | ||
| 29 | [snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'AwesomeClass::method3' in %a/tests/disabled_functions_method.php:10 has been disabled, because its argument 'a' content (pouet) matched a rule. | ||
diff --git a/src/tests/disabled_functions_name_r.phpt b/src/tests/disabled_functions_name_r.phpt new file mode 100644 index 0000000..0e29abb --- /dev/null +++ b/src/tests/disabled_functions_name_r.phpt | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable functions | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_disabled_functions_name_r.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | system("echo 42"); | ||
| 10 | system("echo 1337"); | ||
| 11 | ?> | ||
| 12 | --EXPECTF-- | ||
| 13 | 42 | ||
| 14 | 1337 | ||
| 15 | [snuffleupagus][0.0.0.0][disabled_function][drop] The execution has been aborted in %a/disabled_functions_name_r.php:3, because the return value (1337) of the function 'system' matched a rule. | ||
diff --git a/src/tests/disabled_functions_name_type.phpt b/src/tests/disabled_functions_name_type.phpt new file mode 100644 index 0000000..c5b24d6 --- /dev/null +++ b/src/tests/disabled_functions_name_type.phpt | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable functions | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_disabled_functions_name_type.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | echo strcmp("pouet", "pouet") . "\n"; | ||
| 10 | echo strcmp([1,23], "pouet") . "\n"; | ||
| 11 | ?> | ||
| 12 | --EXPECTF-- | ||
| 13 | 0 | ||
| 14 | [snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'strcmp' in %a/disabled_functions_name_type.php:%d has been disabled, because its argument 'str1' content (?) matched a rule. | ||
diff --git a/src/tests/disabled_functions_namespace.phpt b/src/tests/disabled_functions_namespace.phpt new file mode 100644 index 0000000..72c7d0b --- /dev/null +++ b/src/tests/disabled_functions_namespace.phpt | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable functions: namespaces support isn't implemented now | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_disabled_functions_namespace.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | namespace my_super_namespace { | ||
| 10 | function my_function() { | ||
| 11 | echo "1\n"; | ||
| 12 | } | ||
| 13 | } | ||
| 14 | namespace my_second_namespace { | ||
| 15 | function my_function() { | ||
| 16 | echo "2\n"; | ||
| 17 | } | ||
| 18 | } | ||
| 19 | namespace { | ||
| 20 | function my_function() { | ||
| 21 | echo "3\n"; | ||
| 22 | } | ||
| 23 | \strcmp("1", "2"); | ||
| 24 | \my_super_namespace\my_function(); | ||
| 25 | \my_second_namespace\my_function(); | ||
| 26 | my_function(); | ||
| 27 | } | ||
| 28 | ?> | ||
| 29 | --XFAIL-- | ||
| 30 | --EXPECTF-- | ||
| 31 | [snuffleupagus] The call to the function 'strcmp' in %a/tests/disabled_functions_namespace.php:%d has been disabled. | ||
diff --git a/src/tests/disabled_functions_noconf.phpt b/src/tests/disabled_functions_noconf.phpt new file mode 100644 index 0000000..cb13413 --- /dev/null +++ b/src/tests/disabled_functions_noconf.phpt | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable functions | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/empty.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | echo strpos("pouet", "o"); | ||
| 10 | ?> | ||
| 11 | --EXPECT-- | ||
| 12 | 1 | ||
diff --git a/src/tests/disabled_functions_nul_byte.phpt b/src/tests/disabled_functions_nul_byte.phpt new file mode 100644 index 0000000..95e87de --- /dev/null +++ b/src/tests/disabled_functions_nul_byte.phpt | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable functions with nul byte | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_disabled_functions_nul_byte.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | system("\0id"); | ||
| 10 | system("id"); | ||
| 11 | |||
| 12 | ?> | ||
| 13 | --EXPECTF-- | ||
| 14 | [snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'system' in %a/tests/disabled_functions_nul_byte.php:2 has been disabled, because its argument 'command' content (0id) matched a rule. | ||
| 15 | [snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'system' in %a/tests/disabled_functions_nul_byte.php:3 has been disabled, because its argument 'command' content (id) matched a rule. \ No newline at end of file | ||
diff --git a/src/tests/disabled_functions_param.phpt b/src/tests/disabled_functions_param.phpt new file mode 100644 index 0000000..2309217 --- /dev/null +++ b/src/tests/disabled_functions_param.phpt | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable functions | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_disabled_functions_param.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | system("id"); | ||
| 10 | system("echo win"); | ||
| 11 | var_dump(array_sum([1,2,3,4,5])); | ||
| 12 | shell_exec("id"); | ||
| 13 | echo shell_exec("echo 42"); | ||
| 14 | strcmp("bla", "ble"); | ||
| 15 | strncmp("bla", "ble", 2); | ||
| 16 | ?> | ||
| 17 | --EXPECTF-- | ||
| 18 | [snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'system' in %a/disabled_functions_param.php:2 has been disabled, because its argument 'command' content (id) matched the rule '1'. | ||
| 19 | win | ||
| 20 | int(15) | ||
| 21 | [snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'shell_exec' in %a/disabled_functions_param.php:5 has been disabled, because its argument 'cmd' content (id) matched the rule '3'. | ||
| 22 | 42 | ||
| 23 | [snuffleupagus][0.0.0.0][disabled_function][notice] The call to the function 'strcmp' in %a/tests/disabled_functions_param.php:7 has been disabled, because its argument 'str1' content (bla) matched the rule '5'. | ||
| 24 | [snuffleupagus][0.0.0.0][disabled_function][notice] The call to the function 'strncmp' in %a/tests/disabled_functions_param.php:8 has been disabled, because its argument 'str1' content (bla) matched a rule. | ||
diff --git a/src/tests/disabled_functions_param_alias.phpt b/src/tests/disabled_functions_param_alias.phpt new file mode 100644 index 0000000..fe3d1c1 --- /dev/null +++ b/src/tests/disabled_functions_param_alias.phpt | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable functions - alias | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_disabled_functions_param_alias.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | system("id"); | ||
| 10 | shell_exec("id"); | ||
| 11 | ?> | ||
| 12 | --EXPECTF-- | ||
| 13 | [snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'system' in %a/tests/disabled_functions_param_alias.php:2 has been disabled, because of the the rule '1'. | ||
| 14 | [snuffleupagus][0.0.0.0][disabled_function][notice] The call to the function 'shell_exec' in %a/tests/disabled_functions_param_alias.php:3 has been disabled, because of the the rule '2'. | ||
diff --git a/src/tests/disabled_functions_param_allow.phpt b/src/tests/disabled_functions_param_allow.phpt new file mode 100644 index 0000000..b6ff01a --- /dev/null +++ b/src/tests/disabled_functions_param_allow.phpt | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable functions - allow | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_disabled_functions_param_allow.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | system("echo win"); | ||
| 10 | system("id"); | ||
| 11 | ?> | ||
| 12 | --EXPECTF-- | ||
| 13 | win | ||
| 14 | [snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'system' in %a/tests/disabled_functions_param_allow.php:3 has been disabled. \ No newline at end of file | ||
diff --git a/src/tests/disabled_functions_param_array.phpt b/src/tests/disabled_functions_param_array.phpt new file mode 100644 index 0000000..6596d1a --- /dev/null +++ b/src/tests/disabled_functions_param_array.phpt | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable functions | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_disabled_functions_param_array.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | function foo($arr) { | ||
| 10 | echo $arr["a"]."\n"; | ||
| 11 | } | ||
| 12 | $a=Array("a"=>"test1"); | ||
| 13 | foo($a); | ||
| 14 | $a=Array("a"=>"abcd"); | ||
| 15 | foo($a); | ||
| 16 | $a=Array("a"=>"abcde"); | ||
| 17 | foo($a); | ||
| 18 | $a=Array("bla"=>"abcdef"); | ||
| 19 | foo($a); | ||
| 20 | $a=Array("bla"=>"aaa", "a"=>"eee" ); | ||
| 21 | foo($a); | ||
| 22 | $a=Array("test"=>"aaa", "a"=>"fff" ); | ||
| 23 | foo($a); | ||
| 24 | $a=Array("test2"=>Array("foo"=>Array("lol"=>"bbb")), "a"=>"cccc"); | ||
| 25 | foo($a); | ||
| 26 | $a=Array("test2"=>Array("foo"=>Array("lol"=>"aaa")), "a"=>"dddd"); | ||
| 27 | foo($a); | ||
| 28 | ?> | ||
| 29 | --EXPECTF-- | ||
| 30 | test1 | ||
| 31 | [snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'foo' in %a/disabled_functions_param_array.php:3 has been disabled, because its argument 'arr' content (Array) matched the rule '1'. | ||
| 32 | abcde | ||
| 33 | [snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'foo' in %a/disabled_functions_param_array.php:3 has been disabled, because its argument 'arr' content (Array) matched the rule '2'. | ||
| 34 | eee | ||
| 35 | [snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'foo' in %a/disabled_functions_param_array.php:3 has been disabled, because its argument 'arr' content (Array) matched the rule '3'. | ||
| 36 | cccc | ||
| 37 | [snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'foo' in %a/disabled_functions_param_array.php:3 has been disabled, because its argument 'arr' content (Array) matched the rule '4'. | ||
diff --git a/src/tests/disabled_functions_param_int.phpt b/src/tests/disabled_functions_param_int.phpt new file mode 100644 index 0000000..3b2cc08 --- /dev/null +++ b/src/tests/disabled_functions_param_int.phpt | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable functions | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_disabled_functions_param_int.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | function foobar($id) { | ||
| 10 | echo $id."\n"; | ||
| 11 | } | ||
| 12 | foobar(1); | ||
| 13 | foobar(42); | ||
| 14 | foobar(1337); | ||
| 15 | foobar(13374242); | ||
| 16 | foobar(0x2A); | ||
| 17 | foobar("10"); | ||
| 18 | ?> | ||
| 19 | --EXPECTF-- | ||
| 20 | 1 | ||
| 21 | [snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'foobar' in %a/tests/disabled_functions_param_int.php:3 has been disabled, because its argument 'id' content (42) matched a rule. | ||
| 22 | [snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'foobar' in %a/tests/disabled_functions_param_int.php:3 has been disabled, because its argument 'id' content (1337) matched a rule. | ||
| 23 | [snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'foobar' in %a/tests/disabled_functions_param_int.php:3 has been disabled, because its argument 'id' content (13374242) matched a rule. | ||
| 24 | [snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'foobar' in %a/tests/disabled_functions_param_int.php:3 has been disabled, because its argument 'id' content (42) matched a rule. | ||
| 25 | 10 | ||
diff --git a/src/tests/disabled_functions_param_r.phpt b/src/tests/disabled_functions_param_r.phpt new file mode 100644 index 0000000..3708881 --- /dev/null +++ b/src/tests/disabled_functions_param_r.phpt | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable functions | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_disabled_functions_param_r.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | system("id"); | ||
| 10 | system("echo win"); | ||
| 11 | ?> | ||
| 12 | --EXPECTF-- | ||
| 13 | [snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'system' in %a/tests/disabled_functions_param_r.php:2 has been disabled, because its argument 'command' content (id) matched a rule. | ||
| 14 | win | ||
diff --git a/src/tests/disabled_functions_param_str_representation.phpt b/src/tests/disabled_functions_param_str_representation.phpt new file mode 100644 index 0000000..7cbdc0f --- /dev/null +++ b/src/tests/disabled_functions_param_str_representation.phpt | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable functions - casting various types to string internally | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_disabled_functions_param_str_representation.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | echo var_export(true) . "\n"; | ||
| 10 | echo var_export(false) . "\n"; | ||
| 11 | echo var_export(null) . "\n"; | ||
| 12 | echo var_export(1) . "\n"; | ||
| 13 | echo var_export(1.0) . "\n"; | ||
| 14 | function f(&$a) { | ||
| 15 | echo var_export($a) . "\n"; | ||
| 16 | } | ||
| 17 | $a = 123; f($a); | ||
| 18 | ?> | ||
| 19 | --EXPECTF-- | ||
| 20 | true | ||
| 21 | false | ||
| 22 | NULL | ||
| 23 | 1 | ||
| 24 | 1.0 | ||
| 25 | 123 | ||
diff --git a/src/tests/disabled_functions_parse_class.phpt b/src/tests/disabled_functions_parse_class.phpt new file mode 100644 index 0000000..af9ed88 --- /dev/null +++ b/src/tests/disabled_functions_parse_class.phpt | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable functions - Parsing of an Object as a return value of a function | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/disabled_functions_ret.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | /* | ||
| 10 | Because Snuffleupagus used to cast everything with the `zval_get_string` function, | ||
| 11 | this sometimes raised exceptions, because PHP is awful. | ||
| 12 | */ | ||
| 13 | class Bob { | ||
| 14 | function a() { | ||
| 15 | return new StdClass; | ||
| 16 | } | ||
| 17 | } | ||
| 18 | $b = new Bob; | ||
| 19 | echo ($b->a() instanceof StdClass)?'Y':'N'; | ||
| 20 | ?> | ||
| 21 | --EXPECT-- | ||
| 22 | Y | ||
diff --git a/src/tests/disabled_functions_require.phpt b/src/tests/disabled_functions_require.phpt new file mode 100644 index 0000000..1eedde4 --- /dev/null +++ b/src/tests/disabled_functions_require.phpt | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable functions - Require | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_disabled_functions_require.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | $dir = __DIR__; | ||
| 10 | file_put_contents($dir . '/test.meh', ""); | ||
| 11 | file_put_contents($dir . '/test.bla', ""); | ||
| 12 | require $dir . '/test.meh'; | ||
| 13 | require $dir . '/test.bla'; | ||
| 14 | echo "1337"; | ||
| 15 | ?> | ||
| 16 | --XFAIL-- | ||
| 17 | PHP doesn't replace the format string, so the test is failing. | ||
| 18 | --EXPECTF-- | ||
| 19 | [snuffleupagus][0.0.0.0][include][drop] Inclusion of a forbidden file (%a/test.bla) | ||
| 20 | --CLEAN-- | ||
| 21 | <?php | ||
| 22 | $dir = __DIR__; | ||
| 23 | unlink($dir . '/test.meh'); | ||
| 24 | unlink($dir . '/test.bla'); | ||
| 25 | ?> | ||
diff --git a/src/tests/disabled_functions_ret.phpt b/src/tests/disabled_functions_ret.phpt new file mode 100644 index 0000000..b64bf70 --- /dev/null +++ b/src/tests/disabled_functions_ret.phpt | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable functions check on `ret`. | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/disabled_functions_ret.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | echo strpos("pouet", "p"); | ||
| 10 | echo stripos("pouet", "p"); | ||
| 11 | ?> | ||
| 12 | --EXPECTF-- | ||
| 13 | [snuffleupagus][0.0.0.0][disabled_function][drop] The execution has been aborted in %a/disabled_functions_ret.php:2, because the return value (0) of the function 'strpos' matched a rule. | ||
diff --git a/src/tests/disabled_functions_ret2.phpt b/src/tests/disabled_functions_ret2.phpt new file mode 100644 index 0000000..b713201 --- /dev/null +++ b/src/tests/disabled_functions_ret2.phpt | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable functions check on `ret`. | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/disabled_functions_ret.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | echo stripos("pouet", "p"); | ||
| 10 | ?> | ||
| 11 | --EXPECTF-- | ||
| 12 | [snuffleupagus][0.0.0.0][disabled_function][drop] The execution has been aborted in %a/disabled_functions_ret2.php:2, because the return value (0) of the function 'stripos' matched a rule. | ||
diff --git a/src/tests/disabled_functions_ret3.phpt b/src/tests/disabled_functions_ret3.phpt new file mode 100644 index 0000000..d5f96d0 --- /dev/null +++ b/src/tests/disabled_functions_ret3.phpt | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable functions check on `ret`. | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/disabled_functions_ret.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | class Bob { | ||
| 10 | function a() { | ||
| 11 | echo("We're in function `a`.\n"); | ||
| 12 | return 1; | ||
| 13 | } | ||
| 14 | } | ||
| 15 | $b = new Bob(); | ||
| 16 | echo "`a` returned: " . $b->a() . ".\n"; | ||
| 17 | echo("We're at the end of the execution.\n"); | ||
| 18 | ?> | ||
| 19 | --EXPECTF-- | ||
| 20 | We're in function `a`. | ||
| 21 | `a` returned: 1. | ||
| 22 | We're at the end of the execution. \ No newline at end of file | ||
diff --git a/src/tests/disabled_functions_ret_allow.phpt b/src/tests/disabled_functions_ret_allow.phpt new file mode 100644 index 0000000..1690995 --- /dev/null +++ b/src/tests/disabled_functions_ret_allow.phpt | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable functions check on `ret`. | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_disabled_functions_ret_allow.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | echo strpos("pouet", "p"); | ||
| 10 | echo stripos("pouet", "p"); | ||
| 11 | ?> | ||
| 12 | --EXPECT-- | ||
| 13 | 00 \ No newline at end of file | ||
diff --git a/src/tests/disabled_functions_ret_allow_value.phpt b/src/tests/disabled_functions_ret_allow_value.phpt new file mode 100644 index 0000000..881a006 --- /dev/null +++ b/src/tests/disabled_functions_ret_allow_value.phpt | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable functions check on `ret` allowed | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_disabled_functions_ret_allow_value.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | echo strpos("pouet", "p"); | ||
| 10 | ?> | ||
| 11 | --EXPECT-- | ||
| 12 | 0 | ||
diff --git a/src/tests/disabled_functions_ret_right_hash.phpt b/src/tests/disabled_functions_ret_right_hash.phpt new file mode 100644 index 0000000..e0d8b5b --- /dev/null +++ b/src/tests/disabled_functions_ret_right_hash.phpt | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable functions | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_disabled_functions_ret_right_hash.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | system("echo $((1 + 1336))"); | ||
| 10 | ?> | ||
| 11 | --EXPECTF-- | ||
| 12 | 1337 | ||
diff --git a/src/tests/disabled_functions_ret_simulation.phpt b/src/tests/disabled_functions_ret_simulation.phpt new file mode 100644 index 0000000..58af3a9 --- /dev/null +++ b/src/tests/disabled_functions_ret_simulation.phpt | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable functions check on `ret` simulation | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_disabled_functions_ret_simulation.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | echo strpos("pouet", "p") . "\n"; | ||
| 10 | echo stripos("pouet", "p") . "\n"; | ||
| 11 | strcmp("p", "p") . "\n"; | ||
| 12 | ?> | ||
| 13 | --EXPECTF-- | ||
| 14 | [snuffleupagus][0.0.0.0][disabled_function][notice] The execution has been aborted in %a/disabled_functions_ret_simulation.php:2, because the return value (0) of the function 'strpos' matched a rule. | ||
| 15 | 0 | ||
| 16 | [snuffleupagus][0.0.0.0][disabled_function][notice] The execution has been aborted in %a/disabled_functions_ret_simulation.php:3, because the function 'stripos' returned '0', which matched the rule '1'. | ||
| 17 | 0 | ||
| 18 | [snuffleupagus][0.0.0.0][disabled_function][drop] The execution has been aborted in %a/disabled_functions_ret_simulation.php:4, because the return value (0) of the function 'strcmp' matched a rule. | ||
diff --git a/src/tests/disabled_functions_ret_type.phpt b/src/tests/disabled_functions_ret_type.phpt new file mode 100644 index 0000000..f1c6e4c --- /dev/null +++ b/src/tests/disabled_functions_ret_type.phpt | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable functions check on `ret` by type matching on boolean | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/disabled_functions_ret_type.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | echo strpos("pouet", "p") . "\n"; | ||
| 10 | echo "1337\n"; | ||
| 11 | echo strpos("pouet", "123"); | ||
| 12 | ?> | ||
| 13 | --EXPECTF-- | ||
| 14 | 0 | ||
| 15 | 1337 | ||
| 16 | [snuffleupagus][0.0.0.0][disabled_function][drop] The execution has been aborted in %a/tests/disabled_functions_ret_type.php:%d, because the function 'strpos' returned 'FALSE', which matched the rule 'Return value is FALSE'. | ||
diff --git a/src/tests/disabled_functions_ret_type_double.phpt b/src/tests/disabled_functions_ret_type_double.phpt new file mode 100644 index 0000000..b7942e1 --- /dev/null +++ b/src/tests/disabled_functions_ret_type_double.phpt | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable functions check on `ret` by type matching (double). | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/disabled_functions_ret_type_double.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | echo cos(0.5) . "\n"; | ||
| 10 | ?> | ||
| 11 | --EXPECTF-- | ||
| 12 | [snuffleupagus][0.0.0.0][disabled_function][drop] The execution has been aborted in %a/disabled_functions_ret_type_double.php:%d, because the function 'cos' returned '0.877583', which matched the rule 'Return value is a double'. | ||
diff --git a/src/tests/disabled_functions_ret_type_long.phpt b/src/tests/disabled_functions_ret_type_long.phpt new file mode 100644 index 0000000..b841c64 --- /dev/null +++ b/src/tests/disabled_functions_ret_type_long.phpt | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable functions check on `ret` by type matching (long). | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/disabled_functions_ret_type_long.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | echo strlen("pouet") . "\n"; | ||
| 10 | ?> | ||
| 11 | --EXPECTF-- | ||
| 12 | [snuffleupagus][0.0.0.0][disabled_function][drop] The execution has been aborted in %a/disabled_functions_ret_type_long.php:%d, because the function 'strlen' returned '5', which matched the rule 'Return value is a long'. | ||
diff --git a/src/tests/disabled_functions_ret_type_resource.phpt b/src/tests/disabled_functions_ret_type_resource.phpt new file mode 100644 index 0000000..4ceb610 --- /dev/null +++ b/src/tests/disabled_functions_ret_type_resource.phpt | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable functions check on `ret` by type matching (resource). | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/disabled_functions_ret_type_resource.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | echo fopen("/etc/passwd", "r"); | ||
| 10 | ?> | ||
| 11 | --EXPECTF-- | ||
| 12 | [snuffleupagus][0.0.0.0][disabled_function][drop] The execution has been aborted in %a/disabled_functions_ret_type_resource.php:2, because the function 'fopen' returned 'RESOURCE', which matched the rule 'Return value is a resource'. | ||
diff --git a/src/tests/disabled_functions_ret_type_str.phpt b/src/tests/disabled_functions_ret_type_str.phpt new file mode 100644 index 0000000..8c48b1d --- /dev/null +++ b/src/tests/disabled_functions_ret_type_str.phpt | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable functions check on `ret` by type matching (string). | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/disabled_functions_ret_type_str.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | echo substr("pouet", 3) . "\n"; | ||
| 10 | ?> | ||
| 11 | --EXPECTF-- | ||
| 12 | [snuffleupagus][0.0.0.0][disabled_function][drop] The execution has been aborted in %a/disabled_functions_ret_type_str.php:%d, because the function 'substr' returned 'et', which matched the rule 'Return value is a string'. | ||
diff --git a/src/tests/disabled_functions_ret_type_true.phpt b/src/tests/disabled_functions_ret_type_true.phpt new file mode 100644 index 0000000..a5eae38 --- /dev/null +++ b/src/tests/disabled_functions_ret_type_true.phpt | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable functions check on `ret` by type matching (true). | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/disabled_functions_ret_type_true.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | var_dump(is_numeric("pouet")) . "\n"; | ||
| 10 | echo "1337\n"; | ||
| 11 | echo is_numeric("1234") . "\n"; | ||
| 12 | ?> | ||
| 13 | --EXPECTF-- | ||
| 14 | bool(false) | ||
| 15 | 1337 | ||
| 16 | [snuffleupagus][0.0.0.0][disabled_function][drop] The execution has been aborted in %a/disabled_functions_ret_type_true.php:%d, because the function 'is_numeric' returned 'TRUE', which matched the rule 'Return value is a true'. | ||
diff --git a/src/tests/disabled_functions_ret_val.phpt b/src/tests/disabled_functions_ret_val.phpt new file mode 100644 index 0000000..8a02b29 --- /dev/null +++ b/src/tests/disabled_functions_ret_val.phpt | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable functions ret val | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/disabled_functions_retval.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | echo str_repeat("fufu",1)."\n"; | ||
| 10 | echo str_repeat("fufufu",1); | ||
| 11 | ?> | ||
| 12 | --EXPECTF-- | ||
| 13 | fufu | ||
| 14 | [snuffleupagus][0.0.0.0][disabled_function][drop] The execution has been aborted in %a/disabled_functions_ret_val.php:3, because the return value (fufufu) of the function 'str_repeat' matched a rule. | ||
diff --git a/src/tests/disabled_functions_ret_val_rx.phpt b/src/tests/disabled_functions_ret_val_rx.phpt new file mode 100644 index 0000000..1054b70 --- /dev/null +++ b/src/tests/disabled_functions_ret_val_rx.phpt | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable functions ret val rx | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/disabled_functions_retval_rx.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | echo str_repeat("fufu",1)."\n"; | ||
| 10 | echo str_repeat("fufufu",1); | ||
| 11 | ?> | ||
| 12 | --EXPECTF-- | ||
| 13 | fufu | ||
| 14 | [snuffleupagus][0.0.0.0][disabled_function][drop] The execution has been aborted in %a/disabled_functions_ret_val_rx.php:3, because the return value (fufufu) of the function 'str_repeat' matched a rule. | ||
diff --git a/src/tests/disabled_functions_right_hash.phpt b/src/tests/disabled_functions_right_hash.phpt new file mode 100644 index 0000000..f3c5fb3 --- /dev/null +++ b/src/tests/disabled_functions_right_hash.phpt | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable functions | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_disabled_functions_right_hash.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | system("echo $((1 + 1336))"); | ||
| 10 | ?> | ||
| 11 | --EXPECTF-- | ||
| 12 | 1337 | ||
diff --git a/src/tests/disabled_functions_runtime.phpt b/src/tests/disabled_functions_runtime.phpt new file mode 100644 index 0000000..1c6a141 --- /dev/null +++ b/src/tests/disabled_functions_runtime.phpt | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable functions - runtime inclusion | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_disabled_functions_param_runtime.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | |||
| 10 | $dir = __DIR__; | ||
| 11 | $content = '<?php function test($param) { echo $param . "\n"; }'; | ||
| 12 | file_put_contents('file_to_include1.php', $content); | ||
| 13 | file_put_contents('file_to_include2.php', $content); | ||
| 14 | |||
| 15 | if (rand() % 2) { | ||
| 16 | include "file_to_include1.php"; | ||
| 17 | } else { | ||
| 18 | include "file_to_include2.php"; | ||
| 19 | } | ||
| 20 | |||
| 21 | test('1338');test('1337'); | ||
| 22 | |||
| 23 | ?> | ||
| 24 | --EXPECTF-- | ||
| 25 | 1338 | ||
| 26 | [snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'test' in %a has been disabled, because its argument 'param' content (1337) matched a rule. | ||
| 27 | --CLEAN-- | ||
| 28 | <?php | ||
| 29 | unlink("file_to_include1.php"); | ||
| 30 | unlink("file_to_include2.php"); | ||
| 31 | ?> | ||
diff --git a/src/tests/disabled_functions_zero_cidr.phpt b/src/tests/disabled_functions_zero_cidr.phpt new file mode 100644 index 0000000..35d187a --- /dev/null +++ b/src/tests/disabled_functions_zero_cidr.phpt | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disable functions | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --ENV-- | ||
| 6 | return <<<EOF | ||
| 7 | REMOTE_ADDR=127.0.0.1 | ||
| 8 | EOF; | ||
| 9 | --INI-- | ||
| 10 | sp.configuration_file={PWD}/config/disabled_functions_zero_cidr.ini | ||
| 11 | --FILE-- | ||
| 12 | <?php | ||
| 13 | system("echo 42"); | ||
| 14 | printf("1337"); | ||
| 15 | ?> | ||
| 16 | --EXPECTF-- | ||
| 17 | [snuffleupagus][127.0.0.1][disabled_function][drop] The call to the function 'system' in %a/tests/disabled_functions_zero_cidr.php:2 has been disabled. | ||
| 18 | 1337 | ||
diff --git a/src/tests/disabled_option.phpt b/src/tests/disabled_option.phpt new file mode 100644 index 0000000..8bc7e39 --- /dev/null +++ b/src/tests/disabled_option.phpt | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | --TEST-- | ||
| 2 | Harden rand | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_rand_harden_disabled.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | srand(0); | ||
| 10 | echo rand(0,100)."\n"; | ||
| 11 | srand(0); | ||
| 12 | echo rand(0,100)."\n"; | ||
| 13 | ?> | ||
| 14 | --EXPECT-- | ||
| 15 | 84 | ||
| 16 | 84 | ||
diff --git a/src/tests/disabled_user_functions.phpt b/src/tests/disabled_user_functions.phpt new file mode 100644 index 0000000..8952d43 --- /dev/null +++ b/src/tests/disabled_user_functions.phpt | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | --TEST-- | ||
| 2 | Disabled user-created functions | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_disabled_user_functions.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | function my_super_function() { | ||
| 10 | echo 1; | ||
| 11 | } | ||
| 12 | my_super_function(); | ||
| 13 | ?> | ||
| 14 | --EXPECTF-- | ||
| 15 | [snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'my_super_function' in %a/tests/disabled_user_functions.php:3 has been disabled. | ||
diff --git a/src/tests/dump_request.phpt b/src/tests/dump_request.phpt new file mode 100644 index 0000000..a752def --- /dev/null +++ b/src/tests/dump_request.phpt | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | --TEST-- | ||
| 2 | Dump request | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php | ||
| 5 | if (!extension_loaded("snuffleupagus")) { | ||
| 6 | print "skip"; | ||
| 7 | } | ||
| 8 | |||
| 9 | foreach (glob("./tests/dump_results/*.dump") as $dump) { | ||
| 10 | unlink($dump); | ||
| 11 | } | ||
| 12 | rmdir("./tests/dump_results/"); | ||
| 13 | ?> | ||
| 14 | --POST-- | ||
| 15 | post_a=data_post_a&post_b=data_post_b | ||
| 16 | --GET-- | ||
| 17 | get_a=data_get_a&get_b=data_get_b | ||
| 18 | --COOKIE-- | ||
| 19 | cookie_a=data_cookie_a&cookie_b=data_cookie_b | ||
| 20 | --INI-- | ||
| 21 | sp.configuration_file={PWD}/config/dump_request.ini | ||
| 22 | --FILE-- | ||
| 23 | <?php | ||
| 24 | mkdir("./dump_results/"); | ||
| 25 | echo "1\n"; | ||
| 26 | echo system("echo 1337;"); | ||
| 27 | $filename = glob('./dump_results/*.dump')[0]; | ||
| 28 | $res = file($filename); | ||
| 29 | if ($res[1] != "GET:get_a=data_get_a&get_b=data_get_b\n") { | ||
| 30 | echo "1\n"; | ||
| 31 | } elseif ($res[2] != "POST:post_a=data_post_a&post_b=data_post_b\n") { | ||
| 32 | echo "2\n"; | ||
| 33 | } elseif ($res[3] != "COOKIE:cookie_a=data_cookie_a&cookie_b=data_cookie_b\n") { | ||
| 34 | echo "3\n"; | ||
| 35 | } | ||
| 36 | ?> | ||
| 37 | --EXPECTF-- | ||
| 38 | 1 | ||
| 39 | [snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'system' in %a/dump_request.php:%d has been disabled. | ||
diff --git a/src/tests/dump_request_invalid_folder.phpt b/src/tests/dump_request_invalid_folder.phpt new file mode 100644 index 0000000..b866f70 --- /dev/null +++ b/src/tests/dump_request_invalid_folder.phpt | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | --TEST-- | ||
| 2 | Dump request - invalid folder. | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php | ||
| 5 | if (!extension_loaded("snuffleupagus")) { print "skip"; } | ||
| 6 | ?> | ||
| 7 | --POST-- | ||
| 8 | post_a=data_post_a&post_b=data_post_b | ||
| 9 | --GET-- | ||
| 10 | get_a=data_get_a&get_b=data_get_b | ||
| 11 | --COOKIE-- | ||
| 12 | cookie_a=data_cookie_a&cookie_b=data_cookie_b | ||
| 13 | --INI-- | ||
| 14 | sp.configuration_file={PWD}/config/dump_request_invalid_folder.ini | ||
| 15 | --FILE-- | ||
| 16 | <?php | ||
| 17 | echo "1\n"; | ||
| 18 | echo system("echo 1337;"); | ||
| 19 | echo "2\n"; | ||
| 20 | ?> | ||
| 21 | --EXPECTF-- | ||
| 22 | 1 | ||
| 23 | [snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'system' in %atests/dump_request_invalid_folder.php:3 has been disabled. | ||
| 24 | [snuffleupagus][0.0.0.0][request_logging][error] Unable to open /root/NON_EXISTENT/FOLDER/PLEASE/sp_dump_%a_0.0.0.0.dump | ||
| 25 | 2 \ No newline at end of file | ||
diff --git a/src/tests/dump_request_too_big.phpt b/src/tests/dump_request_too_big.phpt new file mode 100644 index 0000000..81eb71c --- /dev/null +++ b/src/tests/dump_request_too_big.phpt | |||
| @@ -0,0 +1,42 @@ | |||
| 1 | --TEST-- | ||
| 2 | Dump request -- to big, so it's truncated. | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php | ||
| 5 | if (!extension_loaded("snuffleupagus")) { | ||
| 6 | print "skip"; | ||
| 7 | } | ||
| 8 | |||
| 9 | foreach (glob("./tests/dump_results/*.dump") as $dump) { | ||
| 10 | unlink($dump); | ||
| 11 | } | ||
| 12 | rmdir("./tests/dump_results/"); | ||
| 13 | ?> | ||
| 14 | --POST-- | ||
| 15 | post_a=data_post_a&post_b=data_post_b&post_c=c | ||
| 16 | --GET-- | ||
| 17 | get_a=data_get_a&get_b=data_get_b&get_c=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaBBBB | ||
| 18 | --COOKIE-- | ||
| 19 | cookie_a=data_cookie_a&cookie_b=data_cookie_b&data_cookie_c=cookie_c | ||
| 20 | --ENV-- | ||
| 21 | return <<<END | ||
| 22 | REMOTE_ADDR=127.0.0.1 | ||
| 23 | END; | ||
| 24 | --INI-- | ||
| 25 | sp.configuration_file={PWD}/config/dump_request.ini | ||
| 26 | --FILE-- | ||
| 27 | <?php | ||
| 28 | echo "1\n"; | ||
| 29 | echo system("echo 1337;"); | ||
| 30 | $filename = glob('./dump_results/*.dump')[0]; | ||
| 31 | $res = file($filename); | ||
| 32 | if ($res[1] != "GET:get_a=data_get_a&get_b=data_get_b&get_c=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n") { | ||
| 33 | echo "1\n"; | ||
| 34 | } elseif ($res[2] != "POST:post_a=data_post_a&post_b=data_post_b&post_c=c\n") { | ||
| 35 | echo "2\n"; | ||
| 36 | } elseif ($res[3] != "COOKIE:cookie_a=data_cookie_a&cookie_b=data_cookie_b&data_cookie_c=cookie_c\n") { | ||
| 37 | echo "3\n"; | ||
| 38 | } | ||
| 39 | ?> | ||
| 40 | --EXPECTF-- | ||
| 41 | 1 | ||
| 42 | [snuffleupagus][127.0.0.1][disabled_function][drop] The call to the function 'system' in %a/dump_request_too_big.php:%d has been disabled. | ||
diff --git a/src/tests/empty_conf.phpt b/src/tests/empty_conf.phpt new file mode 100644 index 0000000..411c817 --- /dev/null +++ b/src/tests/empty_conf.phpt | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | --TEST-- | ||
| 2 | Empty configuration | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/empty_conf.ini | ||
| 7 | --FILE-- | ||
| 8 | --EXPECT-- | ||
diff --git a/src/tests/encrypt_cookies.phpt b/src/tests/encrypt_cookies.phpt new file mode 100644 index 0000000..f8bf64f --- /dev/null +++ b/src/tests/encrypt_cookies.phpt | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | --TEST-- | ||
| 2 | Cookie decryption in ipv4 | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_encrypted_cookies.ini | ||
| 7 | --COOKIE-- | ||
| 8 | super_cookie=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEmXkk3H0xheoOMxoWPEDw1Zd8NAmD9KbB2DSjQ=%3d;awful_cookie=awful_cookie_value; | ||
| 9 | --ENV-- | ||
| 10 | return <<<EOF | ||
| 11 | REMOTE_ADDR=127.0.0.1 | ||
| 12 | HTTP_USER_AGENT=Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/59.0.3071.109 Chrome/59.0.3071.109 Safari/537.36 | ||
| 13 | EOF; | ||
| 14 | --FILE-- | ||
| 15 | <?php var_dump($_COOKIE); ?> | ||
| 16 | --EXPECT-- | ||
| 17 | array(2) { | ||
| 18 | ["super_cookie"]=> | ||
| 19 | string(11) "super_value" | ||
| 20 | ["awful_cookie"]=> | ||
| 21 | string(18) "awful_cookie_value" | ||
| 22 | } | ||
diff --git a/src/tests/encrypt_cookies2.phpt b/src/tests/encrypt_cookies2.phpt new file mode 100644 index 0000000..be4c990 --- /dev/null +++ b/src/tests/encrypt_cookies2.phpt | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | --TEST-- | ||
| 2 | Cookie encryption in ipv4 | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_encrypted_cookies.ini | ||
| 7 | --COOKIE-- | ||
| 8 | --ENV-- | ||
| 9 | return <<<EOF | ||
| 10 | REMOTE_ADDR=127.0.0.1 | ||
| 11 | HTTP_USER_AGENT=Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/59.0.3071.109 Chrome/59.0.3071.109 Safari/537.36 | ||
| 12 | HTTPS=1 | ||
| 13 | EOF; | ||
| 14 | --FILE-- | ||
| 15 | <?php | ||
| 16 | setcookie("super_cookie", "super_value"); | ||
| 17 | setcookie("awful_cookie", "awful_value"); | ||
| 18 | setcookie("nice_cookie", "nice_value", 1, "1", "1", true, true); | ||
| 19 | var_dump($_COOKIE); | ||
| 20 | ?> | ||
| 21 | --EXPECT-- | ||
| 22 | array(0) { | ||
| 23 | } | ||
diff --git a/src/tests/encrypt_cookies3.phpt b/src/tests/encrypt_cookies3.phpt new file mode 100644 index 0000000..c85c5dc --- /dev/null +++ b/src/tests/encrypt_cookies3.phpt | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | --TEST-- | ||
| 2 | Cookie decryption with ipv6 | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_encrypted_cookies.ini | ||
| 7 | --COOKIE-- | ||
| 8 | super_cookie=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJNTUge7MpiVNi4q3DqstbcumllXBir0CbIQiDI%3D;awful_cookie=awful_cookie_value; | ||
| 9 | --ENV-- | ||
| 10 | return <<<EOF | ||
| 11 | REMOTE_ADDR=2001:0db8:0000:0000:0000:fe00:0042:8329 | ||
| 12 | HTTP_USER_AGENT=Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/59.0.3071.109 Chrome/59.0.3071.109 Safari/537.36 | ||
| 13 | HTTPS=1 | ||
| 14 | EOF; | ||
| 15 | --FILE-- | ||
| 16 | <?php var_dump($_COOKIE); ?> | ||
| 17 | --EXPECT-- | ||
| 18 | array(2) { | ||
| 19 | ["super_cookie"]=> | ||
| 20 | string(11) "super_value" | ||
| 21 | ["awful_cookie"]=> | ||
| 22 | string(18) "awful_cookie_value" | ||
| 23 | } | ||
diff --git a/src/tests/encrypt_cookies4.phpt b/src/tests/encrypt_cookies4.phpt new file mode 100644 index 0000000..14d737a --- /dev/null +++ b/src/tests/encrypt_cookies4.phpt | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | --TEST-- | ||
| 2 | Cookie encryption in ipv6 | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_encrypted_cookies.ini | ||
| 7 | --COOKIE-- | ||
| 8 | --ENV-- | ||
| 9 | return <<<EOF | ||
| 10 | REMOTE_ADDR=2001:0db8:0000:0000:0000:fe00:0042:8329 | ||
| 11 | HTTP_USER_AGENT=Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/59.0.3071.109 Chrome/59.0.3071.109 Safari/537.36 | ||
| 12 | HTTPS=1 | ||
| 13 | EOF; | ||
| 14 | --FILE-- | ||
| 15 | <?php | ||
| 16 | setcookie("super_cookie", "super_value"); | ||
| 17 | setcookie("awful_cookie", "awful_value"); | ||
| 18 | setcookie("nice_cookie", "nice_value", 1, "1", "1", true, true); | ||
| 19 | var_dump($_COOKIE); | ||
| 20 | ?> | ||
| 21 | --EXPECT-- | ||
| 22 | array(0) { | ||
| 23 | } | ||
diff --git a/src/tests/encrypt_cookies_invalid_decryption.phpt b/src/tests/encrypt_cookies_invalid_decryption.phpt new file mode 100644 index 0000000..a5187c1 --- /dev/null +++ b/src/tests/encrypt_cookies_invalid_decryption.phpt | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | --TEST-- | ||
| 2 | Cookie encryption | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_encrypted_cookies.ini | ||
| 7 | display_errors=1 | ||
| 8 | display_startup_errors=1 | ||
| 9 | error_reporting=E_ALL | ||
| 10 | --COOKIE-- | ||
| 11 | super_cookie=jWjORGsgZyqzk3WA63XZBmUoSknXWnXDfAAAAAAAAAAAAAAAAAAAAAA7LiMDfkpP94jDnMVH%2Fm41GeL0Y00q3mbOFYz%2FS9mQGySu;awful_cookie=awful_cookie_value; | ||
| 12 | --ENV-- | ||
| 13 | return <<<EOF | ||
| 14 | REMOTE_ADDR=127.0.0.1 | ||
| 15 | EOF; | ||
| 16 | --FILE-- | ||
| 17 | <?php var_dump($_COOKIE); ?> | ||
| 18 | --EXPECT-- | ||
| 19 | |||
| 20 | array(1) { | ||
| 21 | ["awful_cookie"]=> | ||
| 22 | string(18) "awful_cookie_value" | ||
| 23 | } | ||
diff --git a/src/tests/encrypt_cookies_invalid_decryption2.phpt b/src/tests/encrypt_cookies_invalid_decryption2.phpt new file mode 100644 index 0000000..f18cf6d --- /dev/null +++ b/src/tests/encrypt_cookies_invalid_decryption2.phpt | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | --TEST-- | ||
| 2 | Cookie encryption | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_encrypted_cookies.ini | ||
| 7 | display_errors=1 | ||
| 8 | display_startup_errors=1 | ||
| 9 | error_reporting=E_ALL | ||
| 10 | --COOKIE-- | ||
| 11 | super_cookie=1337;awful_cookie=awful_cookie_value; | ||
| 12 | --ENV-- | ||
| 13 | return <<<EOF | ||
| 14 | REMOTE_ADDR=127.0.0.1 | ||
| 15 | EOF; | ||
| 16 | --FILE-- | ||
| 17 | <?php var_dump($_COOKIE); ?> | ||
| 18 | --EXPECT-- | ||
| 19 | |||
| 20 | array(1) { | ||
| 21 | ["awful_cookie"]=> | ||
| 22 | string(18) "awful_cookie_value" | ||
| 23 | } | ||
diff --git a/src/tests/encrypt_cookies_invalid_decryption3.phpt b/src/tests/encrypt_cookies_invalid_decryption3.phpt new file mode 100644 index 0000000..f4afc32 --- /dev/null +++ b/src/tests/encrypt_cookies_invalid_decryption3.phpt | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | --TEST-- | ||
| 2 | Cookie encryption | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_encrypted_cookies.ini | ||
| 7 | --COOKIE-- | ||
| 8 | super_cookie=;awful_cookie=awful_cookie_value; | ||
| 9 | --ENV-- | ||
| 10 | return <<<EOF | ||
| 11 | REMOTE_ADDR=127.0.0.1 | ||
| 12 | EOF; | ||
| 13 | --FILE-- | ||
| 14 | <?php var_dump($_COOKIE); ?> | ||
| 15 | --EXPECT-- | ||
| 16 | array(2) { | ||
| 17 | ["super_cookie"]=> | ||
| 18 | string(0) "" | ||
| 19 | ["awful_cookie"]=> | ||
| 20 | string(18) "awful_cookie_value" | ||
| 21 | } | ||
diff --git a/src/tests/encryption_key_only.phpt b/src/tests/encryption_key_only.phpt new file mode 100644 index 0000000..bf5edb5 --- /dev/null +++ b/src/tests/encryption_key_only.phpt | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | --TEST-- | ||
| 2 | Encryption key only | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/encryption_key_only.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | echo 1337; | ||
| 10 | ?> | ||
| 11 | --EXPECT-- | ||
| 12 | 1337 | ||
| 13 | |||
diff --git a/src/tests/example_configuration.phpt b/src/tests/example_configuration.phpt new file mode 100644 index 0000000..0bbf59c --- /dev/null +++ b/src/tests/example_configuration.phpt | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | --TEST-- | ||
| 2 | Shipped configuration | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/../../config/examples.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | system("echo 0"); | ||
| 10 | ?> | ||
| 11 | --EXPECTF-- | ||
| 12 | 0 | ||
diff --git a/src/tests/global_strict.phpt b/src/tests/global_strict.phpt new file mode 100644 index 0000000..e06721c --- /dev/null +++ b/src/tests/global_strict.phpt | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | --TEST-- | ||
| 2 | Global strict mode | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/global_strict.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | strcmp("pouet", []); | ||
| 10 | ?> | ||
| 11 | --EXPECTF-- | ||
| 12 | Fatal error: Uncaught TypeError: strcmp() expects parameter 2 to be string, array given in %a/global_strict.php:2 | ||
| 13 | Stack trace: | ||
| 14 | #0 %a/global_strict.php(2): strcmp('pouet', Array) | ||
| 15 | #1 {main} | ||
| 16 | thrown in %a/global_strict.php on line 2 | ||
diff --git a/src/tests/global_strict_disabled.phpt b/src/tests/global_strict_disabled.phpt new file mode 100644 index 0000000..ca3ddfa --- /dev/null +++ b/src/tests/global_strict_disabled.phpt | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | --TEST-- | ||
| 2 | Global strict mode | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/global_strict_disabled.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | strcmp("pouet", []); | ||
| 10 | echo 1337; | ||
| 11 | ?> | ||
| 12 | --EXPECTF-- | ||
| 13 | Warning: strcmp() expects parameter 2 to be string, array given in %a/global_strict_disabled.php on line 2 | ||
| 14 | 1337 | ||
diff --git a/src/tests/harden_mt_rand.phpt b/src/tests/harden_mt_rand.phpt new file mode 100644 index 0000000..8887613 --- /dev/null +++ b/src/tests/harden_mt_rand.phpt | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | --TEST-- | ||
| 2 | Harden mt_rand | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/harden_rand.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | mt_srand(0); | ||
| 10 | $a = mt_rand(0,100)."\n"; | ||
| 11 | $b = mt_rand(0,100)."\n"; | ||
| 12 | mt_srand(0); | ||
| 13 | $c = mt_rand(0,100)."\n"; | ||
| 14 | $d = mt_rand(0,100)."\n"; | ||
| 15 | |||
| 16 | if ($a == $c && $b == $d) | ||
| 17 | echo 'lose'; | ||
| 18 | else | ||
| 19 | echo 'win'; | ||
| 20 | ?> | ||
| 21 | --EXPECT-- | ||
| 22 | win | ||
diff --git a/src/tests/harden_rand.phpt b/src/tests/harden_rand.phpt new file mode 100644 index 0000000..391bccc --- /dev/null +++ b/src/tests/harden_rand.phpt | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | --TEST-- | ||
| 2 | Harden rand | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/harden_rand.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | srand(0); | ||
| 10 | $a = rand(0,100)."\n"; | ||
| 11 | $b = rand(0,100)."\n"; | ||
| 12 | srand(0); | ||
| 13 | $c = rand(0,100)."\n"; | ||
| 14 | $d = rand(0,100)."\n"; | ||
| 15 | |||
| 16 | rand(100,0)."\n"; | ||
| 17 | |||
| 18 | if ($a == $c && $b == $d) | ||
| 19 | echo 'fail'; | ||
| 20 | else | ||
| 21 | echo 'win'; | ||
| 22 | ?> | ||
| 23 | --EXPECT-- | ||
| 24 | win | ||
diff --git a/src/tests/harden_rand_noargs.phpt b/src/tests/harden_rand_noargs.phpt new file mode 100644 index 0000000..643a453 --- /dev/null +++ b/src/tests/harden_rand_noargs.phpt | |||
| @@ -0,0 +1,62 @@ | |||
| 1 | --TEST-- | ||
| 2 | Harden rand without any arguments | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/harden_rand.ini | ||
| 7 | We should fix this | ||
| 8 | --FILE-- | ||
| 9 | <?php | ||
| 10 | rand(); | ||
| 11 | mt_rand(); | ||
| 12 | |||
| 13 | rand(1); | ||
| 14 | mt_rand(1); | ||
| 15 | |||
| 16 | rand(1, 2); | ||
| 17 | mt_rand(1, 2); | ||
| 18 | |||
| 19 | rand(2, 1); | ||
| 20 | mt_rand(2, 1); | ||
| 21 | |||
| 22 | rand(2, 1, 0); | ||
| 23 | mt_rand(2, 1, 0); | ||
| 24 | |||
| 25 | rand("test", 1); | ||
| 26 | mt_rand("test", 1); | ||
| 27 | |||
| 28 | rand(1, "test"); | ||
| 29 | mt_rand(1, "test"); | ||
| 30 | |||
| 31 | rand(1, 2, "test"); | ||
| 32 | mt_rand(1, 2, "test"); | ||
| 33 | |||
| 34 | echo "Everything is fine\n"; | ||
| 35 | echo "Absolutely everything\n"; | ||
| 36 | echo 'Even with single quotes'; | ||
| 37 | ?> | ||
| 38 | --EXPECTF-- | ||
| 39 | Warning: rand() expects exactly 2 parameters, 1 given in %s/tests/harden_rand_noargs.php on line %d | ||
| 40 | |||
| 41 | Warning: mt_rand() expects exactly 2 parameters, 1 given in %s/tests/harden_rand_noargs.php on line %d | ||
| 42 | |||
| 43 | Warning: mt_rand(): max(1) is smaller than min(2) in %s/tests/harden_rand_noargs.php on line %d | ||
| 44 | |||
| 45 | Warning: rand() expects exactly 2 parameters, 3 given in %s/tests/harden_rand_noargs.php on line %d | ||
| 46 | |||
| 47 | Warning: mt_rand() expects exactly 2 parameters, 3 given in %s/tests/harden_rand_noargs.php on line %d | ||
| 48 | |||
| 49 | Warning: rand() expects parameter 1 to be integer, string given in %s/tests/harden_rand_noargs.php on line %d | ||
| 50 | |||
| 51 | Warning: mt_rand() expects parameter 1 to be integer, string given in %s/tests/harden_rand_noargs.php on line %d | ||
| 52 | |||
| 53 | Warning: rand() expects parameter 2 to be integer, string given in %s/tests/harden_rand_noargs.php on line %d | ||
| 54 | |||
| 55 | Warning: mt_rand() expects parameter 2 to be integer, string given in %s/tests/harden_rand_noargs.php on line %d | ||
| 56 | |||
| 57 | Warning: rand() expects exactly 2 parameters, 3 given in %s/tests/harden_rand_noargs.php on line %d | ||
| 58 | |||
| 59 | Warning: mt_rand() expects exactly 2 parameters, 3 given in %s/tests/harden_rand_noargs.php on line %d | ||
| 60 | Everything is fine | ||
| 61 | Absolutely everything | ||
| 62 | Even with single quotes | ||
diff --git a/src/tests/inexistent_conf_file.phpt b/src/tests/inexistent_conf_file.phpt new file mode 100644 index 0000000..c7c3fcd --- /dev/null +++ b/src/tests/inexistent_conf_file.phpt | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | --TEST-- | ||
| 2 | Check for snuffleupagus presence | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/unexistent_configuration_file.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php ?> | ||
| 9 | --EXPECTF-- | ||
| 10 | [snuffleupagus][0.0.0.0][config][error] Could not open configuration file %a/tests/config/unexistent_configuration_file.ini : No such file or directory | ||
diff --git a/src/tests/loading.phpt b/src/tests/loading.phpt new file mode 100644 index 0000000..25e2e17 --- /dev/null +++ b/src/tests/loading.phpt | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | --TEST-- | ||
| 2 | Check for snuffleupagus presence | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --FILE-- | ||
| 6 | <?php | ||
| 7 | echo "snuffleupagus extension is available"; | ||
| 8 | ?> | ||
| 9 | --EXPECT-- | ||
| 10 | snuffleupagus extension is available | ||
diff --git a/src/tests/noncore_function_hooking.phpt b/src/tests/noncore_function_hooking.phpt new file mode 100644 index 0000000..106123c --- /dev/null +++ b/src/tests/noncore_function_hooking.phpt | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | --TEST-- | ||
| 2 | Hooking of user-defined functions | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_noncore_function_hooking.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | function custom_fun($a) { | ||
| 10 | echo $a; | ||
| 11 | } | ||
| 12 | custom_fun("hello"); | ||
| 13 | ?> | ||
| 14 | --EXPECTF-- | ||
| 15 | [snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'custom_fun' in %a/tests/noncore_function_hooking.php:3 has been disabled. | ||
diff --git a/src/tests/phpinfo_presence.phpt b/src/tests/phpinfo_presence.phpt new file mode 100644 index 0000000..35ed0ed --- /dev/null +++ b/src/tests/phpinfo_presence.phpt | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | --TEST-- | ||
| 2 | Unserialize fail | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_serialize.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | ob_start () ; | ||
| 10 | phpinfo () ; | ||
| 11 | $pinfo = ob_get_contents () ; | ||
| 12 | ob_end_clean () ; | ||
| 13 | if (strstr($pinfo, "snuffleupagus") !== FALSE) | ||
| 14 | echo 1; | ||
| 15 | else | ||
| 16 | echo 2; | ||
| 17 | ?> | ||
| 18 | --EXPECT-- | ||
| 19 | 1 | ||
diff --git a/src/tests/serialize.phpt b/src/tests/serialize.phpt new file mode 100644 index 0000000..e93dbaf --- /dev/null +++ b/src/tests/serialize.phpt | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | --TEST-- | ||
| 2 | Test serialize hmac | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_serialize.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | echo serialize("a"); | ||
| 10 | ?> | ||
| 11 | --EXPECT-- | ||
| 12 | s:1:"a";650609b417904d0d9bbf1fc44a975d13ecdf6b02b715c1a06271fb3b673f25b1 | ||
| 13 | |||
diff --git a/src/tests/setcookie.phpt b/src/tests/setcookie.phpt new file mode 100644 index 0000000..ba1d1c1 --- /dev/null +++ b/src/tests/setcookie.phpt | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | --TEST-- | ||
| 2 | Set cookies. | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_encrypted_cookies.ini | ||
| 7 | --COOKIE-- | ||
| 8 | --ENV-- | ||
| 9 | return <<<EOF | ||
| 10 | REMOTE_ADDR=127.0.0.1 | ||
| 11 | HTTP_USER_AGENT=Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/59.0.3071.109 Chrome/59.0.3071.109 Safari/537.36 | ||
| 12 | HTTPS=1 | ||
| 13 | EOF; | ||
| 14 | --FILE-- | ||
| 15 | <?php | ||
| 16 | setcookie("name"); | ||
| 17 | setcookie("super_cookie"); | ||
| 18 | setcookie("name", "value"); | ||
| 19 | setcookie("name", "value1", 1); | ||
| 20 | setcookie("name", "value2", 0); | ||
| 21 | setcookie("name", "value", 1, "/super/path"); | ||
| 22 | setcookie("name", "value", 1, "/super/path", "super_domain"); | ||
| 23 | setcookie("name", "value", 1, "/super/path", "super_domain1", true); | ||
| 24 | setcookie("name", "value", 1, "/super/path", "super_domain2", false); | ||
| 25 | setcookie("name", "value", 1, "/super/path", "super_domain1", true, true); | ||
| 26 | setcookie("name", "value", 1, "/super/path", "super_domain2", true, false); | ||
| 27 | setcookie("name", "value", 1, "/super/path", "super_domain2", true, false, 1337); | ||
| 28 | setcookie(); | ||
| 29 | echo '1337'; | ||
| 30 | ?> | ||
| 31 | --EXPECTF-- | ||
| 32 | Warning: setcookie() expects at most 7 parameters, 8 given in %a/setcookie.php on line %d | ||
| 33 | |||
| 34 | Warning: setcookie() expects at least 1 parameter, 0 given in %a/setcookie.php on line %d | ||
| 35 | 1337 | ||
diff --git a/src/tests/shipped_configuration.phpt b/src/tests/shipped_configuration.phpt new file mode 100644 index 0000000..c060a85 --- /dev/null +++ b/src/tests/shipped_configuration.phpt | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | --TEST-- | ||
| 2 | Shipped configuration | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/../../config/default.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | system("echo 0"); | ||
| 10 | ?> | ||
| 11 | --EXPECTF-- | ||
| 12 | 0 | ||
diff --git a/src/tests/unserialize.phpt b/src/tests/unserialize.phpt new file mode 100644 index 0000000..b1db915 --- /dev/null +++ b/src/tests/unserialize.phpt | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | --TEST-- | ||
| 2 | Unserialize ok | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_serialize.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | $a=serialize("a"); | ||
| 10 | var_dump(unserialize($a)); | ||
| 11 | ?> | ||
| 12 | --EXPECT-- | ||
| 13 | string(1) "a" | ||
diff --git a/src/tests/unserialize_fail.phpt b/src/tests/unserialize_fail.phpt new file mode 100644 index 0000000..5c0bb80 --- /dev/null +++ b/src/tests/unserialize_fail.phpt | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | --TEST-- | ||
| 2 | Unserialize fail | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_serialize.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | var_dump(unserialize('s:1:"a";')); | ||
| 10 | var_dump(unserialize('s:1:"a";alyualskdufyhalkdjsfhalkjdhflaksjdfhlkasdhflkahdawkuerylksjdfhlkssjgdflaksjdhflkasjdf')); | ||
| 11 | var_dump(unserialize('s:1:"a";dslfjklfjfkjfdjffjfjads')); | ||
| 12 | var_dump(unserialize(1,2,3,4)); | ||
| 13 | ?> | ||
| 14 | --EXPECTF-- | ||
| 15 | [snuffleupagus][0.0.0.0][unserialize][drop] The serialized object is too small. | ||
| 16 | bool(false) | ||
| 17 | [snuffleupagus][0.0.0.0][unserialize][drop] Invalid HMAC for s:1:"a";alyualskdufyhalkdjsfh | ||
| 18 | NULL | ||
| 19 | [snuffleupagus][0.0.0.0][unserialize][drop] The serialized object is too small. | ||
| 20 | bool(false) | ||
| 21 | |||
| 22 | Warning: unserialize() expects at most 2 parameters, 4 given in %a/tests/unserialize_fail.php on line %d | ||
| 23 | bool(false) \ No newline at end of file | ||
diff --git a/src/tests/unserialize_sim.phpt b/src/tests/unserialize_sim.phpt new file mode 100644 index 0000000..8ebf64d --- /dev/null +++ b/src/tests/unserialize_sim.phpt | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | --TEST-- | ||
| 2 | Unserialize ok | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_serialize_sim.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | $a=serialize("a"); | ||
| 10 | echo $a; | ||
| 11 | var_dump(unserialize($a)); | ||
| 12 | var_dump(unserialize('s:1:"a";alyualskdufyhalkdjsfhalkjdhflaksjdfhlkasdhflkahdawkuerylksjdfhlkssjgdflaksjdh1337sjdf')); | ||
| 13 | ?> | ||
| 14 | --EXPECT-- | ||
| 15 | s:1:"a";650609b417904d0d9bbf1fc44a975d13ecdf6b02b715c1a06271fb3b673f25b1string(1) "a" | ||
| 16 | [snuffleupagus][0.0.0.0][unserialize][notice] Invalid HMAC for s:1:"a";alyualskdufyhalkdjsfh | ||
| 17 | string(1) "a" | ||
diff --git a/src/tests/upload_validation.phpt b/src/tests/upload_validation.phpt new file mode 100644 index 0000000..c802c16 --- /dev/null +++ b/src/tests/upload_validation.phpt | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | --TEST-- | ||
| 2 | Upload a file, validation ok, no simulation | ||
| 3 | --INI-- | ||
| 4 | file_uploads=1 | ||
| 5 | sp.configuration_file={PWD}/config/upload_validation.ini | ||
| 6 | --POST_RAW-- | ||
| 7 | Content-Type: multipart/form-data; boundary=blabla | ||
| 8 | --blabla | ||
| 9 | Content-Disposition: form-data; name="test"; filename="test.php" | ||
| 10 | --blabla-- | ||
| 11 | --FILE-- | ||
| 12 | <?php | ||
| 13 | echo 1; | ||
| 14 | ?> | ||
| 15 | --EXPECTF-- | ||
| 16 | 1 | ||
diff --git a/src/tests/upload_validation_invalid.phpt b/src/tests/upload_validation_invalid.phpt new file mode 100644 index 0000000..f8c993b --- /dev/null +++ b/src/tests/upload_validation_invalid.phpt | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | --TEST-- | ||
| 2 | Upload a file, invalid validation script | ||
| 3 | --INI-- | ||
| 4 | file_uploads=1 | ||
| 5 | sp.configuration_file={PWD}/config/upload_validation_invalid.ini | ||
| 6 | --POST_RAW-- | ||
| 7 | Content-Type: multipart/form-data; boundary=blabla | ||
| 8 | --blabla | ||
| 9 | Content-Disposition: form-data; name="test"; filename="test.php" | ||
| 10 | --blabla-- | ||
| 11 | --FILE-- | ||
| 12 | <?php | ||
| 13 | echo 1; | ||
| 14 | ?> | ||
| 15 | --EXPECTF-- | ||
| 16 | [snuffleupagus][0.0.0.0][upload_validation][error] Could not call './tests/data/upload_invalid.sh' : Exec format error | ||
| 17 | [snuffleupagus][0.0.0.0][upload_valiation][drop] The upload of test.php on ? was rejected. | ||
diff --git a/src/tests/upload_validation_ko.phpt b/src/tests/upload_validation_ko.phpt new file mode 100644 index 0000000..cf4057a --- /dev/null +++ b/src/tests/upload_validation_ko.phpt | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | --TEST-- | ||
| 2 | Upload a file, validation ko, no simulation | ||
| 3 | --INI-- | ||
| 4 | file_uploads=1 | ||
| 5 | sp.configuration_file={PWD}/config/upload_validation_ko.ini | ||
| 6 | output_buffering=off | ||
| 7 | --POST_RAW-- | ||
| 8 | Content-Type: multipart/form-data; boundary=blabla | ||
| 9 | --blabla | ||
| 10 | Content-Disposition: form-data; name="test"; filename="test.php" | ||
| 11 | --blabla-- | ||
| 12 | --FILE-- | ||
| 13 | --EXPECTF-- | ||
| 14 | [snuffleupagus][0.0.0.0][upload_valiation][drop] The upload of test.php on ? was rejected. | ||
diff --git a/src/tests/upload_validation_no_exec.phpt b/src/tests/upload_validation_no_exec.phpt new file mode 100644 index 0000000..90a58da --- /dev/null +++ b/src/tests/upload_validation_no_exec.phpt | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | --TEST-- | ||
| 2 | Upload a file, validation script not executable | ||
| 3 | --INI-- | ||
| 4 | file_uploads=1 | ||
| 5 | sp.configuration_file={PWD}/config/upload_validation_non_exec.ini | ||
| 6 | output_buffering=off | ||
| 7 | --POST_RAW-- | ||
| 8 | Content-Type: multipart/form-data; boundary=blabla | ||
| 9 | --blabla | ||
| 10 | Content-Disposition: form-data; name="test"; filename="test.php" | ||
| 11 | --blabla-- | ||
| 12 | --FILE-- | ||
| 13 | <?php | ||
| 14 | var_dump($_FILES); | ||
| 15 | echo "\n\n\n\n\n\n\n\n\n\n\n\n\n\n"; | ||
| 16 | ?> | ||
| 17 | --EXPECTF-- | ||
| 18 | array(1) { | ||
| 19 | ["test"]=> | ||
| 20 | array(5) { | ||
| 21 | ["name"]=> | ||
| 22 | string(8) "test.php" | ||
| 23 | ["type"]=> | ||
| 24 | string(0) "" | ||
| 25 | ["tmp_name"]=> | ||
| 26 | string(0) "" | ||
| 27 | ["error"]=> | ||
| 28 | int(3) | ||
| 29 | ["size"]=> | ||
| 30 | int(0) | ||
| 31 | } | ||
| 32 | } | ||
diff --git a/src/tests/upload_validation_nocrash.phpt b/src/tests/upload_validation_nocrash.phpt new file mode 100644 index 0000000..6fa50d0 --- /dev/null +++ b/src/tests/upload_validation_nocrash.phpt | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | --TEST-- | ||
| 2 | Upload validation isn't crashing | ||
| 3 | --INI-- | ||
| 4 | file_uploads=1 | ||
| 5 | sp.configuration_file={PWD}/config/upload_validation_ok.ini | ||
| 6 | output_buffering=off | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | echo 1; | ||
| 10 | ?> | ||
| 11 | --EXPECTF-- | ||
| 12 | 1 | ||
diff --git a/src/tests/upload_validation_ok.phpt b/src/tests/upload_validation_ok.phpt new file mode 100644 index 0000000..f9b5015 --- /dev/null +++ b/src/tests/upload_validation_ok.phpt | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | --TEST-- | ||
| 2 | Upload a file, validation ok, no simulation | ||
| 3 | --INI-- | ||
| 4 | file_uploads=1 | ||
| 5 | sp.configuration_file={PWD}/config/upload_validation_ok.ini | ||
| 6 | output_buffering=off | ||
| 7 | --POST_RAW-- | ||
| 8 | Content-Type: multipart/form-data; boundary=blabla | ||
| 9 | --blabla | ||
| 10 | Content-Disposition: form-data; name="test"; filename="test.php" | ||
| 11 | --blabla-- | ||
| 12 | --FILE-- | ||
| 13 | <?php | ||
| 14 | echo 1; | ||
| 15 | ?> | ||
| 16 | --EXPECTF-- | ||
| 17 | 1 | ||
diff --git a/src/tweetnacl.c b/src/tweetnacl.c new file mode 100644 index 0000000..937e879 --- /dev/null +++ b/src/tweetnacl.c | |||
| @@ -0,0 +1,842 @@ | |||
| 1 | #include "tweetnacl.h" | ||
| 2 | #define FOR(i,n) for (i = 0;i < n;++i) | ||
| 3 | #define sv static void | ||
| 4 | |||
| 5 | typedef unsigned char u8; | ||
| 6 | typedef unsigned long u32; | ||
| 7 | typedef unsigned long long u64; | ||
| 8 | typedef long long i64; | ||
| 9 | typedef i64 gf[16]; | ||
| 10 | |||
| 11 | |||
| 12 | /* it's really stupid that there isn't a syscall for this */ | ||
| 13 | |||
| 14 | static int fd = -1; | ||
| 15 | |||
| 16 | void randombytes(unsigned char *x,unsigned long long xlen) | ||
| 17 | { | ||
| 18 | int i; | ||
| 19 | |||
| 20 | if (fd == -1) { | ||
| 21 | for (;;) { | ||
| 22 | fd = open("/dev/urandom",O_RDONLY); | ||
| 23 | if (fd != -1) break; | ||
| 24 | sleep(1); | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
| 28 | while (xlen > 0) { | ||
| 29 | if (xlen < 1048576) i = xlen; else i = 1048576; | ||
| 30 | |||
| 31 | i = read(fd,x,i); | ||
| 32 | if (i < 1) { | ||
| 33 | sleep(1); | ||
| 34 | continue; | ||
| 35 | } | ||
| 36 | |||
| 37 | x += i; | ||
| 38 | xlen -= i; | ||
| 39 | } | ||
| 40 | } | ||
| 41 | |||
| 42 | |||
| 43 | static const u8 | ||
| 44 | _0[16], | ||
| 45 | _9[32] = {9}; | ||
| 46 | static const gf | ||
| 47 | gf0, | ||
| 48 | gf1 = {1}, | ||
| 49 | _121665 = {0xDB41,1}, | ||
| 50 | D = {0x78a3, 0x1359, 0x4dca, 0x75eb, 0xd8ab, 0x4141, 0x0a4d, 0x0070, 0xe898, 0x7779, 0x4079, 0x8cc7, 0xfe73, 0x2b6f, 0x6cee, 0x5203}, | ||
| 51 | D2 = {0xf159, 0x26b2, 0x9b94, 0xebd6, 0xb156, 0x8283, 0x149a, 0x00e0, 0xd130, 0xeef3, 0x80f2, 0x198e, 0xfce7, 0x56df, 0xd9dc, 0x2406}, | ||
| 52 | X = {0xd51a, 0x8f25, 0x2d60, 0xc956, 0xa7b2, 0x9525, 0xc760, 0x692c, 0xdc5c, 0xfdd6, 0xe231, 0xc0a4, 0x53fe, 0xcd6e, 0x36d3, 0x2169}, | ||
| 53 | Y = {0x6658, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666}, | ||
| 54 | I = {0xa0b0, 0x4a0e, 0x1b27, 0xc4ee, 0xe478, 0xad2f, 0x1806, 0x2f43, 0xd7a7, 0x3dfb, 0x0099, 0x2b4d, 0xdf0b, 0x4fc1, 0x2480, 0x2b83}; | ||
| 55 | |||
| 56 | static u32 L32(u32 x,int c) { return (x << c) | ((x&0xffffffff) >> (32 - c)); } | ||
| 57 | |||
| 58 | static u32 ld32(const u8 *x) | ||
| 59 | { | ||
| 60 | u32 u = x[3]; | ||
| 61 | u = (u<<8)|x[2]; | ||
| 62 | u = (u<<8)|x[1]; | ||
| 63 | return (u<<8)|x[0]; | ||
| 64 | } | ||
| 65 | |||
| 66 | static u64 dl64(const u8 *x) | ||
| 67 | { | ||
| 68 | u64 i,u=0; | ||
| 69 | FOR(i,8) u=(u<<8)|x[i]; | ||
| 70 | return u; | ||
| 71 | } | ||
| 72 | |||
| 73 | sv st32(u8 *x,u32 u) | ||
| 74 | { | ||
| 75 | int i; | ||
| 76 | FOR(i,4) { x[i] = u; u >>= 8; } | ||
| 77 | } | ||
| 78 | |||
| 79 | sv ts64(u8 *x,u64 u) | ||
| 80 | { | ||
| 81 | int i; | ||
| 82 | for (i = 7;i >= 0;--i) { x[i] = u; u >>= 8; } | ||
| 83 | } | ||
| 84 | |||
| 85 | static int vn(const u8 *x,const u8 *y,int n) | ||
| 86 | { | ||
| 87 | int i = 0; | ||
| 88 | u32 d = 0; | ||
| 89 | FOR(i,n) d |= x[i]^y[i]; | ||
| 90 | return (1 & ((d - 1) >> 8)) - 1; | ||
| 91 | } | ||
| 92 | |||
| 93 | int crypto_verify_16(const u8 *x,const u8 *y) | ||
| 94 | { | ||
| 95 | return vn(x,y,16); | ||
| 96 | } | ||
| 97 | |||
| 98 | int crypto_verify_32(const u8 *x,const u8 *y) | ||
| 99 | { | ||
| 100 | return vn(x,y,32); | ||
| 101 | } | ||
| 102 | |||
| 103 | sv core(u8 *out,const u8 *in,const u8 *k,const u8 *c,int h) | ||
| 104 | { | ||
| 105 | u32 w[16],x[16],y[16],t[4]; | ||
| 106 | int i,j,m; | ||
| 107 | |||
| 108 | FOR(i,4) { | ||
| 109 | x[5*i] = ld32(c+4*i); | ||
| 110 | x[1+i] = ld32(k+4*i); | ||
| 111 | x[6+i] = ld32(in+4*i); | ||
| 112 | x[11+i] = ld32(k+16+4*i); | ||
| 113 | } | ||
| 114 | |||
| 115 | FOR(i,16) y[i] = x[i]; | ||
| 116 | |||
| 117 | FOR(i,20) { | ||
| 118 | FOR(j,4) { | ||
| 119 | FOR(m,4) t[m] = x[(5*j+4*m)%16]; | ||
| 120 | t[1] ^= L32(t[0]+t[3], 7); | ||
| 121 | t[2] ^= L32(t[1]+t[0], 9); | ||
| 122 | t[3] ^= L32(t[2]+t[1],13); | ||
| 123 | t[0] ^= L32(t[3]+t[2],18); | ||
| 124 | FOR(m,4) w[4*j+(j+m)%4] = t[m]; | ||
| 125 | } | ||
| 126 | FOR(m,16) x[m] = w[m]; | ||
| 127 | } | ||
| 128 | |||
| 129 | if (h) { | ||
| 130 | FOR(i,16) x[i] += y[i]; | ||
| 131 | FOR(i,4) { | ||
| 132 | x[5*i] -= ld32(c+4*i); | ||
| 133 | x[6+i] -= ld32(in+4*i); | ||
| 134 | } | ||
| 135 | FOR(i,4) { | ||
| 136 | st32(out+4*i,x[5*i]); | ||
| 137 | st32(out+16+4*i,x[6+i]); | ||
| 138 | } | ||
| 139 | } else | ||
| 140 | FOR(i,16) st32(out + 4 * i,x[i] + y[i]); | ||
| 141 | } | ||
| 142 | |||
| 143 | int crypto_core_salsa20(u8 *out,const u8 *in,const u8 *k,const u8 *c) | ||
| 144 | { | ||
| 145 | core(out,in,k,c,0); | ||
| 146 | return 0; | ||
| 147 | } | ||
| 148 | |||
| 149 | int crypto_core_hsalsa20(u8 *out,const u8 *in,const u8 *k,const u8 *c) | ||
| 150 | { | ||
| 151 | core(out,in,k,c,1); | ||
| 152 | return 0; | ||
| 153 | } | ||
| 154 | |||
| 155 | static const u8 sigma[16] = "expand 32-byte k"; | ||
| 156 | |||
| 157 | int crypto_stream_salsa20_xor(u8 *c,const u8 *m,u64 b,const u8 *n,const u8 *k) | ||
| 158 | { | ||
| 159 | u8 z[16],x[64]; | ||
| 160 | u32 u,i; | ||
| 161 | if (!b) return 0; | ||
| 162 | FOR(i,16) z[i] = 0; | ||
| 163 | FOR(i,8) z[i] = n[i]; | ||
| 164 | while (b >= 64) { | ||
| 165 | crypto_core_salsa20(x,z,k,sigma); | ||
| 166 | FOR(i,64) c[i] = (m?m[i]:0) ^ x[i]; | ||
| 167 | u = 1; | ||
| 168 | for (i = 8;i < 16;++i) { | ||
| 169 | u += (u32) z[i]; | ||
| 170 | z[i] = u; | ||
| 171 | u >>= 8; | ||
| 172 | } | ||
| 173 | b -= 64; | ||
| 174 | c += 64; | ||
| 175 | if (m) m += 64; | ||
| 176 | } | ||
| 177 | if (b) { | ||
| 178 | crypto_core_salsa20(x,z,k,sigma); | ||
| 179 | FOR(i,b) c[i] = (m?m[i]:0) ^ x[i]; | ||
| 180 | } | ||
| 181 | return 0; | ||
| 182 | } | ||
| 183 | |||
| 184 | int crypto_stream_salsa20(u8 *c,u64 d,const u8 *n,const u8 *k) | ||
| 185 | { | ||
| 186 | return crypto_stream_salsa20_xor(c,0,d,n,k); | ||
| 187 | } | ||
| 188 | |||
| 189 | int crypto_stream(u8 *c,u64 d,const u8 *n,const u8 *k) | ||
| 190 | { | ||
| 191 | u8 s[32]; | ||
| 192 | crypto_core_hsalsa20(s,n,k,sigma); | ||
| 193 | return crypto_stream_salsa20(c,d,n+16,s); | ||
| 194 | } | ||
| 195 | |||
| 196 | int crypto_stream_xor(u8 *c,const u8 *m,u64 d,const u8 *n,const u8 *k) | ||
| 197 | { | ||
| 198 | u8 s[32]; | ||
| 199 | crypto_core_hsalsa20(s,n,k,sigma); | ||
| 200 | return crypto_stream_salsa20_xor(c,m,d,n+16,s); | ||
| 201 | } | ||
| 202 | |||
| 203 | sv add1305(u32 *h,const u32 *c) | ||
| 204 | { | ||
| 205 | u32 j,u = 0; | ||
| 206 | FOR(j,17) { | ||
| 207 | u += h[j] + c[j]; | ||
| 208 | h[j] = u & 255; | ||
| 209 | u >>= 8; | ||
| 210 | } | ||
| 211 | } | ||
| 212 | |||
| 213 | static const u32 minusp[17] = { | ||
| 214 | 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 252 | ||
| 215 | } ; | ||
| 216 | |||
| 217 | int crypto_onetimeauth(u8 *out,const u8 *m,u64 n,const u8 *k) | ||
| 218 | { | ||
| 219 | u32 s,i,j,u,x[17],r[17],h[17],c[17],g[17]; | ||
| 220 | |||
| 221 | FOR(j,17) r[j]=h[j]=0; | ||
| 222 | FOR(j,16) r[j]=k[j]; | ||
| 223 | r[3]&=15; | ||
| 224 | r[4]&=252; | ||
| 225 | r[7]&=15; | ||
| 226 | r[8]&=252; | ||
| 227 | r[11]&=15; | ||
| 228 | r[12]&=252; | ||
| 229 | r[15]&=15; | ||
| 230 | |||
| 231 | while (n > 0) { | ||
| 232 | FOR(j,17) c[j] = 0; | ||
| 233 | for (j = 0;(j < 16) && (j < n);++j) c[j] = m[j]; | ||
| 234 | c[j] = 1; | ||
| 235 | m += j; n -= j; | ||
| 236 | add1305(h,c); | ||
| 237 | FOR(i,17) { | ||
| 238 | x[i] = 0; | ||
| 239 | FOR(j,17) x[i] += h[j] * ((j <= i) ? r[i - j] : 320 * r[i + 17 - j]); | ||
| 240 | } | ||
| 241 | FOR(i,17) h[i] = x[i]; | ||
| 242 | u = 0; | ||
| 243 | FOR(j,16) { | ||
| 244 | u += h[j]; | ||
| 245 | h[j] = u & 255; | ||
| 246 | u >>= 8; | ||
| 247 | } | ||
| 248 | u += h[16]; h[16] = u & 3; | ||
| 249 | u = 5 * (u >> 2); | ||
| 250 | FOR(j,16) { | ||
| 251 | u += h[j]; | ||
| 252 | h[j] = u & 255; | ||
| 253 | u >>= 8; | ||
| 254 | } | ||
| 255 | u += h[16]; h[16] = u; | ||
| 256 | } | ||
| 257 | |||
| 258 | FOR(j,17) g[j] = h[j]; | ||
| 259 | add1305(h,minusp); | ||
| 260 | s = -(h[16] >> 7); | ||
| 261 | FOR(j,17) h[j] ^= s & (g[j] ^ h[j]); | ||
| 262 | |||
| 263 | FOR(j,16) c[j] = k[j + 16]; | ||
| 264 | c[16] = 0; | ||
| 265 | add1305(h,c); | ||
| 266 | FOR(j,16) out[j] = h[j]; | ||
| 267 | return 0; | ||
| 268 | } | ||
| 269 | |||
| 270 | int crypto_onetimeauth_verify(const u8 *h,const u8 *m,u64 n,const u8 *k) | ||
| 271 | { | ||
| 272 | u8 x[16]; | ||
| 273 | crypto_onetimeauth(x,m,n,k); | ||
| 274 | return crypto_verify_16(h,x); | ||
| 275 | } | ||
| 276 | |||
| 277 | int crypto_secretbox(u8 *c,const u8 *m,u64 d,const u8 *n,const u8 *k) | ||
| 278 | { | ||
| 279 | int i; | ||
| 280 | if (d < 32) return -1; | ||
| 281 | crypto_stream_xor(c,m,d,n,k); | ||
| 282 | crypto_onetimeauth(c + 16,c + 32,d - 32,c); | ||
| 283 | FOR(i,16) c[i] = 0; | ||
| 284 | return 0; | ||
| 285 | } | ||
| 286 | |||
| 287 | int crypto_secretbox_open(u8 *m,const u8 *c,u64 d,const u8 *n,const u8 *k) | ||
| 288 | { | ||
| 289 | int i; | ||
| 290 | u8 x[32]; | ||
| 291 | if (d < 32) return -1; | ||
| 292 | crypto_stream(x,32,n,k); | ||
| 293 | if (crypto_onetimeauth_verify(c + 16,c + 32,d - 32,x) != 0) return -1; | ||
| 294 | crypto_stream_xor(m,c,d,n,k); | ||
| 295 | FOR(i,32) m[i] = 0; | ||
| 296 | return 0; | ||
| 297 | } | ||
| 298 | |||
| 299 | sv set25519(gf r, const gf a) | ||
| 300 | { | ||
| 301 | int i; | ||
| 302 | FOR(i,16) r[i]=a[i]; | ||
| 303 | } | ||
| 304 | |||
| 305 | sv car25519(gf o) | ||
| 306 | { | ||
| 307 | int i; | ||
| 308 | i64 c; | ||
| 309 | FOR(i,16) { | ||
| 310 | o[i]+=(1LL<<16); | ||
| 311 | c=o[i]>>16; | ||
| 312 | o[(i+1)*(i<15)]+=c-1+37*(c-1)*(i==15); | ||
| 313 | o[i]-=c<<16; | ||
| 314 | } | ||
| 315 | } | ||
| 316 | |||
| 317 | sv sel25519(gf p,gf q,int b) | ||
| 318 | { | ||
| 319 | i64 t,i,c=~(b-1); | ||
| 320 | FOR(i,16) { | ||
| 321 | t= c&(p[i]^q[i]); | ||
| 322 | p[i]^=t; | ||
| 323 | q[i]^=t; | ||
| 324 | } | ||
| 325 | } | ||
| 326 | |||
| 327 | sv pack25519(u8 *o,const gf n) | ||
| 328 | { | ||
| 329 | int i,j,b; | ||
| 330 | gf m,t; | ||
| 331 | FOR(i,16) t[i]=n[i]; | ||
| 332 | car25519(t); | ||
| 333 | car25519(t); | ||
| 334 | car25519(t); | ||
| 335 | FOR(j,2) { | ||
| 336 | m[0]=t[0]-0xffed; | ||
| 337 | for(i=1;i<15;i++) { | ||
| 338 | m[i]=t[i]-0xffff-((m[i-1]>>16)&1); | ||
| 339 | m[i-1]&=0xffff; | ||
| 340 | } | ||
| 341 | m[15]=t[15]-0x7fff-((m[14]>>16)&1); | ||
| 342 | b=(m[15]>>16)&1; | ||
| 343 | m[14]&=0xffff; | ||
| 344 | sel25519(t,m,1-b); | ||
| 345 | } | ||
| 346 | FOR(i,16) { | ||
| 347 | o[2*i]=t[i]&0xff; | ||
| 348 | o[2*i+1]=t[i]>>8; | ||
| 349 | } | ||
| 350 | } | ||
| 351 | |||
| 352 | static int neq25519(const gf a, const gf b) | ||
| 353 | { | ||
| 354 | u8 c[32],d[32]; | ||
| 355 | pack25519(c,a); | ||
| 356 | pack25519(d,b); | ||
| 357 | return crypto_verify_32(c,d); | ||
| 358 | } | ||
| 359 | |||
| 360 | static u8 par25519(const gf a) | ||
| 361 | { | ||
| 362 | u8 d[32]; | ||
| 363 | pack25519(d,a); | ||
| 364 | return d[0]&1; | ||
| 365 | } | ||
| 366 | |||
| 367 | sv unpack25519(gf o, const u8 *n) | ||
| 368 | { | ||
| 369 | int i; | ||
| 370 | FOR(i,16) o[i]=n[2*i]+((i64)n[2*i+1]<<8); | ||
| 371 | o[15]&=0x7fff; | ||
| 372 | } | ||
| 373 | |||
| 374 | sv A(gf o,const gf a,const gf b) | ||
| 375 | { | ||
| 376 | int i; | ||
| 377 | FOR(i,16) o[i]=a[i]+b[i]; | ||
| 378 | } | ||
| 379 | |||
| 380 | sv Z(gf o,const gf a,const gf b) | ||
| 381 | { | ||
| 382 | int i; | ||
| 383 | FOR(i,16) o[i]=a[i]-b[i]; | ||
| 384 | } | ||
| 385 | |||
| 386 | sv M(gf o,const gf a,const gf b) | ||
| 387 | { | ||
| 388 | i64 i,j,t[31]; | ||
| 389 | FOR(i,31) t[i]=0; | ||
| 390 | FOR(i,16) FOR(j,16) t[i+j]+=a[i]*b[j]; | ||
| 391 | FOR(i,15) t[i]+=38*t[i+16]; | ||
| 392 | FOR(i,16) o[i]=t[i]; | ||
| 393 | car25519(o); | ||
| 394 | car25519(o); | ||
| 395 | } | ||
| 396 | |||
| 397 | sv S(gf o,const gf a) | ||
| 398 | { | ||
| 399 | M(o,a,a); | ||
| 400 | } | ||
| 401 | |||
| 402 | sv inv25519(gf o,const gf i) | ||
| 403 | { | ||
| 404 | gf c; | ||
| 405 | int a; | ||
| 406 | FOR(a,16) c[a]=i[a]; | ||
| 407 | for(a=253;a>=0;a--) { | ||
| 408 | S(c,c); | ||
| 409 | if(a!=2&&a!=4) M(c,c,i); | ||
| 410 | } | ||
| 411 | FOR(a,16) o[a]=c[a]; | ||
| 412 | } | ||
| 413 | |||
| 414 | sv pow2523(gf o,const gf i) | ||
| 415 | { | ||
| 416 | gf c; | ||
| 417 | int a; | ||
| 418 | FOR(a,16) c[a]=i[a]; | ||
| 419 | for(a=250;a>=0;a--) { | ||
| 420 | S(c,c); | ||
| 421 | if(a!=1) M(c,c,i); | ||
| 422 | } | ||
| 423 | FOR(a,16) o[a]=c[a]; | ||
| 424 | } | ||
| 425 | |||
| 426 | int crypto_scalarmult(u8 *q,const u8 *n,const u8 *p) | ||
| 427 | { | ||
| 428 | u8 z[32]; | ||
| 429 | i64 x[80],r,i; | ||
| 430 | gf a,b,c,d,e,f; | ||
| 431 | FOR(i,31) z[i]=n[i]; | ||
| 432 | z[31]=(n[31]&127)|64; | ||
| 433 | z[0]&=248; | ||
| 434 | unpack25519(x,p); | ||
| 435 | FOR(i,16) { | ||
| 436 | b[i]=x[i]; | ||
| 437 | d[i]=a[i]=c[i]=0; | ||
| 438 | } | ||
| 439 | a[0]=d[0]=1; | ||
| 440 | for(i=254;i>=0;--i) { | ||
| 441 | r=(z[i>>3]>>(i&7))&1; | ||
| 442 | sel25519(a,b,r); | ||
| 443 | sel25519(c,d,r); | ||
| 444 | A(e,a,c); | ||
| 445 | Z(a,a,c); | ||
| 446 | A(c,b,d); | ||
| 447 | Z(b,b,d); | ||
| 448 | S(d,e); | ||
| 449 | S(f,a); | ||
| 450 | M(a,c,a); | ||
| 451 | M(c,b,e); | ||
| 452 | A(e,a,c); | ||
| 453 | Z(a,a,c); | ||
| 454 | S(b,a); | ||
| 455 | Z(c,d,f); | ||
| 456 | M(a,c,_121665); | ||
| 457 | A(a,a,d); | ||
| 458 | M(c,c,a); | ||
| 459 | M(a,d,f); | ||
| 460 | M(d,b,x); | ||
| 461 | S(b,e); | ||
| 462 | sel25519(a,b,r); | ||
| 463 | sel25519(c,d,r); | ||
| 464 | } | ||
| 465 | FOR(i,16) { | ||
| 466 | x[i+16]=a[i]; | ||
| 467 | x[i+32]=c[i]; | ||
| 468 | x[i+48]=b[i]; | ||
| 469 | x[i+64]=d[i]; | ||
| 470 | } | ||
| 471 | inv25519(x+32,x+32); | ||
| 472 | M(x+16,x+16,x+32); | ||
| 473 | pack25519(q,x+16); | ||
| 474 | return 0; | ||
| 475 | } | ||
| 476 | |||
| 477 | int crypto_scalarmult_base(u8 *q,const u8 *n) | ||
| 478 | { | ||
| 479 | return crypto_scalarmult(q,n,_9); | ||
| 480 | } | ||
| 481 | |||
| 482 | int crypto_box_keypair(u8 *y,u8 *x) | ||
| 483 | { | ||
| 484 | randombytes(x,32); | ||
| 485 | return crypto_scalarmult_base(y,x); | ||
| 486 | } | ||
| 487 | |||
| 488 | int crypto_box_beforenm(u8 *k,const u8 *y,const u8 *x) | ||
| 489 | { | ||
| 490 | u8 s[32]; | ||
| 491 | crypto_scalarmult(s,x,y); | ||
| 492 | return crypto_core_hsalsa20(k,_0,s,sigma); | ||
| 493 | } | ||
| 494 | |||
| 495 | int crypto_box_afternm(u8 *c,const u8 *m,u64 d,const u8 *n,const u8 *k) | ||
| 496 | { | ||
| 497 | return crypto_secretbox(c,m,d,n,k); | ||
| 498 | } | ||
| 499 | |||
| 500 | int crypto_box_open_afternm(u8 *m,const u8 *c,u64 d,const u8 *n,const u8 *k) | ||
| 501 | { | ||
| 502 | return crypto_secretbox_open(m,c,d,n,k); | ||
| 503 | } | ||
| 504 | |||
| 505 | int crypto_box(u8 *c,const u8 *m,u64 d,const u8 *n,const u8 *y,const u8 *x) | ||
| 506 | { | ||
| 507 | u8 k[32]; | ||
| 508 | crypto_box_beforenm(k,y,x); | ||
| 509 | return crypto_box_afternm(c,m,d,n,k); | ||
| 510 | } | ||
| 511 | |||
| 512 | int crypto_box_open(u8 *m,const u8 *c,u64 d,const u8 *n,const u8 *y,const u8 *x) | ||
| 513 | { | ||
| 514 | u8 k[32]; | ||
| 515 | crypto_box_beforenm(k,y,x); | ||
| 516 | return crypto_box_open_afternm(m,c,d,n,k); | ||
| 517 | } | ||
| 518 | |||
| 519 | static u64 R(u64 x,int c) { return (x >> c) | (x << (64 - c)); } | ||
| 520 | static u64 Ch(u64 x,u64 y,u64 z) { return (x & y) ^ (~x & z); } | ||
| 521 | static u64 Maj(u64 x,u64 y,u64 z) { return (x & y) ^ (x & z) ^ (y & z); } | ||
| 522 | static u64 Sigma0(u64 x) { return R(x,28) ^ R(x,34) ^ R(x,39); } | ||
| 523 | static u64 Sigma1(u64 x) { return R(x,14) ^ R(x,18) ^ R(x,41); } | ||
| 524 | static u64 sigma0(u64 x) { return R(x, 1) ^ R(x, 8) ^ (x >> 7); } | ||
| 525 | static u64 sigma1(u64 x) { return R(x,19) ^ R(x,61) ^ (x >> 6); } | ||
| 526 | |||
| 527 | static const u64 K[80] = | ||
| 528 | { | ||
| 529 | 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, | ||
| 530 | 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, | ||
| 531 | 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, | ||
| 532 | 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, | ||
| 533 | 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, | ||
| 534 | 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, | ||
| 535 | 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, | ||
| 536 | 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, | ||
| 537 | 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, | ||
| 538 | 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, | ||
| 539 | 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, | ||
| 540 | 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, | ||
| 541 | 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, | ||
| 542 | 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, | ||
| 543 | 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, | ||
| 544 | 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, | ||
| 545 | 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, | ||
| 546 | 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, | ||
| 547 | 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, | ||
| 548 | 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL | ||
| 549 | }; | ||
| 550 | |||
| 551 | int crypto_hashblocks(u8 *x,const u8 *m,u64 n) | ||
| 552 | { | ||
| 553 | u64 z[8],b[8],a[8],w[16],t; | ||
| 554 | int i,j; | ||
| 555 | |||
| 556 | FOR(i,8) z[i] = a[i] = dl64(x + 8 * i); | ||
| 557 | |||
| 558 | while (n >= 128) { | ||
| 559 | FOR(i,16) w[i] = dl64(m + 8 * i); | ||
| 560 | |||
| 561 | FOR(i,80) { | ||
| 562 | FOR(j,8) b[j] = a[j]; | ||
| 563 | t = a[7] + Sigma1(a[4]) + Ch(a[4],a[5],a[6]) + K[i] + w[i%16]; | ||
| 564 | b[7] = t + Sigma0(a[0]) + Maj(a[0],a[1],a[2]); | ||
| 565 | b[3] += t; | ||
| 566 | FOR(j,8) a[(j+1)%8] = b[j]; | ||
| 567 | if (i%16 == 15) | ||
| 568 | FOR(j,16) | ||
| 569 | w[j] += w[(j+9)%16] + sigma0(w[(j+1)%16]) + sigma1(w[(j+14)%16]); | ||
| 570 | } | ||
| 571 | |||
| 572 | FOR(i,8) { a[i] += z[i]; z[i] = a[i]; } | ||
| 573 | |||
| 574 | m += 128; | ||
| 575 | n -= 128; | ||
| 576 | } | ||
| 577 | |||
| 578 | FOR(i,8) ts64(x+8*i,z[i]); | ||
| 579 | |||
| 580 | return n; | ||
| 581 | } | ||
| 582 | |||
| 583 | static const u8 iv[64] = { | ||
| 584 | 0x6a,0x09,0xe6,0x67,0xf3,0xbc,0xc9,0x08, | ||
| 585 | 0xbb,0x67,0xae,0x85,0x84,0xca,0xa7,0x3b, | ||
| 586 | 0x3c,0x6e,0xf3,0x72,0xfe,0x94,0xf8,0x2b, | ||
| 587 | 0xa5,0x4f,0xf5,0x3a,0x5f,0x1d,0x36,0xf1, | ||
| 588 | 0x51,0x0e,0x52,0x7f,0xad,0xe6,0x82,0xd1, | ||
| 589 | 0x9b,0x05,0x68,0x8c,0x2b,0x3e,0x6c,0x1f, | ||
| 590 | 0x1f,0x83,0xd9,0xab,0xfb,0x41,0xbd,0x6b, | ||
| 591 | 0x5b,0xe0,0xcd,0x19,0x13,0x7e,0x21,0x79 | ||
| 592 | } ; | ||
| 593 | |||
| 594 | int crypto_hash(u8 *out,const u8 *m,u64 n) | ||
| 595 | { | ||
| 596 | u8 h[64],x[256]; | ||
| 597 | u64 i,b = n; | ||
| 598 | |||
| 599 | FOR(i,64) h[i] = iv[i]; | ||
| 600 | |||
| 601 | crypto_hashblocks(h,m,n); | ||
| 602 | m += n; | ||
| 603 | n &= 127; | ||
| 604 | m -= n; | ||
| 605 | |||
| 606 | FOR(i,256) x[i] = 0; | ||
| 607 | FOR(i,n) x[i] = m[i]; | ||
| 608 | x[n] = 128; | ||
| 609 | |||
| 610 | n = 256-128*(n<112); | ||
| 611 | x[n-9] = b >> 61; | ||
| 612 | ts64(x+n-8,b<<3); | ||
| 613 | crypto_hashblocks(h,x,n); | ||
| 614 | |||
| 615 | FOR(i,64) out[i] = h[i]; | ||
| 616 | |||
| 617 | return 0; | ||
| 618 | } | ||
| 619 | |||
| 620 | sv add(gf p[4],gf q[4]) | ||
| 621 | { | ||
| 622 | gf a,b,c,d,t,e,f,g,h; | ||
| 623 | |||
| 624 | Z(a, p[1], p[0]); | ||
| 625 | Z(t, q[1], q[0]); | ||
| 626 | M(a, a, t); | ||
| 627 | A(b, p[0], p[1]); | ||
| 628 | A(t, q[0], q[1]); | ||
| 629 | M(b, b, t); | ||
| 630 | M(c, p[3], q[3]); | ||
| 631 | M(c, c, D2); | ||
| 632 | M(d, p[2], q[2]); | ||
| 633 | A(d, d, d); | ||
| 634 | Z(e, b, a); | ||
| 635 | Z(f, d, c); | ||
| 636 | A(g, d, c); | ||
| 637 | A(h, b, a); | ||
| 638 | |||
| 639 | M(p[0], e, f); | ||
| 640 | M(p[1], h, g); | ||
| 641 | M(p[2], g, f); | ||
| 642 | M(p[3], e, h); | ||
| 643 | } | ||
| 644 | |||
| 645 | sv cswap(gf p[4],gf q[4],u8 b) | ||
| 646 | { | ||
| 647 | int i; | ||
| 648 | FOR(i,4) | ||
| 649 | sel25519(p[i],q[i],b); | ||
| 650 | } | ||
| 651 | |||
| 652 | sv pack(u8 *r,gf p[4]) | ||
| 653 | { | ||
| 654 | gf tx, ty, zi; | ||
| 655 | inv25519(zi, p[2]); | ||
| 656 | M(tx, p[0], zi); | ||
| 657 | M(ty, p[1], zi); | ||
| 658 | pack25519(r, ty); | ||
| 659 | r[31] ^= par25519(tx) << 7; | ||
| 660 | } | ||
| 661 | |||
| 662 | sv scalarmult(gf p[4],gf q[4],const u8 *s) | ||
| 663 | { | ||
| 664 | int i; | ||
| 665 | set25519(p[0],gf0); | ||
| 666 | set25519(p[1],gf1); | ||
| 667 | set25519(p[2],gf1); | ||
| 668 | set25519(p[3],gf0); | ||
| 669 | for (i = 255;i >= 0;--i) { | ||
| 670 | u8 b = (s[i/8]>>(i&7))&1; | ||
| 671 | cswap(p,q,b); | ||
| 672 | add(q,p); | ||
| 673 | add(p,p); | ||
| 674 | cswap(p,q,b); | ||
| 675 | } | ||
| 676 | } | ||
| 677 | |||
| 678 | sv scalarbase(gf p[4],const u8 *s) | ||
| 679 | { | ||
| 680 | gf q[4]; | ||
| 681 | set25519(q[0],X); | ||
| 682 | set25519(q[1],Y); | ||
| 683 | set25519(q[2],gf1); | ||
| 684 | M(q[3],X,Y); | ||
| 685 | scalarmult(p,q,s); | ||
| 686 | } | ||
| 687 | |||
| 688 | int crypto_sign_keypair(u8 *pk, u8 *sk) | ||
| 689 | { | ||
| 690 | u8 d[64]; | ||
| 691 | gf p[4]; | ||
| 692 | int i; | ||
| 693 | |||
| 694 | randombytes(sk, 32); | ||
| 695 | crypto_hash(d, sk, 32); | ||
| 696 | d[0] &= 248; | ||
| 697 | d[31] &= 127; | ||
| 698 | d[31] |= 64; | ||
| 699 | |||
| 700 | scalarbase(p,d); | ||
| 701 | pack(pk,p); | ||
| 702 | |||
| 703 | FOR(i,32) sk[32 + i] = pk[i]; | ||
| 704 | return 0; | ||
| 705 | } | ||
| 706 | |||
| 707 | static const u64 L[32] = {0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10}; | ||
| 708 | |||
| 709 | sv modL(u8 *r,i64 x[64]) | ||
| 710 | { | ||
| 711 | i64 carry,i,j; | ||
| 712 | for (i = 63;i >= 32;--i) { | ||
| 713 | carry = 0; | ||
| 714 | for (j = i - 32;j < i - 12;++j) { | ||
| 715 | x[j] += carry - 16 * x[i] * L[j - (i - 32)]; | ||
| 716 | carry = (x[j] + 128) >> 8; | ||
| 717 | x[j] -= carry << 8; | ||
| 718 | } | ||
| 719 | x[j] += carry; | ||
| 720 | x[i] = 0; | ||
| 721 | } | ||
| 722 | carry = 0; | ||
| 723 | FOR(j,32) { | ||
| 724 | x[j] += carry - (x[31] >> 4) * L[j]; | ||
| 725 | carry = x[j] >> 8; | ||
| 726 | x[j] &= 255; | ||
| 727 | } | ||
| 728 | FOR(j,32) x[j] -= carry * L[j]; | ||
| 729 | FOR(i,32) { | ||
| 730 | x[i+1] += x[i] >> 8; | ||
| 731 | r[i] = x[i] & 255; | ||
| 732 | } | ||
| 733 | } | ||
| 734 | |||
| 735 | sv reduce(u8 *r) | ||
| 736 | { | ||
| 737 | i64 x[64],i; | ||
| 738 | FOR(i,64) x[i] = (u64) r[i]; | ||
| 739 | FOR(i,64) r[i] = 0; | ||
| 740 | modL(r,x); | ||
| 741 | } | ||
| 742 | |||
| 743 | int crypto_sign(u8 *sm,u64 *smlen,const u8 *m,u64 n,const u8 *sk) | ||
| 744 | { | ||
| 745 | u8 d[64],h[64],r[64]; | ||
| 746 | u64 i; | ||
| 747 | i64 j,x[64]; | ||
| 748 | gf p[4]; | ||
| 749 | |||
| 750 | crypto_hash(d, sk, 32); | ||
| 751 | d[0] &= 248; | ||
| 752 | d[31] &= 127; | ||
| 753 | d[31] |= 64; | ||
| 754 | |||
| 755 | *smlen = n+64; | ||
| 756 | FOR(i,n) sm[64 + i] = m[i]; | ||
| 757 | FOR(i,32) sm[32 + i] = d[32 + i]; | ||
| 758 | |||
| 759 | crypto_hash(r, sm+32, n+32); | ||
| 760 | reduce(r); | ||
| 761 | scalarbase(p,r); | ||
| 762 | pack(sm,p); | ||
| 763 | |||
| 764 | FOR(i,32) sm[i+32] = sk[i+32]; | ||
| 765 | crypto_hash(h,sm,n + 64); | ||
| 766 | reduce(h); | ||
| 767 | |||
| 768 | FOR(i,64) x[i] = 0; | ||
| 769 | FOR(i,32) x[i] = (u64) r[i]; | ||
| 770 | FOR(i,32) FOR(j,32) x[i+j] += h[i] * (u64) d[j]; | ||
| 771 | modL(sm + 32,x); | ||
| 772 | |||
| 773 | return 0; | ||
| 774 | } | ||
| 775 | |||
| 776 | static int unpackneg(gf r[4],const u8 p[32]) | ||
| 777 | { | ||
| 778 | gf t, chk, num, den, den2, den4, den6; | ||
| 779 | set25519(r[2],gf1); | ||
| 780 | unpack25519(r[1],p); | ||
| 781 | S(num,r[1]); | ||
| 782 | M(den,num,D); | ||
| 783 | Z(num,num,r[2]); | ||
| 784 | A(den,r[2],den); | ||
| 785 | |||
| 786 | S(den2,den); | ||
| 787 | S(den4,den2); | ||
| 788 | M(den6,den4,den2); | ||
| 789 | M(t,den6,num); | ||
| 790 | M(t,t,den); | ||
| 791 | |||
| 792 | pow2523(t,t); | ||
| 793 | M(t,t,num); | ||
| 794 | M(t,t,den); | ||
| 795 | M(t,t,den); | ||
| 796 | M(r[0],t,den); | ||
| 797 | |||
| 798 | S(chk,r[0]); | ||
| 799 | M(chk,chk,den); | ||
| 800 | if (neq25519(chk, num)) M(r[0],r[0],I); | ||
| 801 | |||
| 802 | S(chk,r[0]); | ||
| 803 | M(chk,chk,den); | ||
| 804 | if (neq25519(chk, num)) return -1; | ||
| 805 | |||
| 806 | if (par25519(r[0]) == (p[31]>>7)) Z(r[0],gf0,r[0]); | ||
| 807 | |||
| 808 | M(r[3],r[0],r[1]); | ||
| 809 | return 0; | ||
| 810 | } | ||
| 811 | |||
| 812 | int crypto_sign_open(u8 *m,u64 *mlen,const u8 *sm,u64 n,const u8 *pk) | ||
| 813 | { | ||
| 814 | u64 i; | ||
| 815 | u8 t[32],h[64]; | ||
| 816 | gf p[4],q[4]; | ||
| 817 | |||
| 818 | *mlen = -1; | ||
| 819 | if (n < 64) return -1; | ||
| 820 | |||
| 821 | if (unpackneg(q,pk)) return -1; | ||
| 822 | |||
| 823 | FOR(i,n) m[i] = sm[i]; | ||
| 824 | FOR(i,32) m[i+32] = pk[i]; | ||
| 825 | crypto_hash(h,m,n); | ||
| 826 | reduce(h); | ||
| 827 | scalarmult(p,q,h); | ||
| 828 | |||
| 829 | scalarbase(q,sm + 32); | ||
| 830 | add(p,q); | ||
| 831 | pack(t,p); | ||
| 832 | |||
| 833 | n -= 64; | ||
| 834 | if (crypto_verify_32(sm, t)) { | ||
| 835 | FOR(i,n) m[i] = 0; | ||
| 836 | return -1; | ||
| 837 | } | ||
| 838 | |||
| 839 | FOR(i,n) m[i] = sm[i + 64]; | ||
| 840 | *mlen = n; | ||
| 841 | return 0; | ||
| 842 | } | ||
diff --git a/src/tweetnacl.h b/src/tweetnacl.h new file mode 100644 index 0000000..508876d --- /dev/null +++ b/src/tweetnacl.h | |||
| @@ -0,0 +1,277 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <sys/stat.h> | ||
| 3 | #include <fcntl.h> | ||
| 4 | #include <unistd.h> | ||
| 5 | |||
| 6 | #ifndef TWEETNACL_H | ||
| 7 | #define TWEETNACL_H | ||
| 8 | #define crypto_auth_PRIMITIVE "hmacsha512256" | ||
| 9 | #define crypto_auth crypto_auth_hmacsha512256 | ||
| 10 | #define crypto_auth_verify crypto_auth_hmacsha512256_verify | ||
| 11 | #define crypto_auth_BYTES crypto_auth_hmacsha512256_BYTES | ||
| 12 | #define crypto_auth_KEYBYTES crypto_auth_hmacsha512256_KEYBYTES | ||
| 13 | #define crypto_auth_IMPLEMENTATION crypto_auth_hmacsha512256_IMPLEMENTATION | ||
| 14 | #define crypto_auth_VERSION crypto_auth_hmacsha512256_VERSION | ||
| 15 | #define crypto_auth_hmacsha512256_tweet_BYTES 32 | ||
| 16 | #define crypto_auth_hmacsha512256_tweet_KEYBYTES 32 | ||
| 17 | extern int crypto_auth_hmacsha512256_tweet(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *); | ||
| 18 | extern int crypto_auth_hmacsha512256_tweet_verify(const unsigned char *,const unsigned char *,unsigned long long,const unsigned char *); | ||
| 19 | #define crypto_auth_hmacsha512256_tweet_VERSION "-" | ||
| 20 | #define crypto_auth_hmacsha512256 crypto_auth_hmacsha512256_tweet | ||
| 21 | #define crypto_auth_hmacsha512256_verify crypto_auth_hmacsha512256_tweet_verify | ||
| 22 | #define crypto_auth_hmacsha512256_BYTES crypto_auth_hmacsha512256_tweet_BYTES | ||
| 23 | #define crypto_auth_hmacsha512256_KEYBYTES crypto_auth_hmacsha512256_tweet_KEYBYTES | ||
| 24 | #define crypto_auth_hmacsha512256_VERSION crypto_auth_hmacsha512256_tweet_VERSION | ||
| 25 | #define crypto_auth_hmacsha512256_IMPLEMENTATION "crypto_auth/hmacsha512256/tweet" | ||
| 26 | #define crypto_box_PRIMITIVE "curve25519xsalsa20poly1305" | ||
| 27 | #define crypto_box crypto_box_curve25519xsalsa20poly1305 | ||
| 28 | #define crypto_box_open crypto_box_curve25519xsalsa20poly1305_open | ||
| 29 | #define crypto_box_keypair crypto_box_curve25519xsalsa20poly1305_keypair | ||
| 30 | #define crypto_box_beforenm crypto_box_curve25519xsalsa20poly1305_beforenm | ||
| 31 | #define crypto_box_afternm crypto_box_curve25519xsalsa20poly1305_afternm | ||
| 32 | #define crypto_box_open_afternm crypto_box_curve25519xsalsa20poly1305_open_afternm | ||
| 33 | #define crypto_box_PUBLICKEYBYTES crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES | ||
| 34 | #define crypto_box_SECRETKEYBYTES crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES | ||
| 35 | #define crypto_box_BEFORENMBYTES crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES | ||
| 36 | #define crypto_box_NONCEBYTES crypto_box_curve25519xsalsa20poly1305_NONCEBYTES | ||
| 37 | #define crypto_box_ZEROBYTES crypto_box_curve25519xsalsa20poly1305_ZEROBYTES | ||
| 38 | #define crypto_box_BOXZEROBYTES crypto_box_curve25519xsalsa20poly1305_BOXZEROBYTES | ||
| 39 | #define crypto_box_IMPLEMENTATION crypto_box_curve25519xsalsa20poly1305_IMPLEMENTATION | ||
| 40 | #define crypto_box_VERSION crypto_box_curve25519xsalsa20poly1305_VERSION | ||
| 41 | #define crypto_box_curve25519xsalsa20poly1305_tweet_PUBLICKEYBYTES 32 | ||
| 42 | #define crypto_box_curve25519xsalsa20poly1305_tweet_SECRETKEYBYTES 32 | ||
| 43 | #define crypto_box_curve25519xsalsa20poly1305_tweet_BEFORENMBYTES 32 | ||
| 44 | #define crypto_box_curve25519xsalsa20poly1305_tweet_NONCEBYTES 24 | ||
| 45 | #define crypto_box_curve25519xsalsa20poly1305_tweet_ZEROBYTES 32 | ||
| 46 | #define crypto_box_curve25519xsalsa20poly1305_tweet_BOXZEROBYTES 16 | ||
| 47 | extern int crypto_box_curve25519xsalsa20poly1305_tweet(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *,const unsigned char *); | ||
| 48 | extern int crypto_box_curve25519xsalsa20poly1305_tweet_open(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *,const unsigned char *); | ||
| 49 | extern int crypto_box_curve25519xsalsa20poly1305_tweet_keypair(unsigned char *,unsigned char *); | ||
| 50 | extern int crypto_box_curve25519xsalsa20poly1305_tweet_beforenm(unsigned char *,const unsigned char *,const unsigned char *); | ||
| 51 | extern int crypto_box_curve25519xsalsa20poly1305_tweet_afternm(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *); | ||
| 52 | extern int crypto_box_curve25519xsalsa20poly1305_tweet_open_afternm(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *); | ||
| 53 | #define crypto_box_curve25519xsalsa20poly1305_tweet_VERSION "-" | ||
| 54 | #define crypto_box_curve25519xsalsa20poly1305 crypto_box_curve25519xsalsa20poly1305_tweet | ||
| 55 | #define crypto_box_curve25519xsalsa20poly1305_open crypto_box_curve25519xsalsa20poly1305_tweet_open | ||
| 56 | #define crypto_box_curve25519xsalsa20poly1305_keypair crypto_box_curve25519xsalsa20poly1305_tweet_keypair | ||
| 57 | #define crypto_box_curve25519xsalsa20poly1305_beforenm crypto_box_curve25519xsalsa20poly1305_tweet_beforenm | ||
| 58 | #define crypto_box_curve25519xsalsa20poly1305_afternm crypto_box_curve25519xsalsa20poly1305_tweet_afternm | ||
| 59 | #define crypto_box_curve25519xsalsa20poly1305_open_afternm crypto_box_curve25519xsalsa20poly1305_tweet_open_afternm | ||
| 60 | #define crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES crypto_box_curve25519xsalsa20poly1305_tweet_PUBLICKEYBYTES | ||
| 61 | #define crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES crypto_box_curve25519xsalsa20poly1305_tweet_SECRETKEYBYTES | ||
| 62 | #define crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES crypto_box_curve25519xsalsa20poly1305_tweet_BEFORENMBYTES | ||
| 63 | #define crypto_box_curve25519xsalsa20poly1305_NONCEBYTES crypto_box_curve25519xsalsa20poly1305_tweet_NONCEBYTES | ||
| 64 | #define crypto_box_curve25519xsalsa20poly1305_ZEROBYTES crypto_box_curve25519xsalsa20poly1305_tweet_ZEROBYTES | ||
| 65 | #define crypto_box_curve25519xsalsa20poly1305_BOXZEROBYTES crypto_box_curve25519xsalsa20poly1305_tweet_BOXZEROBYTES | ||
| 66 | #define crypto_box_curve25519xsalsa20poly1305_VERSION crypto_box_curve25519xsalsa20poly1305_tweet_VERSION | ||
| 67 | #define crypto_box_curve25519xsalsa20poly1305_IMPLEMENTATION "crypto_box/curve25519xsalsa20poly1305/tweet" | ||
| 68 | #define crypto_core_PRIMITIVE "salsa20" | ||
| 69 | #define crypto_core crypto_core_salsa20 | ||
| 70 | #define crypto_core_OUTPUTBYTES crypto_core_salsa20_OUTPUTBYTES | ||
| 71 | #define crypto_core_INPUTBYTES crypto_core_salsa20_INPUTBYTES | ||
| 72 | #define crypto_core_KEYBYTES crypto_core_salsa20_KEYBYTES | ||
| 73 | #define crypto_core_CONSTBYTES crypto_core_salsa20_CONSTBYTES | ||
| 74 | #define crypto_core_IMPLEMENTATION crypto_core_salsa20_IMPLEMENTATION | ||
| 75 | #define crypto_core_VERSION crypto_core_salsa20_VERSION | ||
| 76 | #define crypto_core_salsa20_tweet_OUTPUTBYTES 64 | ||
| 77 | #define crypto_core_salsa20_tweet_INPUTBYTES 16 | ||
| 78 | #define crypto_core_salsa20_tweet_KEYBYTES 32 | ||
| 79 | #define crypto_core_salsa20_tweet_CONSTBYTES 16 | ||
| 80 | extern int crypto_core_salsa20_tweet(unsigned char *,const unsigned char *,const unsigned char *,const unsigned char *); | ||
| 81 | #define crypto_core_salsa20_tweet_VERSION "-" | ||
| 82 | #define crypto_core_salsa20 crypto_core_salsa20_tweet | ||
| 83 | #define crypto_core_salsa20_OUTPUTBYTES crypto_core_salsa20_tweet_OUTPUTBYTES | ||
| 84 | #define crypto_core_salsa20_INPUTBYTES crypto_core_salsa20_tweet_INPUTBYTES | ||
| 85 | #define crypto_core_salsa20_KEYBYTES crypto_core_salsa20_tweet_KEYBYTES | ||
| 86 | #define crypto_core_salsa20_CONSTBYTES crypto_core_salsa20_tweet_CONSTBYTES | ||
| 87 | #define crypto_core_salsa20_VERSION crypto_core_salsa20_tweet_VERSION | ||
| 88 | #define crypto_core_salsa20_IMPLEMENTATION "crypto_core/salsa20/tweet" | ||
| 89 | #define crypto_core_hsalsa20_tweet_OUTPUTBYTES 32 | ||
| 90 | #define crypto_core_hsalsa20_tweet_INPUTBYTES 16 | ||
| 91 | #define crypto_core_hsalsa20_tweet_KEYBYTES 32 | ||
| 92 | #define crypto_core_hsalsa20_tweet_CONSTBYTES 16 | ||
| 93 | extern int crypto_core_hsalsa20_tweet(unsigned char *,const unsigned char *,const unsigned char *,const unsigned char *); | ||
| 94 | #define crypto_core_hsalsa20_tweet_VERSION "-" | ||
| 95 | #define crypto_core_hsalsa20 crypto_core_hsalsa20_tweet | ||
| 96 | #define crypto_core_hsalsa20_OUTPUTBYTES crypto_core_hsalsa20_tweet_OUTPUTBYTES | ||
| 97 | #define crypto_core_hsalsa20_INPUTBYTES crypto_core_hsalsa20_tweet_INPUTBYTES | ||
| 98 | #define crypto_core_hsalsa20_KEYBYTES crypto_core_hsalsa20_tweet_KEYBYTES | ||
| 99 | #define crypto_core_hsalsa20_CONSTBYTES crypto_core_hsalsa20_tweet_CONSTBYTES | ||
| 100 | #define crypto_core_hsalsa20_VERSION crypto_core_hsalsa20_tweet_VERSION | ||
| 101 | #define crypto_core_hsalsa20_IMPLEMENTATION "crypto_core/hsalsa20/tweet" | ||
| 102 | #define crypto_hashblocks_PRIMITIVE "sha512" | ||
| 103 | #define crypto_hashblocks crypto_hashblocks_sha512 | ||
| 104 | #define crypto_hashblocks_STATEBYTES crypto_hashblocks_sha512_STATEBYTES | ||
| 105 | #define crypto_hashblocks_BLOCKBYTES crypto_hashblocks_sha512_BLOCKBYTES | ||
| 106 | #define crypto_hashblocks_IMPLEMENTATION crypto_hashblocks_sha512_IMPLEMENTATION | ||
| 107 | #define crypto_hashblocks_VERSION crypto_hashblocks_sha512_VERSION | ||
| 108 | #define crypto_hashblocks_sha512_tweet_STATEBYTES 64 | ||
| 109 | #define crypto_hashblocks_sha512_tweet_BLOCKBYTES 128 | ||
| 110 | extern int crypto_hashblocks_sha512_tweet(unsigned char *,const unsigned char *,unsigned long long); | ||
| 111 | #define crypto_hashblocks_sha512_tweet_VERSION "-" | ||
| 112 | #define crypto_hashblocks_sha512 crypto_hashblocks_sha512_tweet | ||
| 113 | #define crypto_hashblocks_sha512_STATEBYTES crypto_hashblocks_sha512_tweet_STATEBYTES | ||
| 114 | #define crypto_hashblocks_sha512_BLOCKBYTES crypto_hashblocks_sha512_tweet_BLOCKBYTES | ||
| 115 | #define crypto_hashblocks_sha512_VERSION crypto_hashblocks_sha512_tweet_VERSION | ||
| 116 | #define crypto_hashblocks_sha512_IMPLEMENTATION "crypto_hashblocks/sha512/tweet" | ||
| 117 | #define crypto_hashblocks_sha256_tweet_STATEBYTES 32 | ||
| 118 | #define crypto_hashblocks_sha256_tweet_BLOCKBYTES 64 | ||
| 119 | extern int crypto_hashblocks_sha256_tweet(unsigned char *,const unsigned char *,unsigned long long); | ||
| 120 | #define crypto_hashblocks_sha256_tweet_VERSION "-" | ||
| 121 | #define crypto_hashblocks_sha256 crypto_hashblocks_sha256_tweet | ||
| 122 | #define crypto_hashblocks_sha256_STATEBYTES crypto_hashblocks_sha256_tweet_STATEBYTES | ||
| 123 | #define crypto_hashblocks_sha256_BLOCKBYTES crypto_hashblocks_sha256_tweet_BLOCKBYTES | ||
| 124 | #define crypto_hashblocks_sha256_VERSION crypto_hashblocks_sha256_tweet_VERSION | ||
| 125 | #define crypto_hashblocks_sha256_IMPLEMENTATION "crypto_hashblocks/sha256/tweet" | ||
| 126 | #define crypto_hash_PRIMITIVE "sha512" | ||
| 127 | #define crypto_hash crypto_hash_sha512 | ||
| 128 | #define crypto_hash_BYTES crypto_hash_sha512_BYTES | ||
| 129 | #define crypto_hash_IMPLEMENTATION crypto_hash_sha512_IMPLEMENTATION | ||
| 130 | #define crypto_hash_VERSION crypto_hash_sha512_VERSION | ||
| 131 | #define crypto_hash_sha512_tweet_BYTES 64 | ||
| 132 | extern int crypto_hash_sha512_tweet(unsigned char *,const unsigned char *,unsigned long long); | ||
| 133 | #define crypto_hash_sha512_tweet_VERSION "-" | ||
| 134 | #define crypto_hash_sha512 crypto_hash_sha512_tweet | ||
| 135 | #define crypto_hash_sha512_BYTES crypto_hash_sha512_tweet_BYTES | ||
| 136 | #define crypto_hash_sha512_VERSION crypto_hash_sha512_tweet_VERSION | ||
| 137 | #define crypto_hash_sha512_IMPLEMENTATION "crypto_hash/sha512/tweet" | ||
| 138 | #define crypto_hash_sha256_tweet_BYTES 32 | ||
| 139 | extern int crypto_hash_sha256_tweet(unsigned char *,const unsigned char *,unsigned long long); | ||
| 140 | #define crypto_hash_sha256_tweet_VERSION "-" | ||
| 141 | #define crypto_hash_sha256 crypto_hash_sha256_tweet | ||
| 142 | #define crypto_hash_sha256_BYTES crypto_hash_sha256_tweet_BYTES | ||
| 143 | #define crypto_hash_sha256_VERSION crypto_hash_sha256_tweet_VERSION | ||
| 144 | #define crypto_hash_sha256_IMPLEMENTATION "crypto_hash/sha256/tweet" | ||
| 145 | #define crypto_onetimeauth_PRIMITIVE "poly1305" | ||
| 146 | #define crypto_onetimeauth crypto_onetimeauth_poly1305 | ||
| 147 | #define crypto_onetimeauth_verify crypto_onetimeauth_poly1305_verify | ||
| 148 | #define crypto_onetimeauth_BYTES crypto_onetimeauth_poly1305_BYTES | ||
| 149 | #define crypto_onetimeauth_KEYBYTES crypto_onetimeauth_poly1305_KEYBYTES | ||
| 150 | #define crypto_onetimeauth_IMPLEMENTATION crypto_onetimeauth_poly1305_IMPLEMENTATION | ||
| 151 | #define crypto_onetimeauth_VERSION crypto_onetimeauth_poly1305_VERSION | ||
| 152 | #define crypto_onetimeauth_poly1305_tweet_BYTES 16 | ||
| 153 | #define crypto_onetimeauth_poly1305_tweet_KEYBYTES 32 | ||
| 154 | extern int crypto_onetimeauth_poly1305_tweet(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *); | ||
| 155 | extern int crypto_onetimeauth_poly1305_tweet_verify(const unsigned char *,const unsigned char *,unsigned long long,const unsigned char *); | ||
| 156 | #define crypto_onetimeauth_poly1305_tweet_VERSION "-" | ||
| 157 | #define crypto_onetimeauth_poly1305 crypto_onetimeauth_poly1305_tweet | ||
| 158 | #define crypto_onetimeauth_poly1305_verify crypto_onetimeauth_poly1305_tweet_verify | ||
| 159 | #define crypto_onetimeauth_poly1305_BYTES crypto_onetimeauth_poly1305_tweet_BYTES | ||
| 160 | #define crypto_onetimeauth_poly1305_KEYBYTES crypto_onetimeauth_poly1305_tweet_KEYBYTES | ||
| 161 | #define crypto_onetimeauth_poly1305_VERSION crypto_onetimeauth_poly1305_tweet_VERSION | ||
| 162 | #define crypto_onetimeauth_poly1305_IMPLEMENTATION "crypto_onetimeauth/poly1305/tweet" | ||
| 163 | #define crypto_scalarmult_PRIMITIVE "curve25519" | ||
| 164 | #define crypto_scalarmult crypto_scalarmult_curve25519 | ||
| 165 | #define crypto_scalarmult_base crypto_scalarmult_curve25519_base | ||
| 166 | #define crypto_scalarmult_BYTES crypto_scalarmult_curve25519_BYTES | ||
| 167 | #define crypto_scalarmult_SCALARBYTES crypto_scalarmult_curve25519_SCALARBYTES | ||
| 168 | #define crypto_scalarmult_IMPLEMENTATION crypto_scalarmult_curve25519_IMPLEMENTATION | ||
| 169 | #define crypto_scalarmult_VERSION crypto_scalarmult_curve25519_VERSION | ||
| 170 | #define crypto_scalarmult_curve25519_tweet_BYTES 32 | ||
| 171 | #define crypto_scalarmult_curve25519_tweet_SCALARBYTES 32 | ||
| 172 | extern int crypto_scalarmult_curve25519_tweet(unsigned char *,const unsigned char *,const unsigned char *); | ||
| 173 | extern int crypto_scalarmult_curve25519_tweet_base(unsigned char *,const unsigned char *); | ||
| 174 | #define crypto_scalarmult_curve25519_tweet_VERSION "-" | ||
| 175 | #define crypto_scalarmult_curve25519 crypto_scalarmult_curve25519_tweet | ||
| 176 | #define crypto_scalarmult_curve25519_base crypto_scalarmult_curve25519_tweet_base | ||
| 177 | #define crypto_scalarmult_curve25519_BYTES crypto_scalarmult_curve25519_tweet_BYTES | ||
| 178 | #define crypto_scalarmult_curve25519_SCALARBYTES crypto_scalarmult_curve25519_tweet_SCALARBYTES | ||
| 179 | #define crypto_scalarmult_curve25519_VERSION crypto_scalarmult_curve25519_tweet_VERSION | ||
| 180 | #define crypto_scalarmult_curve25519_IMPLEMENTATION "crypto_scalarmult/curve25519/tweet" | ||
| 181 | #define crypto_secretbox_PRIMITIVE "xsalsa20poly1305" | ||
| 182 | #define crypto_secretbox crypto_secretbox_xsalsa20poly1305 | ||
| 183 | #define crypto_secretbox_open crypto_secretbox_xsalsa20poly1305_open | ||
| 184 | #define crypto_secretbox_KEYBYTES crypto_secretbox_xsalsa20poly1305_KEYBYTES | ||
| 185 | #define crypto_secretbox_NONCEBYTES crypto_secretbox_xsalsa20poly1305_NONCEBYTES | ||
| 186 | #define crypto_secretbox_ZEROBYTES crypto_secretbox_xsalsa20poly1305_ZEROBYTES | ||
| 187 | #define crypto_secretbox_BOXZEROBYTES crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES | ||
| 188 | #define crypto_secretbox_IMPLEMENTATION crypto_secretbox_xsalsa20poly1305_IMPLEMENTATION | ||
| 189 | #define crypto_secretbox_VERSION crypto_secretbox_xsalsa20poly1305_VERSION | ||
| 190 | #define crypto_secretbox_xsalsa20poly1305_tweet_KEYBYTES 32 | ||
| 191 | #define crypto_secretbox_xsalsa20poly1305_tweet_NONCEBYTES 24 | ||
| 192 | #define crypto_secretbox_xsalsa20poly1305_tweet_ZEROBYTES 32 | ||
| 193 | #define crypto_secretbox_xsalsa20poly1305_tweet_BOXZEROBYTES 16 | ||
| 194 | extern int crypto_secretbox_xsalsa20poly1305_tweet(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *); | ||
| 195 | extern int crypto_secretbox_xsalsa20poly1305_tweet_open(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *); | ||
| 196 | #define crypto_secretbox_xsalsa20poly1305_tweet_VERSION "-" | ||
| 197 | #define crypto_secretbox_xsalsa20poly1305 crypto_secretbox_xsalsa20poly1305_tweet | ||
| 198 | #define crypto_secretbox_xsalsa20poly1305_open crypto_secretbox_xsalsa20poly1305_tweet_open | ||
| 199 | #define crypto_secretbox_xsalsa20poly1305_KEYBYTES crypto_secretbox_xsalsa20poly1305_tweet_KEYBYTES | ||
| 200 | #define crypto_secretbox_xsalsa20poly1305_NONCEBYTES crypto_secretbox_xsalsa20poly1305_tweet_NONCEBYTES | ||
| 201 | #define crypto_secretbox_xsalsa20poly1305_ZEROBYTES crypto_secretbox_xsalsa20poly1305_tweet_ZEROBYTES | ||
| 202 | #define crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES crypto_secretbox_xsalsa20poly1305_tweet_BOXZEROBYTES | ||
| 203 | #define crypto_secretbox_xsalsa20poly1305_VERSION crypto_secretbox_xsalsa20poly1305_tweet_VERSION | ||
| 204 | #define crypto_secretbox_xsalsa20poly1305_IMPLEMENTATION "crypto_secretbox/xsalsa20poly1305/tweet" | ||
| 205 | #define crypto_sign_PRIMITIVE "ed25519" | ||
| 206 | #define crypto_sign crypto_sign_ed25519 | ||
| 207 | #define crypto_sign_open crypto_sign_ed25519_open | ||
| 208 | #define crypto_sign_keypair crypto_sign_ed25519_keypair | ||
| 209 | #define crypto_sign_BYTES crypto_sign_ed25519_BYTES | ||
| 210 | #define crypto_sign_PUBLICKEYBYTES crypto_sign_ed25519_PUBLICKEYBYTES | ||
| 211 | #define crypto_sign_SECRETKEYBYTES crypto_sign_ed25519_SECRETKEYBYTES | ||
| 212 | #define crypto_sign_IMPLEMENTATION crypto_sign_ed25519_IMPLEMENTATION | ||
| 213 | #define crypto_sign_VERSION crypto_sign_ed25519_VERSION | ||
| 214 | #define crypto_sign_ed25519_tweet_BYTES 64 | ||
| 215 | #define crypto_sign_ed25519_tweet_PUBLICKEYBYTES 32 | ||
| 216 | #define crypto_sign_ed25519_tweet_SECRETKEYBYTES 64 | ||
| 217 | extern int crypto_sign_ed25519_tweet(unsigned char *,unsigned long long *,const unsigned char *,unsigned long long,const unsigned char *); | ||
| 218 | extern int crypto_sign_ed25519_tweet_open(unsigned char *,unsigned long long *,const unsigned char *,unsigned long long,const unsigned char *); | ||
| 219 | extern int crypto_sign_ed25519_tweet_keypair(unsigned char *,unsigned char *); | ||
| 220 | #define crypto_sign_ed25519_tweet_VERSION "-" | ||
| 221 | #define crypto_sign_ed25519 crypto_sign_ed25519_tweet | ||
| 222 | #define crypto_sign_ed25519_open crypto_sign_ed25519_tweet_open | ||
| 223 | #define crypto_sign_ed25519_keypair crypto_sign_ed25519_tweet_keypair | ||
| 224 | #define crypto_sign_ed25519_BYTES crypto_sign_ed25519_tweet_BYTES | ||
| 225 | #define crypto_sign_ed25519_PUBLICKEYBYTES crypto_sign_ed25519_tweet_PUBLICKEYBYTES | ||
| 226 | #define crypto_sign_ed25519_SECRETKEYBYTES crypto_sign_ed25519_tweet_SECRETKEYBYTES | ||
| 227 | #define crypto_sign_ed25519_VERSION crypto_sign_ed25519_tweet_VERSION | ||
| 228 | #define crypto_sign_ed25519_IMPLEMENTATION "crypto_sign/ed25519/tweet" | ||
| 229 | #define crypto_stream_PRIMITIVE "xsalsa20" | ||
| 230 | #define crypto_stream crypto_stream_xsalsa20 | ||
| 231 | #define crypto_stream_xor crypto_stream_xsalsa20_xor | ||
| 232 | #define crypto_stream_KEYBYTES crypto_stream_xsalsa20_KEYBYTES | ||
| 233 | #define crypto_stream_NONCEBYTES crypto_stream_xsalsa20_NONCEBYTES | ||
| 234 | #define crypto_stream_IMPLEMENTATION crypto_stream_xsalsa20_IMPLEMENTATION | ||
| 235 | #define crypto_stream_VERSION crypto_stream_xsalsa20_VERSION | ||
| 236 | #define crypto_stream_xsalsa20_tweet_KEYBYTES 32 | ||
| 237 | #define crypto_stream_xsalsa20_tweet_NONCEBYTES 24 | ||
| 238 | extern int crypto_stream_xsalsa20_tweet(unsigned char *,unsigned long long,const unsigned char *,const unsigned char *); | ||
| 239 | extern int crypto_stream_xsalsa20_tweet_xor(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *); | ||
| 240 | #define crypto_stream_xsalsa20_tweet_VERSION "-" | ||
| 241 | #define crypto_stream_xsalsa20 crypto_stream_xsalsa20_tweet | ||
| 242 | #define crypto_stream_xsalsa20_xor crypto_stream_xsalsa20_tweet_xor | ||
| 243 | #define crypto_stream_xsalsa20_KEYBYTES crypto_stream_xsalsa20_tweet_KEYBYTES | ||
| 244 | #define crypto_stream_xsalsa20_NONCEBYTES crypto_stream_xsalsa20_tweet_NONCEBYTES | ||
| 245 | #define crypto_stream_xsalsa20_VERSION crypto_stream_xsalsa20_tweet_VERSION | ||
| 246 | #define crypto_stream_xsalsa20_IMPLEMENTATION "crypto_stream/xsalsa20/tweet" | ||
| 247 | #define crypto_stream_salsa20_tweet_KEYBYTES 32 | ||
| 248 | #define crypto_stream_salsa20_tweet_NONCEBYTES 8 | ||
| 249 | extern int crypto_stream_salsa20_tweet(unsigned char *,unsigned long long,const unsigned char *,const unsigned char *); | ||
| 250 | extern int crypto_stream_salsa20_tweet_xor(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *); | ||
| 251 | #define crypto_stream_salsa20_tweet_VERSION "-" | ||
| 252 | #define crypto_stream_salsa20 crypto_stream_salsa20_tweet | ||
| 253 | #define crypto_stream_salsa20_xor crypto_stream_salsa20_tweet_xor | ||
| 254 | #define crypto_stream_salsa20_KEYBYTES crypto_stream_salsa20_tweet_KEYBYTES | ||
| 255 | #define crypto_stream_salsa20_NONCEBYTES crypto_stream_salsa20_tweet_NONCEBYTES | ||
| 256 | #define crypto_stream_salsa20_VERSION crypto_stream_salsa20_tweet_VERSION | ||
| 257 | #define crypto_stream_salsa20_IMPLEMENTATION "crypto_stream/salsa20/tweet" | ||
| 258 | #define crypto_verify_PRIMITIVE "16" | ||
| 259 | #define crypto_verify crypto_verify_16 | ||
| 260 | #define crypto_verify_BYTES crypto_verify_16_BYTES | ||
| 261 | #define crypto_verify_IMPLEMENTATION crypto_verify_16_IMPLEMENTATION | ||
| 262 | #define crypto_verify_VERSION crypto_verify_16_VERSION | ||
| 263 | #define crypto_verify_16_tweet_BYTES 16 | ||
| 264 | extern int crypto_verify_16_tweet(const unsigned char *,const unsigned char *); | ||
| 265 | #define crypto_verify_16_tweet_VERSION "-" | ||
| 266 | #define crypto_verify_16 crypto_verify_16_tweet | ||
| 267 | #define crypto_verify_16_BYTES crypto_verify_16_tweet_BYTES | ||
| 268 | #define crypto_verify_16_VERSION crypto_verify_16_tweet_VERSION | ||
| 269 | #define crypto_verify_16_IMPLEMENTATION "crypto_verify/16/tweet" | ||
| 270 | #define crypto_verify_32_tweet_BYTES 32 | ||
| 271 | extern int crypto_verify_32_tweet(const unsigned char *,const unsigned char *); | ||
| 272 | #define crypto_verify_32_tweet_VERSION "-" | ||
| 273 | #define crypto_verify_32 crypto_verify_32_tweet | ||
| 274 | #define crypto_verify_32_BYTES crypto_verify_32_tweet_BYTES | ||
| 275 | #define crypto_verify_32_VERSION crypto_verify_32_tweet_VERSION | ||
| 276 | #define crypto_verify_32_IMPLEMENTATION "crypto_verify/32/tweet" | ||
| 277 | #endif | ||
