summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bench/bench.php422
-rw-r--r--src/bench/micro_bench.php358
-rw-r--r--src/config.m435
-rw-r--r--src/config.w3213
-rw-r--r--src/php_snuffleupagus.h71
-rw-r--r--src/snuffleupagus.c222
-rw-r--r--src/snuffleupagus.php21
-rw-r--r--src/sp_compile.c53
-rw-r--r--src/sp_compile.h6
-rw-r--r--src/sp_config.c193
-rw-r--r--src/sp_config.h206
-rw-r--r--src/sp_config_keywords.c268
-rw-r--r--src/sp_config_keywords.h16
-rw-r--r--src/sp_config_utils.c211
-rw-r--r--src/sp_config_utils.h8
-rw-r--r--src/sp_cookie_encryption.c216
-rw-r--r--src/sp_cookie_encryption.h17
-rw-r--r--src/sp_disable_xxe.c25
-rw-r--r--src/sp_disable_xxe.h6
-rw-r--r--src/sp_disabled_functions.c356
-rw-r--r--src/sp_disabled_functions.h11
-rw-r--r--src/sp_execute.c100
-rw-r--r--src/sp_execute.h6
-rw-r--r--src/sp_harden_rand.c77
-rw-r--r--src/sp_harden_rand.h10
-rw-r--r--src/sp_list.c37
-rw-r--r--src/sp_list.h15
-rw-r--r--src/sp_network_utils.c159
-rw-r--r--src/sp_network_utils.h8
-rw-r--r--src/sp_unserialize.c111
-rw-r--r--src/sp_unserialize.h9
-rw-r--r--src/sp_upload_validation.c92
-rw-r--r--src/sp_upload_validation.h9
-rw-r--r--src/sp_utils.c425
-rw-r--r--src/sp_utils.h68
-rw-r--r--src/tests/broken_conf.phpt10
-rw-r--r--src/tests/broken_conf2.phpt9
-rw-r--r--src/tests/broken_conf_config_regexp.phpt10
-rw-r--r--src/tests/broken_conf_enable_disable.phpt9
-rw-r--r--src/tests/broken_conf_expecting_bool.phpt9
-rw-r--r--src/tests/broken_conf_expecting_int.phpt9
-rw-r--r--src/tests/broken_conf_invalid_cidr.phpt9
-rw-r--r--src/tests/broken_conf_invalid_cidr6.phpt9
-rw-r--r--src/tests/broken_conf_invalid_cidr6_no_slash.phpt9
-rw-r--r--src/tests/broken_conf_invalid_cidr6_too_big.phpt9
-rw-r--r--src/tests/broken_conf_invalid_cidr_value.phpt11
-rw-r--r--src/tests/broken_conf_invalid_type.phpt9
-rw-r--r--src/tests/broken_conf_line_empty_string.phpt9
-rw-r--r--src/tests/broken_conf_line_no_closing.phpt9
-rw-r--r--src/tests/broken_conf_line_too_long.phpt10
-rw-r--r--src/tests/broken_conf_lots_of_quotes.phpt9
-rw-r--r--src/tests/broken_conf_mutually_exclusive.phpt9
-rw-r--r--src/tests/broken_conf_mutually_exclusive2.phpt9
-rw-r--r--src/tests/broken_conf_mutually_exclusive3.phpt9
-rw-r--r--src/tests/broken_conf_mutually_exclusive4.phpt9
-rw-r--r--src/tests/broken_conf_mutually_exclusive5.phpt9
-rw-r--r--src/tests/broken_conf_mutually_exclusive6.phpt9
-rw-r--r--src/tests/broken_conf_mutually_exclusive7.phpt9
-rw-r--r--src/tests/broken_conf_mutually_exclusive8.phpt9
-rw-r--r--src/tests/broken_conf_no_closing_misc.phpt10
-rw-r--r--src/tests/broken_conf_weird_keyword.phpt9
-rw-r--r--src/tests/broken_conf_wrong_quotes.phpt9
-rw-r--r--src/tests/broken_conf_wrong_type.phpt9
-rw-r--r--src/tests/broken_regexp.phpt9
-rw-r--r--src/tests/config/borken_conf_enable_disable.ini1
-rw-r--r--src/tests/config/broken_conf.ini1
-rw-r--r--src/tests/config/broken_conf2.ini1
-rw-r--r--src/tests/config/broken_conf_expecting_bool.ini5
-rw-r--r--src/tests/config/broken_conf_expecting_int.ini2
-rw-r--r--src/tests/config/broken_conf_invalid_cidr.ini1
-rw-r--r--src/tests/config/broken_conf_invalid_cidr6.ini1
-rw-r--r--src/tests/config/broken_conf_invalid_cidr6_no_slash.ini1
-rw-r--r--src/tests/config/broken_conf_invalid_cidr6_too_big.ini1
-rw-r--r--src/tests/config/broken_conf_invalid_cidr_value.ini1
-rw-r--r--src/tests/config/broken_conf_invalid_type.ini1
-rw-r--r--src/tests/config/broken_conf_line_empty_string.ini1
-rw-r--r--src/tests/config/broken_conf_line_no_closing.ini1
-rw-r--r--src/tests/config/broken_conf_line_too_long.ini1
-rw-r--r--src/tests/config/broken_conf_lots_of_quotes.ini1
-rw-r--r--src/tests/config/broken_conf_mutually_exclusive.ini1
-rw-r--r--src/tests/config/broken_conf_mutually_exclusive2.ini1
-rw-r--r--src/tests/config/broken_conf_mutually_exclusive3.ini1
-rw-r--r--src/tests/config/broken_conf_mutually_exclusive4.ini1
-rw-r--r--src/tests/config/broken_conf_mutually_exclusive5.ini1
-rw-r--r--src/tests/config/broken_conf_mutually_exclusive6.ini1
-rw-r--r--src/tests/config/broken_conf_mutually_exclusive7.ini1
-rw-r--r--src/tests/config/broken_conf_mutually_exclusive8.ini1
-rw-r--r--src/tests/config/broken_conf_no_closing_misc.ini1
-rw-r--r--src/tests/config/broken_conf_to_few_args.ini1
-rw-r--r--src/tests/config/broken_conf_weird_keyword.ini1
-rw-r--r--src/tests/config/broken_conf_wrong_quotes.ini1
-rw-r--r--src/tests/config/broken_conf_wrong_type.ini5
-rw-r--r--src/tests/config/broken_config_regexp.ini1
-rw-r--r--src/tests/config/broken_regexp.ini1
-rw-r--r--src/tests/config/config_disable_writable.ini1
-rw-r--r--src/tests/config/config_disable_writable_disabled.ini1
-rw-r--r--src/tests/config/config_disable_writable_simulation.ini1
-rw-r--r--src/tests/config/config_disabled_functions_filename_r.ini2
-rw-r--r--src/tests/config/config_disabled_functions_method.ini3
-rw-r--r--src/tests/config/config_disabled_functions_name_r.ini2
-rw-r--r--src/tests/config/config_disabled_functions_name_type.ini1
-rw-r--r--src/tests/config/config_disabled_functions_namespace.ini2
-rw-r--r--src/tests/config/config_disabled_functions_nul_byte.ini1
-rw-r--r--src/tests/config/config_disabled_functions_param.ini6
-rw-r--r--src/tests/config/config_disabled_functions_param_alias.ini2
-rw-r--r--src/tests/config/config_disabled_functions_param_allow.ini3
-rw-r--r--src/tests/config/config_disabled_functions_param_array.ini4
-rw-r--r--src/tests/config/config_disabled_functions_param_int.ini2
-rw-r--r--src/tests/config/config_disabled_functions_param_r.ini1
-rw-r--r--src/tests/config/config_disabled_functions_param_runtime.ini1
-rw-r--r--src/tests/config/config_disabled_functions_param_str_representation.ini1
-rw-r--r--src/tests/config/config_disabled_functions_require.ini1
-rw-r--r--src/tests/config/config_disabled_functions_ret_allow.ini2
-rw-r--r--src/tests/config/config_disabled_functions_ret_allow_value.ini1
-rw-r--r--src/tests/config/config_disabled_functions_ret_right_hash.ini4
-rw-r--r--src/tests/config/config_disabled_functions_ret_simulation.ini3
-rw-r--r--src/tests/config/config_disabled_functions_right_hash.ini3
-rw-r--r--src/tests/config/config_disabled_user_functions.ini1
-rw-r--r--src/tests/config/config_encrypted_cookies.ini3
-rw-r--r--src/tests/config/config_noncore_function_hooking.ini1
-rw-r--r--src/tests/config/config_rand_harden_disabled.ini1
-rw-r--r--src/tests/config/config_serialize.ini2
-rw-r--r--src/tests/config/config_serialize_sim.ini2
-rw-r--r--src/tests/config/disable_xxe.ini1
-rw-r--r--src/tests/config/disable_xxe_disable.ini1
-rw-r--r--src/tests/config/disabled_function_local_var.ini2
-rw-r--r--src/tests/config/disabled_function_super_global_var.ini1
-rw-r--r--src/tests/config/disabled_functions.ini7
-rw-r--r--src/tests/config/disabled_functions_cidr.ini4
-rw-r--r--src/tests/config/disabled_functions_mb.ini2
-rw-r--r--src/tests/config/disabled_functions_ret.ini5
-rw-r--r--src/tests/config/disabled_functions_ret_type.ini1
-rw-r--r--src/tests/config/disabled_functions_ret_type_double.ini1
-rw-r--r--src/tests/config/disabled_functions_ret_type_long.ini1
-rw-r--r--src/tests/config/disabled_functions_ret_type_resource.ini1
-rw-r--r--src/tests/config/disabled_functions_ret_type_str.ini1
-rw-r--r--src/tests/config/disabled_functions_ret_type_true.ini1
-rw-r--r--src/tests/config/disabled_functions_retval.ini1
-rw-r--r--src/tests/config/disabled_functions_retval_rx.ini1
-rw-r--r--src/tests/config/disabled_functions_zero_cidr.ini1
-rw-r--r--src/tests/config/dump_request.ini1
-rw-r--r--src/tests/config/dump_request_invalid_folder.ini1
-rw-r--r--src/tests/config/empty.ini0
-rw-r--r--src/tests/config/empty_conf.ini0
-rw-r--r--src/tests/config/encryption_key_only.ini1
-rw-r--r--src/tests/config/global_strict.ini1
-rw-r--r--src/tests/config/global_strict_disabled.ini1
-rw-r--r--src/tests/config/harden_rand.ini1
-rw-r--r--src/tests/config/upload_validation.ini2
-rw-r--r--src/tests/config/upload_validation_invalid.ini1
-rw-r--r--src/tests/config/upload_validation_ko.ini1
-rw-r--r--src/tests/config/upload_validation_ko_simulation.ini1
-rw-r--r--src/tests/config/upload_validation_no_exist.ini1
-rw-r--r--src/tests/config/upload_validation_non_exec.ini1
-rw-r--r--src/tests/config/upload_validation_ok.ini1
-rwxr-xr-xsrc/tests/data/upload_invalid.sh1
-rwxr-xr-xsrc/tests/data/upload_ko.sh2
-rw-r--r--src/tests/data/upload_no_exec.sh2
-rwxr-xr-xsrc/tests/data/upload_ok.sh2
-rw-r--r--src/tests/deny_writable_execution.phpt44
-rw-r--r--src/tests/deny_writable_execution_disabled.phpt32
-rw-r--r--src/tests/deny_writable_execution_simulation.phpt45
-rw-r--r--src/tests/disable_xxe_dom.phpt71
-rw-r--r--src/tests/disable_xxe_dom_disabled.phpt56
-rw-r--r--src/tests/disable_xxe_simplexml.phpt52
-rw-r--r--src/tests/disable_xxe_simplexml_oop.phpt52
-rw-r--r--src/tests/disable_xxe_xml_parse.phpt104
-rw-r--r--src/tests/disabled_function_local_var.phpt24
-rw-r--r--src/tests/disabled_function_super_global_var.phpt20
-rw-r--r--src/tests/disabled_functions.phpt21
-rw-r--r--src/tests/disabled_functions_cidr.phpt18
-rw-r--r--src/tests/disabled_functions_cidr_6.phpt18
-rw-r--r--src/tests/disabled_functions_filename_r.phpt14
-rw-r--r--src/tests/disabled_functions_mb.phpt12
-rw-r--r--src/tests/disabled_functions_method.phpt29
-rw-r--r--src/tests/disabled_functions_name_r.phpt15
-rw-r--r--src/tests/disabled_functions_name_type.phpt14
-rw-r--r--src/tests/disabled_functions_namespace.phpt31
-rw-r--r--src/tests/disabled_functions_noconf.phpt12
-rw-r--r--src/tests/disabled_functions_nul_byte.phpt15
-rw-r--r--src/tests/disabled_functions_param.phpt24
-rw-r--r--src/tests/disabled_functions_param_alias.phpt14
-rw-r--r--src/tests/disabled_functions_param_allow.phpt14
-rw-r--r--src/tests/disabled_functions_param_array.phpt37
-rw-r--r--src/tests/disabled_functions_param_int.phpt25
-rw-r--r--src/tests/disabled_functions_param_r.phpt14
-rw-r--r--src/tests/disabled_functions_param_str_representation.phpt25
-rw-r--r--src/tests/disabled_functions_parse_class.phpt22
-rw-r--r--src/tests/disabled_functions_require.phpt25
-rw-r--r--src/tests/disabled_functions_ret.phpt13
-rw-r--r--src/tests/disabled_functions_ret2.phpt12
-rw-r--r--src/tests/disabled_functions_ret3.phpt22
-rw-r--r--src/tests/disabled_functions_ret_allow.phpt13
-rw-r--r--src/tests/disabled_functions_ret_allow_value.phpt12
-rw-r--r--src/tests/disabled_functions_ret_right_hash.phpt12
-rw-r--r--src/tests/disabled_functions_ret_simulation.phpt18
-rw-r--r--src/tests/disabled_functions_ret_type.phpt16
-rw-r--r--src/tests/disabled_functions_ret_type_double.phpt12
-rw-r--r--src/tests/disabled_functions_ret_type_long.phpt12
-rw-r--r--src/tests/disabled_functions_ret_type_resource.phpt12
-rw-r--r--src/tests/disabled_functions_ret_type_str.phpt12
-rw-r--r--src/tests/disabled_functions_ret_type_true.phpt16
-rw-r--r--src/tests/disabled_functions_ret_val.phpt14
-rw-r--r--src/tests/disabled_functions_ret_val_rx.phpt14
-rw-r--r--src/tests/disabled_functions_right_hash.phpt12
-rw-r--r--src/tests/disabled_functions_runtime.phpt31
-rw-r--r--src/tests/disabled_functions_zero_cidr.phpt18
-rw-r--r--src/tests/disabled_option.phpt16
-rw-r--r--src/tests/disabled_user_functions.phpt15
-rw-r--r--src/tests/dump_request.phpt39
-rw-r--r--src/tests/dump_request_invalid_folder.phpt25
-rw-r--r--src/tests/dump_request_too_big.phpt42
-rw-r--r--src/tests/empty_conf.phpt8
-rw-r--r--src/tests/encrypt_cookies.phpt22
-rw-r--r--src/tests/encrypt_cookies2.phpt23
-rw-r--r--src/tests/encrypt_cookies3.phpt23
-rw-r--r--src/tests/encrypt_cookies4.phpt23
-rw-r--r--src/tests/encrypt_cookies_invalid_decryption.phpt23
-rw-r--r--src/tests/encrypt_cookies_invalid_decryption2.phpt23
-rw-r--r--src/tests/encrypt_cookies_invalid_decryption3.phpt21
-rw-r--r--src/tests/encryption_key_only.phpt13
-rw-r--r--src/tests/example_configuration.phpt12
-rw-r--r--src/tests/global_strict.phpt16
-rw-r--r--src/tests/global_strict_disabled.phpt14
-rw-r--r--src/tests/harden_mt_rand.phpt22
-rw-r--r--src/tests/harden_rand.phpt24
-rw-r--r--src/tests/harden_rand_noargs.phpt62
-rw-r--r--src/tests/inexistent_conf_file.phpt10
-rw-r--r--src/tests/loading.phpt10
-rw-r--r--src/tests/noncore_function_hooking.phpt15
-rw-r--r--src/tests/phpinfo_presence.phpt19
-rw-r--r--src/tests/serialize.phpt13
-rw-r--r--src/tests/setcookie.phpt35
-rw-r--r--src/tests/shipped_configuration.phpt12
-rw-r--r--src/tests/unserialize.phpt13
-rw-r--r--src/tests/unserialize_fail.phpt23
-rw-r--r--src/tests/unserialize_sim.phpt17
-rw-r--r--src/tests/upload_validation.phpt16
-rw-r--r--src/tests/upload_validation_invalid.phpt17
-rw-r--r--src/tests/upload_validation_ko.phpt14
-rw-r--r--src/tests/upload_validation_no_exec.phpt32
-rw-r--r--src/tests/upload_validation_nocrash.phpt12
-rw-r--r--src/tests/upload_validation_ok.phpt17
-rw-r--r--src/tweetnacl.c842
-rw-r--r--src/tweetnacl.h277
245 files changed, 7307 insertions, 0 deletions
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
2if (function_exists("date_default_timezone_set")) {
3 date_default_timezone_set("UTC");
4}
5
6function 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
18function simplecall() {
19 for ($i = 0; $i < 1000000; $i++)
20 strlen("hallo");
21}
22
23/****/
24
25function hallo($a) {
26}
27
28function simpleucall() {
29 for ($i = 0; $i < 1000000; $i++)
30 hallo("hallo");
31}
32
33/****/
34
35function simpleudcall() {
36 for ($i = 0; $i < 1000000; $i++)
37 hallo2("hallo");
38}
39
40function hallo2($a) {
41}
42
43/****/
44
45function 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
85function 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
99function 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
105function ackermann($n) {
106 $r = Ack(3,$n);
107 print "Ack(3,$n): $r\n";
108}
109
110/****/
111
112function 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
125function 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
158function 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
174function fibo_r($n){
175 return(($n < 2) ? 1 : fibo_r($n - 2) + fibo_r($n - 1));
176}
177
178function fibo($n) {
179 $r = fibo_r($n);
180 print "$r\n";
181}
182
183/****/
184
185function 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
198function 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
213function gen_random ($n) {
214 global $LAST;
215 return( ($n * ($LAST = ($LAST * IA + IC) % IM)) / IM );
216}
217
218function 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
250function 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
267function 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
278function 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
292function 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
304function 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
318function 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
337function 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
348function getmicrotime()
349{
350 $t = gettimeofday();
351 return ($t['sec'] + $t['usec'] / 1000000);
352}
353
354function start_test()
355{
356 ob_start();
357 return getmicrotime();
358}
359
360function 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
374function 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();
385simple();
386$t = end_test($t, "simple");
387simplecall();
388$t = end_test($t, "simplecall");
389simpleucall();
390$t = end_test($t, "simpleucall");
391simpleudcall();
392$t = end_test($t, "simpleudcall");
393mandel();
394$t = end_test($t, "mandel");
395mandel2();
396$t = end_test($t, "mandel2");
397ackermann(7);
398$t = end_test($t, "ackermann(7)");
399ary(50000);
400$t = end_test($t, "ary(50000)");
401ary2(50000);
402$t = end_test($t, "ary2(50000)");
403ary3(2000);
404$t = end_test($t, "ary3(2000)");
405fibo(30);
406$t = end_test($t, "fibo(30)");
407hash1(50000);
408$t = end_test($t, "hash1(50000)");
409hash2(500);
410$t = end_test($t, "hash2(500)");
411heapsort(20000);
412$t = end_test($t, "heapsort(20000)");
413matrix(20);
414$t = end_test($t, "matrix(20)");
415nestedloop(12);
416$t = end_test($t, "nestedloop(12)");
417sieve(30);
418$t = end_test($t, "sieve(30)");
419strcat(200000);
420$t = end_test($t, "strcat(200000)");
421total($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
3function hallo() {
4}
5
6function simpleucall($n) {
7 for ($i = 0; $i < $n; $i++)
8 hallo();
9}
10
11function simpleudcall($n) {
12 for ($i = 0; $i < $n; $i++)
13 hallo2();
14}
15
16function hallo2() {
17}
18
19function simpleicall($n) {
20 for ($i = 0; $i < $n; $i++)
21 func_num_args();
22}
23
24class 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
133function read_static($n) {
134 for ($i = 0; $i < $n; ++$i) {
135 $x = Foo::$a;
136 }
137}
138
139function write_static($n) {
140 for ($i = 0; $i < $n; ++$i) {
141 Foo::$a = 0;
142 }
143}
144
145function isset_static($n) {
146 for ($i = 0; $i < $n; ++$i) {
147 $x = isset(Foo::$a);
148 }
149}
150
151function empty_static($n) {
152 for ($i = 0; $i < $n; ++$i) {
153 $x = empty(Foo::$a);
154 }
155}
156
157function call_static($n) {
158 for ($i = 0; $i < $n; ++$i) {
159 Foo::f();
160 }
161}
162
163function create_object($n) {
164 for ($i = 0; $i < $n; ++$i) {
165 $x = new Foo();
166 }
167}
168
169define('TEST', null);
170
171function read_const($n) {
172 for ($i = 0; $i < $n; ++$i) {
173 $x = TEST;
174 }
175}
176
177function read_auto_global($n) {
178 for ($i = 0; $i < $n; ++$i) {
179 $x = $_GET;
180 }
181}
182
183$g_var = 0;
184
185function read_global_var($n) {
186 for ($i = 0; $i < $n; ++$i) {
187 $x = $GLOBALS['g_var'];
188 }
189}
190
191function read_hash($n) {
192 $hash = array('test' => 0);
193 for ($i = 0; $i < $n; ++$i) {
194 $x = $hash['test'];
195 }
196}
197
198function read_str_offset($n) {
199 $str = "test";
200 for ($i = 0; $i < $n; ++$i) {
201 $x = $str[1];
202 }
203}
204
205function 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
212function issetor2($n) {
213 $f = false; $j = 0;
214 for ($i = 0; $i < $n; ++$i) {
215 $x = $f ?: $j + 1;
216 }
217}
218
219function 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
227function 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
236function empty_loop($n) {
237 for ($i = 0; $i < $n; ++$i) {
238 }
239}
240
241function getmicrotime()
242{
243 $t = gettimeofday();
244 return ($t['sec'] + $t['usec'] / 1000000);
245}
246
247function start_test()
248{
249 ob_start();
250 return getmicrotime();
251}
252
253function 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
273function 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
283const N = 5000000;
284
285$t0 = $t = start_test();
286empty_loop(N);
287$t = end_test($t, 'empty_loop');
288$overhead = $last_time;
289simpleucall(N);
290$t = end_test($t, 'func()', $overhead);
291simpleudcall(N);
292$t = end_test($t, 'undef_func()', $overhead);
293simpleicall(N);
294$t = end_test($t, 'int_func()', $overhead);
295Foo::read_static(N);
296$t = end_test($t, '$x = self::$x', $overhead);
297Foo::write_static(N);
298$t = end_test($t, 'self::$x = 0', $overhead);
299Foo::isset_static(N);
300$t = end_test($t, 'isset(self::$x)', $overhead);
301Foo::empty_static(N);
302$t = end_test($t, 'empty(self::$x)', $overhead);
303read_static(N);
304$t = end_test($t, '$x = Foo::$x', $overhead);
305write_static(N);
306$t = end_test($t, 'Foo::$x = 0', $overhead);
307isset_static(N);
308$t = end_test($t, 'isset(Foo::$x)', $overhead);
309empty_static(N);
310$t = end_test($t, 'empty(Foo::$x)', $overhead);
311Foo::call_static(N);
312$t = end_test($t, 'self::f()', $overhead);
313call_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);
338create_object(N);
339$t = end_test($t, 'new Foo()', $overhead);
340read_const(N);
341$t = end_test($t, '$x = TEST', $overhead);
342read_auto_global(N);
343$t = end_test($t, '$x = $_GET', $overhead);
344read_global_var(N);
345$t = end_test($t, '$x = $GLOBALS[\'v\']', $overhead);
346read_hash(N);
347$t = end_test($t, '$x = $hash[\'v\']', $overhead);
348read_str_offset(N);
349$t = end_test($t, '$x = $str[0]', $overhead);
350issetor(N);
351$t = end_test($t, '$x = $a ?: null', $overhead);
352issetor2(N);
353$t = end_test($t, '$x = $f ?: tmp', $overhead);
354ternary(N);
355$t = end_test($t, '$x = $f ? $f : $a', $overhead);
356ternary2(N);
357$t = end_test($t, '$x = $f ? $f : tmp', $overhead);
358total($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 @@
1dnl $Id$
2dnl config.m4 for extension snuffleupagus
3
4sources="snuffleupagus.c sp_config.c sp_config_utils.c sp_harden_rand.c"
5sources="$sources sp_unserialize.c sp_utils.c sp_disable_xxe.c sp_list.c"
6sources="$sources sp_disabled_functions.c sp_execute.c sp_upload_validation.c"
7sources="$sources sp_cookie_encryption.c sp_network_utils.c tweetnacl.c"
8sources="$sources sp_config_keywords.c sp_compile.c"
9
10PHP_ARG_ENABLE(snuffleupagus, whether to enable snuffleupagus support,
11[ --enable-snuffleupagus Enable snuffleupagus support])
12
13PHP_ARG_ENABLE(coverage, whether to enable coverage support,
14[ --enable-coverage Enable coverage support])
15
16PHP_ARG_ENABLE(debug, whether to enable debug messages,
17[ --enable-debug Enable debug messages])
18
19CFLAGS="$CFLAGS -lpcre"
20CFLAGS="$CFLAGS -D_DEFAULT_SOURCE=1 -std=c99"
21CFLAGS="$CFLAGS -Wall -Wextra -Wno-unused-parameter"
22
23if test "$PHP_DEBUG" = "yes"; then
24 AC_DEFINE(SP_DEBUG, 1, [Wether you want to enable debug messages])
25fi
26
27if 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
35fi
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
10if (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
40extern 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
55ZEND_BEGIN_MODULE_GLOBALS(snuffleupagus)
56sp_config config;
57HashTable *disabled_functions_hook;
58HashTable *sp_internal_functions_hook;
59ZEND_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)
64ZEND_TSRMLS_CACHE_EXTERN()
65#endif
66
67PHP_FUNCTION(check_disabled_function);
68
69static 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
11static PHP_INI_MH(OnUpdateConfiguration);
12static inline int zend_auto_start(zend_extension *extension);
13static inline void sp_op_array_handler(zend_op_array *op);
14
15ZEND_EXTENSION();
16
17ZEND_DLEXPORT int sp_zend_startup(zend_extension *extension) {
18 return zend_startup_module(&snuffleupagus_module_entry);
19}
20
21static 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
29ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus)
30
31PHP_INI_BEGIN()
32PHP_INI_ENTRY("sp.configuration_file", "", PHP_INI_SYSTEM,
33 OnUpdateConfiguration)
34PHP_INI_END()
35
36ZEND_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
56static 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
64PHP_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
96PHP_MINIT_FUNCTION(snuffleupagus) {
97 REGISTER_INI_ENTRIES();
98
99 return SUCCESS;
100}
101
102PHP_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
132PHP_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
145PHP_RSHUTDOWN_FUNCTION(snuffleupagus) { return SUCCESS; }
146
147PHP_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
157static 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
199const zend_function_entry snuffleupagus_functions[] = {PHP_FE_END};
200
201zend_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
219ZEND_TSRMLS_CACHE_DEFINE()
220#endif
221ZEND_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
4if(!extension_loaded('snuffleupagus')) {
5 dl('snuffleupagus.' . PHP_SHLIB_SUFFIX);
6}
7$module = 'snuffleupagus';
8$functions = get_extension_funcs($module);
9echo "Functions available in the test extension:$br\n";
10foreach($functions as $func) {
11 echo $func."$br\n";
12}
13echo "$br\n";
14$function = 'confirm_' . $module . '_compiled';
15if (extension_loaded($module)) {
16 $str = $function($module);
17} else {
18 $str = "Module $module is not compiled into PHP";
19}
20echo "$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
3ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus);
4
5static zend_op_array *(*orig_compile_file)(zend_file_handle *, int);
6static zend_op_array *(*orig_compile_string)(zval *, char *);
7
8zend_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
34zend_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
41int 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
4int 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
7ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus)
8
9sp_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
24static 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 */
51int parse_empty(char *restrict line, char *restrict keyword, void *retval) {
52 *(bool *)retval = true;
53 return 0;
54}
55
56int 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
69int 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
109int 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
121int 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
138int 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
166int 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
8typedef enum {
9 SP_TYPE_STR = 0,
10 SP_TYPE_REGEXP,
11 SP_TYPE_INT,
12 SP_TYPE_EMPTY
13} sp_type;
14
15typedef 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
29typedef 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
38typedef struct { char *encryption_key; } sp_config_encryption_key;
39
40typedef struct {
41 bool enable;
42 bool simulation;
43} sp_config_readonly_exec;
44
45typedef struct { bool enable; } sp_config_global_strict;
46
47typedef struct { bool enable; } sp_config_random;
48
49typedef struct { bool enable; } sp_config_auto_cookie_secure;
50
51typedef struct { bool enable; } sp_config_disable_xxe;
52
53typedef struct {
54 HashTable *names;
55 uint32_t mask_ipv4;
56 uint32_t mask_ipv6;
57} sp_config_cookie_encryption;
58
59typedef struct {
60 bool enable;
61 bool simulation;
62} sp_config_unserialize;
63
64typedef 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
101typedef struct {
102 sp_node_t *disabled_functions; // list of sp_disabled_function
103} sp_config_disabled_functions;
104
105typedef struct {
106 sp_node_t *regexp_inclusion; // list of regexp for inclusion
107} sp_config_regexp_inclusion;
108
109typedef struct {
110 char *script;
111 bool simulation;
112 bool enable;
113} sp_config_upload_validation;
114
115typedef 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
130typedef struct {
131 int (*func)(char *, char *, void *);
132 char *token;
133 void *retval;
134} sp_config_functions;
135
136typedef 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
195int sp_parse_config(const char *);
196int parse_array(sp_disabled_function *);
197
198int parse_str(char *restrict, char *restrict, void *);
199int parse_regexp(char *restrict, char *restrict, void *);
200int parse_empty(char *restrict, char *restrict, void *);
201int parse_int(char *restrict, char *restrict, void *);
202int parse_cidr(char *restrict, char *restrict, void *);
203int 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
3ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus)
4
5static 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
29int parse_random(char *line) {
30 return parse_enable(line, &(SNUFFLEUPAGUS_G(config).config_random->enable), NULL);
31}
32
33int parse_disable_xxe(char *line) {
34 return parse_enable(line, &(SNUFFLEUPAGUS_G(config).config_disable_xxe->enable), NULL);
35}
36
37int parse_auto_cookie_secure(char *line) {
38 return parse_enable(line, &(SNUFFLEUPAGUS_G(config).config_auto_cookie_secure->enable), NULL);
39}
40
41int parse_global_strict(char *line) {
42 return parse_enable(line, &(SNUFFLEUPAGUS_G(config).config_global_strict->enable), NULL);
43}
44
45int parse_unserialize(char *line) {
46 return parse_enable(line, &(SNUFFLEUPAGUS_G(config).config_unserialize->enable), &(SNUFFLEUPAGUS_G(config).config_unserialize->simulation));
47}
48
49int 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
53int 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
61int 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
93int 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
230int 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
5int parse_random(char *line);
6int parse_disable_xxe(char *line);
7int parse_auto_cookie_secure(char *line);
8int parse_global_strict(char *line);
9int parse_global(char *line) ;
10int parse_cookie_encryption(char *line);
11int parse_unserialize(char *line) ;
12int parse_readonly_exec(char *line);
13int parse_disabled_functions(char *line) ;
14int 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
3static int validate_int(const char *value);
4static int validate_str(const char *value);
5
6static 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
15static 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
35int 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
65static 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 }
117err:
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
125static 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
150char *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
171int 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
4int parse_keywords(sp_config_functions *, char *);
5char *get_param(size_t *, char *restrict, sp_type, const char *restrict);
6int 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
5ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus)
6
7static unsigned int nonce_d = 0;
8
9static 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
39int 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*/
101static 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
130PHP_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(&params[1], encrypted_data);
174 zend_string_release(encrypted_data);
175 } else if (value) {
176 ZVAL_STR_COPY(&params[1], value);
177 }
178
179 ZVAL_STRING(&func_name, "setcookie");
180 ZVAL_STR_COPY(&params[0], name);
181 ZVAL_LONG(&params[2], expires);
182 if (path) {
183 ZVAL_STR_COPY(&params[3], path);
184 }
185 if (domain) {
186 ZVAL_STR_COPY(&params[4], domain);
187 }
188 if (secure) {
189 ZVAL_LONG(&params[5], secure);
190 }
191 if (httponly) {
192 ZVAL_LONG(&params[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
212int 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
14int hook_cookies();
15int 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
3ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus)
4
5PHP_FUNCTION(sp_libxml_disable_entity_loader) { RETURN_TRUE; }
6
7int 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(&params[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
4int 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
6ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus);
7
8ZEND_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
16static 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
34static 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
74bool 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 }
218next:
219config = config->next;
220 }
221allow:
222 efree(complete_path_function);
223 return false;
224}
225
226static 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
300ZEND_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
324static 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
345int 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
8int hook_disabled_functions();
9bool 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
6ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus);
7
8static void (*orig_execute_ex)(zend_execute_data *execute_data);
9static int (*orig_zend_stream_open)(const char *filename,
10 zend_file_handle *handle);
11
12// FIXME handle symlink
13ZEND_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
31static 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
48static 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
67execute:
68 orig_execute_ex(execute_data);
69}
70
71static 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
85int 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
4int 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
3extern ZEND_API zend_class_entry *zend_ce_error;
4
5ZEND_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. */
9static 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
44PHP_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
57PHP_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
70int 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
8int 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
6void 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
14sp_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
20void 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
4typedef 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
11sp_node_t *sp_new_list();
12void sp_list_insert(sp_node_t *, void *);
13void 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
7ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus)
8
9static inline bool cidr4_match(const struct in_addr addr,
10 const struct in_addr net, uint8_t bits);
11static inline bool cidr6_match(const struct in6_addr address,
12 const struct in6_addr network, uint8_t bits);
13static inline int get_ip_version(const char *ip);
14
15void 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 */
47static 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
55static 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
83static 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
101bool 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
125int 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
4int get_ip_and_cidr(char *, sp_cidr *);
5bool cidr_match(const char *, const sp_cidr *);
6void 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
3ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus)
4
5PHP_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(&params[0], "sha256");
25 params[1] = *return_value;
26 ZVAL_STRING(&params[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
43PHP_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(&params[0], "sha256");
73 ZVAL_STRING(&params[1], serialized_str);
74 ZVAL_STRING(&params[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
104int 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
4int hook_serialize(void);
5
6PHP_FUNCTION(sp_serialize);
7PHP_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
4ZEND_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
11void hook_upload() {
12 sp_rfc1867_orig_callback = php_rfc1867_callback;
13 php_rfc1867_callback = sp_rfc1867_callback;
14}
15
16int 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
4void hook_upload();
5
6int (*sp_rfc1867_orig_callback)(unsigned int event, void *event_data, void **extra);
7int 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
9static 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
19void 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
32int 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
55static 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
81int 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
148static char *zv_str_to_char(zval *zv) {
149 zval copy;
150 char *ret;
151
152
153 ZVAL_ZVAL(&copy, 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
166char* 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
197bool 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
218void 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
259void 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
283int 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
308int 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
342zend_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
350zend_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
362int 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
403int 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
50void sp_log_msg(char const *feature, char const *level, const char* fmt, ...);
51int compute_hash(const char *const filename, char *file_hash);
52char *sp_convert_to_string(zval *);
53bool sp_match_value(const char *, const char *, const pcre *);
54int sp_match_array_key(const zval *, const char *, const pcre *);
55int sp_match_array_key_recurse(const zval *, sp_node_t *, const char *,
56 const pcre *);
57void sp_log_disable(const char *restrict, const char *restrict,
58 const char *restrict, const sp_disabled_function *);
59void sp_log_disable_ret(const char *restrict, const char *restrict,
60 const sp_disabled_function *);
61char *sp_getenv(char *);
62int is_regexp_matching(const pcre *, const char *);
63int hook_function(const char *, HashTable *,
64 void (*)(INTERNAL_FUNCTION_PARAMETERS), bool);
65int 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--
2Broken configuration
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI--
6sp.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--
2Broken configuration
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI--
6sp.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--
2Broken configuration
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI--
6sp.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--
2Global strict mode
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI--
6sp.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--
2Bad boolean value in configuration
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI--
6sp.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--
2Bad integer value in configuration
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI--
6sp.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--
2Broken configuration
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI--
6sp.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--
2Broken configuration
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI--
6sp.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--
2Broken configuration, invalid cidr for ipv6 because there is no `/` in it
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI--
6sp.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--
2Broken 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--
7sp.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--
2Broken configuration, invalid cidr value
3(13337%128 = 25)
4--SKIPIF--
5<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
6--INI--
7sp.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--
2Broken conf with wrong type
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.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--
2Configuration line with an empty string
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI--
6sp.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--
2Configuration line without closing parenthese
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI--
6sp.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--
2Line too long in configuration
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI--
6sp.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--
2Configuration line with too many quotes
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI--
6sp.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--
2Broken configuration
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI--
6sp.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--
2Broken configuration
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI--
6sp.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--
2Broken configuration
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI--
6sp.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--
2Broken configuration
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI--
6sp.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--
2Broken configuration
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI--
6sp.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--
2Broken configuration
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI--
6sp.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--
2Broken configuration
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI--
6sp.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--
2Broken configuration
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI--
6sp.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--
2Configuration line without closing parenthese, misc
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI--
6sp.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--
2Bad config, unknown keyword
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI--
6sp.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--
2Configuration line with too many quotes
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI--
6sp.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--
2Broken conf with wrong type
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.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--
2Broken regexp
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.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
5sp.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 @@
1sp.global.secret_key("abcdef");
2sp.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 @@
1sp.disable_functions.function("strpos").ret_type("undef").drop().alias("Return value is undef");
2sp.disable_functions.function("strpos").ret_type("null").drop().alias("Return value is null");
3sp.disable_functions.function("strpos").ret_type("object").drop().alias("Return value is object");
4sp.disable_functions.function("strpos").ret_type("reference").drop().alias("Return value is reference");
5sp.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 @@
1sp.disable_functions.function_r("^system$").filename_r("\\.txt$").drop();
2sp.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 @@
1sp.disable_functions.function("AwesomeClass::method1").drop();
2sp.disable_functions.function("method2").drop();
3sp.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 @@
1sp.disable_functions.function_r("^not_system$").ret("42").drop();
2sp.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 @@
1sp.disable_functions.function("strcmp").drop();
2sp.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 @@
1sp.disable_functions.function("system").param("command").value_r("^id$").alias("1").drop();
2sp.disable_functions.function("array_sum").param("array").value_r("^8$").alias("2").drop();
3sp.disable_functions.function("shell_exec").param("cmd").value("id").alias("3").drop();
4sp.disable_functions.function("shell_exec").param("cmd").value("bla").alias("4").drop();
5sp.disable_functions.function("strcmp").param("str1").value("bla").alias("5").drop().simulation();
6sp.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 @@
1sp.disable_functions.function("system").alias("1").drop();
2sp.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 @@
1sp.disable_functions.function("system").param("command").value("echo win").filename("test.php").drop();
2sp.disable_functions.function("system").param("command").value("echo win").allow();
3sp.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 @@
1sp.disable_functions.function("foo").param("arr").value("abcd").alias("1").drop();
2sp.disable_functions.function("foo").param("arr[bla]").value("abcdef").alias("2").drop();
3sp.disable_functions.function("foo").param("arr[test]").alias("3").drop();
4sp.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 @@
1sp.disable_functions.function("foobar").param("id").value("42").drop();
2sp.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 @@
1sp.disable_functions.function("strpos").hash("70b33f3eaf585b245640bb2c92445d0040b2bcb31395aa25dede9f2df4dbcbe8").allow();
2sp.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 @@
1sp.disable_functions.function("system").ret("1").drop();
2sp.disable_functions.function("system").ret("1337").hash("123456789597a81a2b862cdb49920e2cba2e5979a3fc374c58c803e8f5c99a10").drop();
3sp.disable_functions.function("system").ret("1338").hash("522a976fa597a81a2b862cdb49920e2cba2e5979a3fc374c58c803e8f5c99a10").drop();
4sp.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 @@
1sp.disable_functions.function("strpos").ret("0").simulation().drop();
2sp.disable_functions.function("stripos").ret("0").simulation().drop().alias("1");
3sp.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 @@
1sp.disable_functions.function("system").hash("1337c3ad8cf096272cd0e78768af3b11325f498de5c2c36f40adc43643af378a").allow();
2sp.disable_functions.function("system").hash("d259c3ad8cf096272cd0e78768af3b11325f498de5c2c36f40adc43643af378a").allow();
3sp.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 @@
1sp.global.secret_key("abcdef");
2sp.cookie_encryption.cookie("super_cookie").mask_ipv4(8).mask_ipv6(2);
3sp.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 @@
1sp.global.secret_key("abcdef");
2sp.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 @@
1sp.global.secret_key("abcdef");
2sp.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 @@
1sp.disable_functions.function("phpinfo").var("b").value("1337").drop();
2sp.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 @@
1sp.disable_functions.function("system").drop();
2sp.disable_functions.function("vprintf").hash("123456789").drop();
3sp.disable_functions.function("printf").disable().drop();
4sp.disable_functions.function("printf").simulation().drop();
5sp.disable_functions.function("print").disable().drop(); # this is a comment
6sp.disable_functions.function_r("^var_dump$").drop();
7sp.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 @@
1sp.disable_functions.function("system").drop().cidr("127.0.0.1/8");
2sp.disable_functions.function("printf").drop().cidr("10.0.0.1/8");
3sp.disable_functions.function("strpos").drop().cidr("2001:0db8:0000:0000:0000:ff00:0042:8329/24");
4sp.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 @@
1sp.disable_functions.function("strlen").drop();
2sp.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 @@
1sp.disable_functions.function("testFunction").ret("0").drop().disable();
2sp.disable_functions.function("strpos").ret("0").drop().filename_r(".*\\.php");
3sp.disable_functions.function_r("str[ia]pos").ret_r("^[^a-z]+$").drop();
4sp.disable_functions.function_r("stripos").ret_r("^[^a-z]+").drop();
5sp.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 @@
1sp.upload_validation.script("tests/upload_ko.sh");
2sp.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
2exit 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
2exit 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
2exit 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--
2Readonly execution attempt
3--SKIPIF--
4<?php
5if (!extension_loaded("snuffleupagus")) print "skip";
6
7$filename = __DIR__ . '/test.txt';
8
9@unlink($filename);
10
11file_put_contents($filename, 'a');
12chmod($filename, 0400);
13
14if (is_writable($filename)) print "skip";
15@unlink($filename);
16 ?>
17--INI--
18sp.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
27file_put_contents("$dir/non_writable_file.txt", '<?php echo "Code execution within a non-writable file.\n";');
28file_put_contents("$dir/writable_file.txt", '<?php echo "Code execution within a writable file.\n";');
29chmod("$dir/non_writable_file.txt", 0400);
30chmod("$dir/writable_file.txt", 0777);
31include "$dir/non_writable_file.txt";
32include "$dir/writable_file.txt";
33?>
34--EXPECTF--
35Code 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__;
40chmod("$dir/non_writable_file.txt", 0777);
41chmod("$dir/writable_file.txt", 0777);
42unlink("$dir/non_writable_file.txt");
43unlink("$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--
2Readonly execution attempt
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI--
6sp.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
15file_put_contents("$dir/writable_file.txt", '<?php echo "Code execution within a writable file.\n";');
16file_put_contents("$dir/non_writable_file.txt", '<?php echo "Code execution within a non-writable file.\n";');
17chmod("$dir/writable_file.txt", 0777);
18chmod("$dir/non_writable_file.txt", 0400);
19include "$dir/writable_file.txt";
20include "$dir/non_writable_file.txt";
21?>
22--EXPECT--
23Code execution within a writable file.
24Code execution within a non-writable file.
25--CLEAN--
26<?php
27$dir = __DIR__;
28chmod("$dir/non_writable_file.txt", 0777);
29chmod("$dir/writable_file.txt", 0777);
30unlink("$dir/non_writable_file.txt");
31unlink("$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--
2Readonly execution attempt (simulation mode)
3--SKIPIF--
4<?php
5if (!extension_loaded("snuffleupagus")) print "skip";
6
7$filename = __DIR__ . '/test.txt';
8
9@unlink($filename);
10
11file_put_contents($filename, 'a');
12chmod($filename, 0400);
13
14if (is_writable($filename)) print "skip";;
15@unlink($filename);
16 ?>
17--INI--
18sp.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
27file_put_contents("$dir/writable_file.txt", '<?php echo "Code execution within a writable file.\n";');
28file_put_contents("$dir/non_writable_file.txt", '<?php echo "Code execution within a non-writable file.\n";');
29chmod("$dir/writable_file.txt", 0777);
30chmod("$dir/non_writable_file.txt", 0400);
31include "$dir/writable_file.txt";
32include "$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).
36Code execution within a writable file.
37Code execution within a non-writable file.
38--CLEAN--
39<?php
40$dir = __DIR__;
41chmod("$dir/non_writable_file.txt", 0777);
42chmod("$dir/writable_file.txt", 0777);
43unlink("$dir/non_writable_file.txt");
44unlink("$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--
2Disable XXE
3--SKIPIF--
4<?php
5 if (!extension_loaded("snuffleupagus")) die "skip";
6 if (!extension_loaded("dom")) die "skip";
7 ?>
8--INI--
9extension=`php-config --extension-dir`/dom.so
10sp.configuration_file={PWD}/config/disable_xxe.ini
11--FILE--
12<?php
13$dir = __DIR__;
14$content = 'WARNING, external entity loaded!';
15file_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>
24EOD;
25
26file_put_contents('content.xml', $xml);
27
28libxml_disable_entity_loader(true);
29$dom = new DOMDocument('1.0');
30$dom->loadXML($xml, LIBXML_DTDATTR|LIBXML_DTDLOAD|LIBXML_NOENT);
31printf("libxml_disable_entity to true: %s\n", $dom->getElementsByTagName('testing')->item(0)->nodeValue);
32
33libxml_disable_entity_loader(false);
34$dom = new DOMDocument('1.0');
35$dom->loadXML($xml, LIBXML_DTDATTR|LIBXML_DTDLOAD|LIBXML_NOENT);
36printf("libxml_disable_entity to false: %s\n", $dom->getElementsByTagName('testing')->item(0)->nodeValue);
37
38$xml = "<test><testing>foo</testing></test>";
39file_put_contents('content.xml', $xml);
40
41libxml_disable_entity_loader(false);
42$dom = new DOMDocument('1.0');
43$dom->loadXML($xml, LIBXML_DTDATTR|LIBXML_DTDLOAD|LIBXML_NOENT);
44printf("without xxe: %s", $dom->getElementsByTagName('testing')->item(0)->nodeValue);
45
46?>
47--EXPECTF--
48Warning: DOMDocument::loadXML(): I/O warning : failed to load external entity "file://%a/content.txt" in %a/disable_xxe_dom.php on line %d
49
50Warning: DOMDocument::loadXML(): Failure to process entity foo in Entity, line: %d in %a/disable_xxe_dom.php on line %d
51
52Warning: DOMDocument::loadXML(): Entity 'foo' not defined in Entity, line: %d in %a/disable_xxe_dom.php on line %d
53
54Notice: Trying to get property of non-object in %a/disable_xxe_dom.php on line %d
55libxml_disable_entity to true:
56
57Warning: DOMDocument::loadXML(): I/O warning : failed to load external entity "file://%a/content.txt" in %a/disable_xxe_dom.php on line %d
58
59Warning: DOMDocument::loadXML(): Failure to process entity foo in Entity, line: %d in %a/disable_xxe_dom.php on line %d
60
61Warning: DOMDocument::loadXML(): Entity 'foo' not defined in Entity, line: %d in %a/disable_xxe_dom.php on line %d
62
63Notice: Trying to get property of non-object in %a/disable_xxe_dom.php on line %d
64libxml_disable_entity to false:
65without xxe: foo
66--CLEAN--
67<?php
68$dir = __DIR__;
69unlink($dir . "content.xml");
70unlink($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--
2Disable XXE
3--SKIPIF--
4<?php
5 if (!extension_loaded("snuffleupagus")) die "skip";
6 if (!extension_loaded("dom")) die "skip";
7 ?>
8--INI--
9extension=`php-config --extension-dir`/dom.so
10sp.configuration_file={PWD}/config/disable_xxe_disable.ini
11--FILE--
12<?php
13$dir = __DIR__;
14$content = '<content>WARNING, external entity loaded!</content>';
15file_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>
24EOD;
25
26file_put_contents($dir . '/content.xml', $xml);
27
28libxml_disable_entity_loader(true);
29$dom = new DOMDocument('1.0');
30$dom->loadXML($xml, LIBXML_DTDATTR|LIBXML_DTDLOAD|LIBXML_NOENT);
31printf("libxml_disable_entity to true: %s\n", $dom->getElementsByTagName('testing')->item(0)->nodeValue);
32
33libxml_disable_entity_loader(false);
34$dom = new DOMDocument('1.0');
35$dom->loadXML($xml, LIBXML_DTDATTR|LIBXML_DTDLOAD|LIBXML_NOENT);
36printf("libxml_disable_entity to false: %s\n", $dom->getElementsByTagName('testing')->item(0)->nodeValue);
37
38$xml = "<test><testing>foo</testing></test>";
39file_put_contents('content.xml', $xml);
40
41libxml_disable_entity_loader(false);
42$dom = new DOMDocument('1.0');
43$dom->loadXML($xml, LIBXML_DTDATTR|LIBXML_DTDLOAD|LIBXML_NOENT);
44printf("without xxe: %s", $dom->getElementsByTagName('testing')->item(0)->nodeValue);
45
46?>
47--EXPECTF--
48libxml_disable_entity to true: WARNING, external entity loaded!
49libxml_disable_entity to false: WARNING, external entity loaded!
50without xxe: foo
51--CLEAN--
52<?php
53$dir = __DIR__;
54unlink($dir . "/content.xml");
55unlink($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--
2Disable XXE
3--SKIPIF--
4<?php
5 if (!extension_loaded("snuffleupagus")) die "skip";
6 if (!extension_loaded("simplexml")) die "skip";
7 ?>
8--INI--
9extension=`php-config --extension-dir`/simplexml.so
10sp.configuration_file={PWD}/config/disable_xxe.ini
11--FILE--
12<?php
13$dir = __DIR__;
14$content = 'WARNING, external entity loaded!';
15file_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>
24EOD;
25
26file_put_contents('content.xml', $xml);
27
28libxml_disable_entity_loader(true);
29$doc = new SimpleXMLElement($xml);
30printf("libxml_disable_entity to true: %s\n", $doc->testing);
31
32libxml_disable_entity_loader(false);
33$doc = new SimpleXMLElement($xml);
34printf("libxml_disable_entity to false: %s\n", $doc->testing);
35
36$xml = "<test><testing>foo</testing></test>";
37file_put_contents('content.xml', $xml);
38
39$doc = new SimpleXMLElement($xml);
40printf("without xxe: %s", $doc->testing);
41
42?>
43--EXPECT--
44libxml_disable_entity to true:
45libxml_disable_entity to false:
46without xxe: foo
47--CLEAN--
48<?php
49$dir = __DIR__;
50unlink($dir . "/content.xml");
51unlink($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--
2Disable XXE
3--SKIPIF--
4<?php
5 if (!extension_loaded("snuffleupagus")) die "skip";
6 if (!extension_loaded("simplexml")) die "skip";
7 ?>
8--INI--
9extension=`php-config --extension-dir`/simplexml.so
10sp.configuration_file={PWD}/config/disable_xxe.ini
11--FILE--
12<?php
13$dir = __DIR__;
14$content = 'WARNING, external entity loaded!';
15file_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>
24EOD;
25
26file_put_contents('content.xml', $xml);
27
28libxml_disable_entity_loader(true);
29$doc = simplexml_load_string($xml);
30printf("libxml_disable_entity to true: %s\n", $doc->testing);
31
32libxml_disable_entity_loader(false);
33$doc = simplexml_load_string($xml);
34printf("libxml_disable_entity to false: %s\n", $doc->testing);
35
36$xml = "<test><testing>foo</testing></test>";
37file_put_contents('content.xml', $xml);
38
39$doc = simplexml_load_string($xml);
40printf("without xxe: %s", $doc->testing);
41
42?>
43--EXPECT--
44libxml_disable_entity to true:
45libxml_disable_entity to false:
46without xxe: foo
47--CLEAN--
48<?php
49$dir = __DIR__;
50unlink($dir . "/content.xml");
51unlink($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--
2Disable XXE
3--SKIPIF--
4<?php
5 if (!extension_loaded("snuffleupagus")) die "skip";
6 if (!extension_loaded("xml")) die "skip";
7 ?>
8--INI--
9extension=`php-config --extension-dir`/xml.so
10sp.configuration_file={PWD}/config/disable_xxe.ini
11--FILE--
12<?php
13$dir = __DIR__;
14$content = 'WARNING, external entity loaded!';
15file_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>
24EOD;
25
26file_put_contents('content.xml', $xml);
27
28function 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
52libxml_disable_entity_loader(true);
53$parser = create_parser();
54$doc = xml_parse($parser, $xml, true);
55xml_parser_free($parser);
56
57libxml_disable_entity_loader(false);
58$parser = create_parser();
59$doc = xml_parse($parser, $xml, true);
60xml_parser_free($parser);
61
62$xml = "<test><testing>foo</testing></test>";
63file_put_contents('content.xml', $xml);
64$parser = create_parser();
65$doc = xml_parse($parser, $xml, true);
66xml_parser_free($parser);
67
68--EXPECT--
69string(4) "TEST"
70
71array(0) {
72}
73string(7) "TESTING"
74
75array(0) {
76}
77string(7) "TESTING"
78string(4) "TEST"
79string(4) "TEST"
80
81array(0) {
82}
83string(7) "TESTING"
84
85array(0) {
86}
87string(7) "TESTING"
88string(4) "TEST"
89string(4) "TEST"
90
91array(0) {
92}
93string(7) "TESTING"
94
95array(0) {
96}
97textfoostring(7) "TESTING"
98string(4) "TEST"
99--CLEAN--
100<?php
101$dir = __DIR__;
102unlink($dir . "/content.xml");
103unlink($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--
2Disable functions - match on a local variable
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/disabled_function_local_var.ini
7--FILE--
8<?php
9$a = 1338;
10function test(){
11 echo strlen("id") . "\n";
12}
13echo "Value of a: $a\n";
14test();
15
16$a = 1337;
17echo "Value of a: $a\n";
18test();
19?>
20--EXPECTF--
21Value of a: 1338
222
23Value 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--
2Disable functions - match on a super global
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/disabled_function_super_global_var.ini
7--GET--
8bla=test
9--FILE--
10<?php
11function test(){
12 echo strlen($_GET['bla']) . "\n";
13}
14test();
15$_GET['bla'] = 'test2';
16test();
17?>
18--EXPECTF--
194
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--
2Disable functions
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/disabled_functions.ini
7--FILE--
8<?php
9system("id");
10printf("printf in simulation mode\n");
11print("print in disabled mode\n");
12var_dump("this is a super test");
13echo 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.
18printf in simulation mode
19print 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.
211
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--
2Disable functions
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--ENV--
6return <<<EOF
7REMOTE_ADDR=127.0.0.1
8EOF;
9--INI--
10sp.configuration_file={PWD}/config/disabled_functions_cidr.ini
11--FILE--
12<?php
13system("echo 42");
14printf("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.
181337
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--
2Disable functions
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--ENV--
6return <<<EOF
7REMOTE_ADDR=2001:0db8:0000:0000:0000:ff00:0042:8328
8EOF;
9--INI--
10sp.configuration_file={PWD}/config/disabled_functions_cidr.ini
11--FILE--
12<?php
13strpos("a", "b");
14printf(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.
181337
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--
2Disable functions - filename regexp
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/config_disabled_functions_filename_r.ini
7--FILE--
8<?php
9system("echo 42");
10shell_exec("echo 43");
11?>
12--EXPECTF--
1342
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--
2Disable functions
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/disabled_functions_mb.ini
7--FILE--
8<?php
9echo 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--
2Disable functions
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/config_disabled_functions_method.ini
7--FILE--
8<?php
9class 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.
28method2: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--
2Disable functions
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/config_disabled_functions_name_r.ini
7--FILE--
8<?php
9system("echo 42");
10system("echo 1337");
11?>
12--EXPECTF--
1342
141337
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--
2Disable functions
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/config_disabled_functions_name_type.ini
7--FILE--
8<?php
9echo strcmp("pouet", "pouet") . "\n";
10echo strcmp([1,23], "pouet") . "\n";
11?>
12--EXPECTF--
130
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--
2Disable functions: namespaces support isn't implemented now
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/config_disabled_functions_namespace.ini
7--FILE--
8<?php
9namespace my_super_namespace {
10 function my_function() {
11 echo "1\n";
12 }
13}
14namespace my_second_namespace {
15 function my_function() {
16 echo "2\n";
17 }
18}
19namespace {
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();
26my_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--
2Disable functions
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/empty.ini
7--FILE--
8<?php
9echo strpos("pouet", "o");
10?>
11--EXPECT--
121
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--
2Disable functions with nul byte
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/config_disabled_functions_nul_byte.ini
7--FILE--
8<?php
9system("\0id");
10system("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--
2Disable functions
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/config_disabled_functions_param.ini
7--FILE--
8<?php
9system("id");
10system("echo win");
11var_dump(array_sum([1,2,3,4,5]));
12shell_exec("id");
13echo shell_exec("echo 42");
14strcmp("bla", "ble");
15strncmp("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'.
19win
20int(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'.
2242
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--
2Disable functions - alias
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/config_disabled_functions_param_alias.ini
7--FILE--
8<?php
9system("id");
10shell_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--
2Disable functions - allow
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/config_disabled_functions_param_allow.ini
7--FILE--
8<?php
9system("echo win");
10system("id");
11?>
12--EXPECTF--
13win
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--
2Disable functions
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/config_disabled_functions_param_array.ini
7--FILE--
8<?php
9function foo($arr) {
10 echo $arr["a"]."\n";
11}
12$a=Array("a"=>"test1");
13foo($a);
14$a=Array("a"=>"abcd");
15foo($a);
16$a=Array("a"=>"abcde");
17foo($a);
18$a=Array("bla"=>"abcdef");
19foo($a);
20$a=Array("bla"=>"aaa", "a"=>"eee" );
21foo($a);
22$a=Array("test"=>"aaa", "a"=>"fff" );
23foo($a);
24$a=Array("test2"=>Array("foo"=>Array("lol"=>"bbb")), "a"=>"cccc");
25foo($a);
26$a=Array("test2"=>Array("foo"=>Array("lol"=>"aaa")), "a"=>"dddd");
27foo($a);
28?>
29--EXPECTF--
30test1
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'.
32abcde
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'.
34eee
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'.
36cccc
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--
2Disable functions
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/config_disabled_functions_param_int.ini
7--FILE--
8<?php
9function foobar($id) {
10 echo $id."\n";
11}
12foobar(1);
13foobar(42);
14foobar(1337);
15foobar(13374242);
16foobar(0x2A);
17foobar("10");
18?>
19--EXPECTF--
201
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.
2510
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--
2Disable functions
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/config_disabled_functions_param_r.ini
7--FILE--
8<?php
9system("id");
10system("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.
14win
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--
2Disable functions - casting various types to string internally
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/config_disabled_functions_param_str_representation.ini
7--FILE--
8<?php
9echo var_export(true) . "\n";
10echo var_export(false) . "\n";
11echo var_export(null) . "\n";
12echo var_export(1) . "\n";
13echo var_export(1.0) . "\n";
14function f(&$a) {
15 echo var_export($a) . "\n";
16}
17$a = 123; f($a);
18?>
19--EXPECTF--
20true
21false
22NULL
231
241.0
25123
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--
2Disable functions - Parsing of an Object as a return value of a function
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/disabled_functions_ret.ini
7--FILE--
8<?php
9/*
10Because Snuffleupagus used to cast everything with the `zval_get_string` function,
11this sometimes raised exceptions, because PHP is awful.
12 */
13class Bob {
14 function a() {
15 return new StdClass;
16 }
17}
18$b = new Bob;
19echo ($b->a() instanceof StdClass)?'Y':'N';
20?>
21--EXPECT--
22Y
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--
2Disable functions - Require
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/config_disabled_functions_require.ini
7--FILE--
8<?php
9$dir = __DIR__;
10file_put_contents($dir . '/test.meh', "");
11file_put_contents($dir . '/test.bla', "");
12require $dir . '/test.meh';
13require $dir . '/test.bla';
14echo "1337";
15?>
16--XFAIL--
17PHP 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__;
23unlink($dir . '/test.meh');
24unlink($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--
2Disable functions check on `ret`.
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/disabled_functions_ret.ini
7--FILE--
8<?php
9echo strpos("pouet", "p");
10echo 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--
2Disable functions check on `ret`.
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/disabled_functions_ret.ini
7--FILE--
8<?php
9echo 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--
2Disable functions check on `ret`.
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/disabled_functions_ret.ini
7--FILE--
8<?php
9class Bob {
10 function a() {
11 echo("We're in function `a`.\n");
12 return 1;
13 }
14}
15$b = new Bob();
16echo "`a` returned: " . $b->a() . ".\n";
17echo("We're at the end of the execution.\n");
18?>
19--EXPECTF--
20We're in function `a`.
21`a` returned: 1.
22We'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--
2Disable functions check on `ret`.
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/config_disabled_functions_ret_allow.ini
7--FILE--
8<?php
9echo strpos("pouet", "p");
10echo stripos("pouet", "p");
11?>
12--EXPECT--
1300 \ 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--
2Disable functions check on `ret` allowed
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/config_disabled_functions_ret_allow_value.ini
7--FILE--
8<?php
9echo strpos("pouet", "p");
10?>
11--EXPECT--
120
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--
2Disable functions
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/config_disabled_functions_ret_right_hash.ini
7--FILE--
8<?php
9system("echo $((1 + 1336))");
10?>
11--EXPECTF--
121337
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--
2Disable functions check on `ret` simulation
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/config_disabled_functions_ret_simulation.ini
7--FILE--
8<?php
9echo strpos("pouet", "p") . "\n";
10echo stripos("pouet", "p") . "\n";
11strcmp("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.
150
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'.
170
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--
2Disable functions check on `ret` by type matching on boolean
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/disabled_functions_ret_type.ini
7--FILE--
8<?php
9echo strpos("pouet", "p") . "\n";
10echo "1337\n";
11echo strpos("pouet", "123");
12?>
13--EXPECTF--
140
151337
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--
2Disable functions check on `ret` by type matching (double).
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/disabled_functions_ret_type_double.ini
7--FILE--
8<?php
9echo 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--
2Disable functions check on `ret` by type matching (long).
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/disabled_functions_ret_type_long.ini
7--FILE--
8<?php
9echo 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--
2Disable functions check on `ret` by type matching (resource).
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/disabled_functions_ret_type_resource.ini
7--FILE--
8<?php
9echo 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--
2Disable functions check on `ret` by type matching (string).
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/disabled_functions_ret_type_str.ini
7--FILE--
8<?php
9echo 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--
2Disable functions check on `ret` by type matching (true).
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/disabled_functions_ret_type_true.ini
7--FILE--
8<?php
9var_dump(is_numeric("pouet")) . "\n";
10echo "1337\n";
11echo is_numeric("1234") . "\n";
12?>
13--EXPECTF--
14bool(false)
151337
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--
2Disable functions ret val
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/disabled_functions_retval.ini
7--FILE--
8<?php
9echo str_repeat("fufu",1)."\n";
10echo str_repeat("fufufu",1);
11?>
12--EXPECTF--
13fufu
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--
2Disable functions ret val rx
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/disabled_functions_retval_rx.ini
7--FILE--
8<?php
9echo str_repeat("fufu",1)."\n";
10echo str_repeat("fufufu",1);
11?>
12--EXPECTF--
13fufu
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--
2Disable functions
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/config_disabled_functions_right_hash.ini
7--FILE--
8<?php
9system("echo $((1 + 1336))");
10?>
11--EXPECTF--
121337
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--
2Disable functions - runtime inclusion
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.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"; }';
12file_put_contents('file_to_include1.php', $content);
13file_put_contents('file_to_include2.php', $content);
14
15if (rand() % 2) {
16 include "file_to_include1.php";
17} else {
18 include "file_to_include2.php";
19}
20
21test('1338');test('1337');
22
23?>
24--EXPECTF--
251338
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
29unlink("file_to_include1.php");
30unlink("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--
2Disable functions
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--ENV--
6return <<<EOF
7REMOTE_ADDR=127.0.0.1
8EOF;
9--INI--
10sp.configuration_file={PWD}/config/disabled_functions_zero_cidr.ini
11--FILE--
12<?php
13system("echo 42");
14printf("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.
181337
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--
2Harden rand
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/config_rand_harden_disabled.ini
7--FILE--
8<?php
9srand(0);
10echo rand(0,100)."\n";
11srand(0);
12echo rand(0,100)."\n";
13?>
14--EXPECT--
1584
1684
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--
2Disabled user-created functions
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/config_disabled_user_functions.ini
7--FILE--
8<?php
9function my_super_function() {
10 echo 1;
11}
12my_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--
2Dump request
3--SKIPIF--
4<?php
5if (!extension_loaded("snuffleupagus")) {
6 print "skip";
7}
8
9foreach (glob("./tests/dump_results/*.dump") as $dump) {
10 unlink($dump);
11}
12rmdir("./tests/dump_results/");
13?>
14--POST--
15post_a=data_post_a&post_b=data_post_b
16--GET--
17get_a=data_get_a&get_b=data_get_b
18--COOKIE--
19cookie_a=data_cookie_a&cookie_b=data_cookie_b
20--INI--
21sp.configuration_file={PWD}/config/dump_request.ini
22--FILE--
23<?php
24mkdir("./dump_results/");
25echo "1\n";
26echo system("echo 1337;");
27$filename = glob('./dump_results/*.dump')[0];
28$res = file($filename);
29if ($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--
381
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--
2Dump request - invalid folder.
3--SKIPIF--
4<?php
5if (!extension_loaded("snuffleupagus")) { print "skip"; }
6?>
7--POST--
8post_a=data_post_a&post_b=data_post_b
9--GET--
10get_a=data_get_a&get_b=data_get_b
11--COOKIE--
12cookie_a=data_cookie_a&cookie_b=data_cookie_b
13--INI--
14sp.configuration_file={PWD}/config/dump_request_invalid_folder.ini
15--FILE--
16<?php
17echo "1\n";
18echo system("echo 1337;");
19echo "2\n";
20?>
21--EXPECTF--
221
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
252 \ 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--
2Dump request -- to big, so it's truncated.
3--SKIPIF--
4<?php
5if (!extension_loaded("snuffleupagus")) {
6 print "skip";
7}
8
9foreach (glob("./tests/dump_results/*.dump") as $dump) {
10 unlink($dump);
11}
12rmdir("./tests/dump_results/");
13?>
14--POST--
15post_a=data_post_a&post_b=data_post_b&post_c=c
16--GET--
17get_a=data_get_a&get_b=data_get_b&get_c=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaBBBB
18--COOKIE--
19cookie_a=data_cookie_a&cookie_b=data_cookie_b&data_cookie_c=cookie_c
20--ENV--
21return <<<END
22REMOTE_ADDR=127.0.0.1
23END;
24--INI--
25sp.configuration_file={PWD}/config/dump_request.ini
26--FILE--
27<?php
28echo "1\n";
29echo system("echo 1337;");
30$filename = glob('./dump_results/*.dump')[0];
31$res = file($filename);
32if ($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--
411
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--
2Empty configuration
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI--
6sp.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--
2Cookie decryption in ipv4
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/config_encrypted_cookies.ini
7--COOKIE--
8super_cookie=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEmXkk3H0xheoOMxoWPEDw1Zd8NAmD9KbB2DSjQ=%3d;awful_cookie=awful_cookie_value;
9--ENV--
10return <<<EOF
11REMOTE_ADDR=127.0.0.1
12HTTP_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
13EOF;
14--FILE--
15<?php var_dump($_COOKIE); ?>
16--EXPECT--
17array(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--
2Cookie encryption in ipv4
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/config_encrypted_cookies.ini
7--COOKIE--
8--ENV--
9return <<<EOF
10REMOTE_ADDR=127.0.0.1
11HTTP_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
12HTTPS=1
13EOF;
14--FILE--
15<?php
16setcookie("super_cookie", "super_value");
17setcookie("awful_cookie", "awful_value");
18setcookie("nice_cookie", "nice_value", 1, "1", "1", true, true);
19var_dump($_COOKIE);
20?>
21--EXPECT--
22array(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--
2Cookie decryption with ipv6
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/config_encrypted_cookies.ini
7--COOKIE--
8super_cookie=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJNTUge7MpiVNi4q3DqstbcumllXBir0CbIQiDI%3D;awful_cookie=awful_cookie_value;
9--ENV--
10return <<<EOF
11REMOTE_ADDR=2001:0db8:0000:0000:0000:fe00:0042:8329
12HTTP_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
13HTTPS=1
14EOF;
15--FILE--
16<?php var_dump($_COOKIE); ?>
17--EXPECT--
18array(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--
2Cookie encryption in ipv6
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/config_encrypted_cookies.ini
7--COOKIE--
8--ENV--
9return <<<EOF
10REMOTE_ADDR=2001:0db8:0000:0000:0000:fe00:0042:8329
11HTTP_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
12HTTPS=1
13EOF;
14--FILE--
15<?php
16setcookie("super_cookie", "super_value");
17setcookie("awful_cookie", "awful_value");
18setcookie("nice_cookie", "nice_value", 1, "1", "1", true, true);
19var_dump($_COOKIE);
20?>
21--EXPECT--
22array(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--
2Cookie encryption
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/config_encrypted_cookies.ini
7display_errors=1
8display_startup_errors=1
9error_reporting=E_ALL
10--COOKIE--
11super_cookie=jWjORGsgZyqzk3WA63XZBmUoSknXWnXDfAAAAAAAAAAAAAAAAAAAAAA7LiMDfkpP94jDnMVH%2Fm41GeL0Y00q3mbOFYz%2FS9mQGySu;awful_cookie=awful_cookie_value;
12--ENV--
13return <<<EOF
14REMOTE_ADDR=127.0.0.1
15EOF;
16--FILE--
17<?php var_dump($_COOKIE); ?>
18--EXPECT--
19
20array(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--
2Cookie encryption
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/config_encrypted_cookies.ini
7display_errors=1
8display_startup_errors=1
9error_reporting=E_ALL
10--COOKIE--
11super_cookie=1337;awful_cookie=awful_cookie_value;
12--ENV--
13return <<<EOF
14REMOTE_ADDR=127.0.0.1
15EOF;
16--FILE--
17<?php var_dump($_COOKIE); ?>
18--EXPECT--
19
20array(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--
2Cookie encryption
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/config_encrypted_cookies.ini
7--COOKIE--
8super_cookie=;awful_cookie=awful_cookie_value;
9--ENV--
10return <<<EOF
11REMOTE_ADDR=127.0.0.1
12EOF;
13--FILE--
14<?php var_dump($_COOKIE); ?>
15--EXPECT--
16array(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--
2Encryption key only
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/encryption_key_only.ini
7--FILE--
8<?php
9echo 1337;
10?>
11--EXPECT--
121337
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--
2Shipped configuration
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/../../config/examples.ini
7--FILE--
8<?php
9system("echo 0");
10?>
11--EXPECTF--
120
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--
2Global strict mode
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/global_strict.ini
7--FILE--
8<?php
9strcmp("pouet", []);
10?>
11--EXPECTF--
12Fatal error: Uncaught TypeError: strcmp() expects parameter 2 to be string, array given in %a/global_strict.php:2
13Stack 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--
2Global strict mode
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/global_strict_disabled.ini
7--FILE--
8<?php
9strcmp("pouet", []);
10echo 1337;
11?>
12--EXPECTF--
13Warning: strcmp() expects parameter 2 to be string, array given in %a/global_strict_disabled.php on line 2
141337
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--
2Harden mt_rand
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/harden_rand.ini
7--FILE--
8<?php
9mt_srand(0);
10$a = mt_rand(0,100)."\n";
11$b = mt_rand(0,100)."\n";
12mt_srand(0);
13$c = mt_rand(0,100)."\n";
14$d = mt_rand(0,100)."\n";
15
16if ($a == $c && $b == $d)
17 echo 'lose';
18else
19 echo 'win';
20?>
21--EXPECT--
22win
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--
2Harden rand
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/harden_rand.ini
7--FILE--
8<?php
9srand(0);
10$a = rand(0,100)."\n";
11$b = rand(0,100)."\n";
12srand(0);
13$c = rand(0,100)."\n";
14$d = rand(0,100)."\n";
15
16rand(100,0)."\n";
17
18if ($a == $c && $b == $d)
19 echo 'fail';
20else
21 echo 'win';
22?>
23--EXPECT--
24win
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--
2Harden rand without any arguments
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/harden_rand.ini
7We should fix this
8--FILE--
9<?php
10rand();
11mt_rand();
12
13rand(1);
14mt_rand(1);
15
16rand(1, 2);
17mt_rand(1, 2);
18
19rand(2, 1);
20mt_rand(2, 1);
21
22rand(2, 1, 0);
23mt_rand(2, 1, 0);
24
25rand("test", 1);
26mt_rand("test", 1);
27
28rand(1, "test");
29mt_rand(1, "test");
30
31rand(1, 2, "test");
32mt_rand(1, 2, "test");
33
34echo "Everything is fine\n";
35echo "Absolutely everything\n";
36echo 'Even with single quotes';
37?>
38--EXPECTF--
39Warning: rand() expects exactly 2 parameters, 1 given in %s/tests/harden_rand_noargs.php on line %d
40
41Warning: mt_rand() expects exactly 2 parameters, 1 given in %s/tests/harden_rand_noargs.php on line %d
42
43Warning: mt_rand(): max(1) is smaller than min(2) in %s/tests/harden_rand_noargs.php on line %d
44
45Warning: rand() expects exactly 2 parameters, 3 given in %s/tests/harden_rand_noargs.php on line %d
46
47Warning: mt_rand() expects exactly 2 parameters, 3 given in %s/tests/harden_rand_noargs.php on line %d
48
49Warning: rand() expects parameter 1 to be integer, string given in %s/tests/harden_rand_noargs.php on line %d
50
51Warning: mt_rand() expects parameter 1 to be integer, string given in %s/tests/harden_rand_noargs.php on line %d
52
53Warning: rand() expects parameter 2 to be integer, string given in %s/tests/harden_rand_noargs.php on line %d
54
55Warning: mt_rand() expects parameter 2 to be integer, string given in %s/tests/harden_rand_noargs.php on line %d
56
57Warning: rand() expects exactly 2 parameters, 3 given in %s/tests/harden_rand_noargs.php on line %d
58
59Warning: mt_rand() expects exactly 2 parameters, 3 given in %s/tests/harden_rand_noargs.php on line %d
60Everything is fine
61Absolutely everything
62Even 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--
2Check for snuffleupagus presence
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI--
6sp.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--
2Check for snuffleupagus presence
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--FILE--
6<?php
7echo "snuffleupagus extension is available";
8?>
9--EXPECT--
10snuffleupagus 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--
2Hooking of user-defined functions
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/config_noncore_function_hooking.ini
7--FILE--
8<?php
9function custom_fun($a) {
10 echo $a;
11}
12custom_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--
2Unserialize fail
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/config_serialize.ini
7--FILE--
8<?php
9ob_start () ;
10phpinfo () ;
11$pinfo = ob_get_contents () ;
12ob_end_clean () ;
13if (strstr($pinfo, "snuffleupagus") !== FALSE)
14 echo 1;
15else
16 echo 2;
17?>
18--EXPECT--
191
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--
2Test serialize hmac
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/config_serialize.ini
7--FILE--
8<?php
9echo serialize("a");
10?>
11--EXPECT--
12s: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--
2Set cookies.
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/config_encrypted_cookies.ini
7--COOKIE--
8--ENV--
9return <<<EOF
10REMOTE_ADDR=127.0.0.1
11HTTP_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
12HTTPS=1
13EOF;
14--FILE--
15<?php
16setcookie("name");
17setcookie("super_cookie");
18setcookie("name", "value");
19setcookie("name", "value1", 1);
20setcookie("name", "value2", 0);
21setcookie("name", "value", 1, "/super/path");
22setcookie("name", "value", 1, "/super/path", "super_domain");
23setcookie("name", "value", 1, "/super/path", "super_domain1", true);
24setcookie("name", "value", 1, "/super/path", "super_domain2", false);
25setcookie("name", "value", 1, "/super/path", "super_domain1", true, true);
26setcookie("name", "value", 1, "/super/path", "super_domain2", true, false);
27setcookie("name", "value", 1, "/super/path", "super_domain2", true, false, 1337);
28setcookie();
29echo '1337';
30?>
31--EXPECTF--
32Warning: setcookie() expects at most 7 parameters, 8 given in %a/setcookie.php on line %d
33
34Warning: setcookie() expects at least 1 parameter, 0 given in %a/setcookie.php on line %d
351337
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--
2Shipped configuration
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/../../config/default.ini
7--FILE--
8<?php
9system("echo 0");
10?>
11--EXPECTF--
120
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--
2Unserialize ok
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/config_serialize.ini
7--FILE--
8<?php
9$a=serialize("a");
10var_dump(unserialize($a));
11?>
12--EXPECT--
13string(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--
2Unserialize fail
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/config_serialize.ini
7--FILE--
8<?php
9var_dump(unserialize('s:1:"a";'));
10var_dump(unserialize('s:1:"a";alyualskdufyhalkdjsfhalkjdhflaksjdfhlkasdhflkahdawkuerylksjdfhlkssjgdflaksjdhflkasjdf'));
11var_dump(unserialize('s:1:"a";dslfjklfjfkjfdjffjfjads'));
12var_dump(unserialize(1,2,3,4));
13?>
14--EXPECTF--
15[snuffleupagus][0.0.0.0][unserialize][drop] The serialized object is too small.
16bool(false)
17[snuffleupagus][0.0.0.0][unserialize][drop] Invalid HMAC for s:1:"a";alyualskdufyhalkdjsfh
18NULL
19[snuffleupagus][0.0.0.0][unserialize][drop] The serialized object is too small.
20bool(false)
21
22Warning: unserialize() expects at most 2 parameters, 4 given in %a/tests/unserialize_fail.php on line %d
23bool(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--
2Unserialize ok
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/config_serialize_sim.ini
7--FILE--
8<?php
9$a=serialize("a");
10echo $a;
11var_dump(unserialize($a));
12var_dump(unserialize('s:1:"a";alyualskdufyhalkdjsfhalkjdhflaksjdfhlkasdhflkahdawkuerylksjdfhlkssjgdflaksjdh1337sjdf'));
13?>
14--EXPECT--
15s:1:"a";650609b417904d0d9bbf1fc44a975d13ecdf6b02b715c1a06271fb3b673f25b1string(1) "a"
16[snuffleupagus][0.0.0.0][unserialize][notice] Invalid HMAC for s:1:"a";alyualskdufyhalkdjsfh
17string(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--
2Upload a file, validation ok, no simulation
3--INI--
4file_uploads=1
5sp.configuration_file={PWD}/config/upload_validation.ini
6--POST_RAW--
7Content-Type: multipart/form-data; boundary=blabla
8--blabla
9Content-Disposition: form-data; name="test"; filename="test.php"
10--blabla--
11--FILE--
12<?php
13echo 1;
14?>
15--EXPECTF--
161
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--
2Upload a file, invalid validation script
3--INI--
4file_uploads=1
5sp.configuration_file={PWD}/config/upload_validation_invalid.ini
6--POST_RAW--
7Content-Type: multipart/form-data; boundary=blabla
8--blabla
9Content-Disposition: form-data; name="test"; filename="test.php"
10--blabla--
11--FILE--
12<?php
13echo 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--
2Upload a file, validation ko, no simulation
3--INI--
4file_uploads=1
5sp.configuration_file={PWD}/config/upload_validation_ko.ini
6output_buffering=off
7--POST_RAW--
8Content-Type: multipart/form-data; boundary=blabla
9--blabla
10Content-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--
2Upload a file, validation script not executable
3--INI--
4file_uploads=1
5sp.configuration_file={PWD}/config/upload_validation_non_exec.ini
6output_buffering=off
7--POST_RAW--
8Content-Type: multipart/form-data; boundary=blabla
9--blabla
10Content-Disposition: form-data; name="test"; filename="test.php"
11--blabla--
12--FILE--
13<?php
14var_dump($_FILES);
15echo "\n\n\n\n\n\n\n\n\n\n\n\n\n\n";
16?>
17--EXPECTF--
18array(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--
2Upload validation isn't crashing
3--INI--
4file_uploads=1
5sp.configuration_file={PWD}/config/upload_validation_ok.ini
6output_buffering=off
7--FILE--
8<?php
9echo 1;
10?>
11--EXPECTF--
121
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--
2Upload a file, validation ok, no simulation
3--INI--
4file_uploads=1
5sp.configuration_file={PWD}/config/upload_validation_ok.ini
6output_buffering=off
7--POST_RAW--
8Content-Type: multipart/form-data; boundary=blabla
9--blabla
10Content-Disposition: form-data; name="test"; filename="test.php"
11--blabla--
12--FILE--
13<?php
14echo 1;
15?>
16--EXPECTF--
171
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
5typedef unsigned char u8;
6typedef unsigned long u32;
7typedef unsigned long long u64;
8typedef long long i64;
9typedef i64 gf[16];
10
11
12/* it's really stupid that there isn't a syscall for this */
13
14static int fd = -1;
15
16void 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
43static const u8
44 _0[16],
45 _9[32] = {9};
46static 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
56static u32 L32(u32 x,int c) { return (x << c) | ((x&0xffffffff) >> (32 - c)); }
57
58static 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
66static 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
73sv st32(u8 *x,u32 u)
74{
75 int i;
76 FOR(i,4) { x[i] = u; u >>= 8; }
77}
78
79sv ts64(u8 *x,u64 u)
80{
81 int i;
82 for (i = 7;i >= 0;--i) { x[i] = u; u >>= 8; }
83}
84
85static 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
93int crypto_verify_16(const u8 *x,const u8 *y)
94{
95 return vn(x,y,16);
96}
97
98int crypto_verify_32(const u8 *x,const u8 *y)
99{
100 return vn(x,y,32);
101}
102
103sv 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
143int 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
149int 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
155static const u8 sigma[16] = "expand 32-byte k";
156
157int 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
184int 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
189int 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
196int 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
203sv 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
213static const u32 minusp[17] = {
214 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 252
215} ;
216
217int 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
270int 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
277int 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
287int 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
299sv set25519(gf r, const gf a)
300{
301 int i;
302 FOR(i,16) r[i]=a[i];
303}
304
305sv 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
317sv 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
327sv 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
352static 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
360static u8 par25519(const gf a)
361{
362 u8 d[32];
363 pack25519(d,a);
364 return d[0]&1;
365}
366
367sv 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
374sv 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
380sv 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
386sv 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
397sv S(gf o,const gf a)
398{
399 M(o,a,a);
400}
401
402sv 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
414sv 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
426int 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
477int crypto_scalarmult_base(u8 *q,const u8 *n)
478{
479 return crypto_scalarmult(q,n,_9);
480}
481
482int crypto_box_keypair(u8 *y,u8 *x)
483{
484 randombytes(x,32);
485 return crypto_scalarmult_base(y,x);
486}
487
488int 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
495int 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
500int 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
505int 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
512int 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
519static u64 R(u64 x,int c) { return (x >> c) | (x << (64 - c)); }
520static u64 Ch(u64 x,u64 y,u64 z) { return (x & y) ^ (~x & z); }
521static u64 Maj(u64 x,u64 y,u64 z) { return (x & y) ^ (x & z) ^ (y & z); }
522static u64 Sigma0(u64 x) { return R(x,28) ^ R(x,34) ^ R(x,39); }
523static u64 Sigma1(u64 x) { return R(x,14) ^ R(x,18) ^ R(x,41); }
524static u64 sigma0(u64 x) { return R(x, 1) ^ R(x, 8) ^ (x >> 7); }
525static u64 sigma1(u64 x) { return R(x,19) ^ R(x,61) ^ (x >> 6); }
526
527static 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
551int 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
583static 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
594int 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
620sv 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
645sv 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
652sv 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
662sv 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
678sv 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
688int 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
707static 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
709sv 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
735sv 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
743int 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
776static 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
812int 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
17extern int crypto_auth_hmacsha512256_tweet(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *);
18extern 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
47extern int crypto_box_curve25519xsalsa20poly1305_tweet(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *,const unsigned char *);
48extern int crypto_box_curve25519xsalsa20poly1305_tweet_open(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *,const unsigned char *);
49extern int crypto_box_curve25519xsalsa20poly1305_tweet_keypair(unsigned char *,unsigned char *);
50extern int crypto_box_curve25519xsalsa20poly1305_tweet_beforenm(unsigned char *,const unsigned char *,const unsigned char *);
51extern int crypto_box_curve25519xsalsa20poly1305_tweet_afternm(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *);
52extern 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
80extern 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
93extern 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
110extern 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
119extern 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
132extern 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
139extern 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
154extern int crypto_onetimeauth_poly1305_tweet(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *);
155extern 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
172extern int crypto_scalarmult_curve25519_tweet(unsigned char *,const unsigned char *,const unsigned char *);
173extern 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
194extern int crypto_secretbox_xsalsa20poly1305_tweet(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *);
195extern 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
217extern int crypto_sign_ed25519_tweet(unsigned char *,unsigned long long *,const unsigned char *,unsigned long long,const unsigned char *);
218extern int crypto_sign_ed25519_tweet_open(unsigned char *,unsigned long long *,const unsigned char *,unsigned long long,const unsigned char *);
219extern 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
238extern int crypto_stream_xsalsa20_tweet(unsigned char *,unsigned long long,const unsigned char *,const unsigned char *);
239extern 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
249extern int crypto_stream_salsa20_tweet(unsigned char *,unsigned long long,const unsigned char *,const unsigned char *);
250extern 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
264extern 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
271extern 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