summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxXx-caillou-xXx2017-12-20 18:09:53 +0100
committerjvoisin2017-12-20 18:09:53 +0100
commite7f541396715ee2895abcf73044b91ae9b746201 (patch)
treeba0e9765e7f14f04b92585df1f3fcd1830ab4b00
parent8d6cc4f2b63c3f0dc31fe6cecd34ac023ea1cccb (diff)
Better parsing of the rules
Thanks to this huge commit from @xXx-caillou-xXx, we can now write amazingly flexible rules.
-rw-r--r--doc/source/config.rst16
-rw-r--r--src/config.m42
-rw-r--r--src/php_snuffleupagus.h1
-rw-r--r--src/sp_config.c4
-rw-r--r--src/sp_config.h9
-rw-r--r--src/sp_config_keywords.c45
-rw-r--r--src/sp_config_utils.c44
-rw-r--r--src/sp_cookie_encryption.c4
-rw-r--r--src/sp_disabled_functions.c138
-rw-r--r--src/sp_list.c28
-rw-r--r--src/sp_list.h1
-rw-r--r--src/sp_tree.c20
-rw-r--r--src/sp_upload_validation.c4
-rw-r--r--src/sp_utils.c84
-rw-r--r--src/sp_utils.h6
-rw-r--r--src/sp_var_parser.c247
-rw-r--r--src/sp_var_parser.h51
-rw-r--r--src/sp_var_value.c226
-rw-r--r--src/tests/broken_conf_key_value.phpt9
-rw-r--r--src/tests/broken_conf_local_var_1.phpt10
-rw-r--r--src/tests/broken_conf_local_var_10.phpt10
-rw-r--r--src/tests/broken_conf_local_var_11.phpt10
-rw-r--r--src/tests/broken_conf_local_var_12.phpt9
-rw-r--r--src/tests/broken_conf_local_var_13.phpt10
-rw-r--r--src/tests/broken_conf_local_var_14.phpt10
-rw-r--r--src/tests/broken_conf_local_var_2.phpt10
-rw-r--r--src/tests/broken_conf_local_var_3.phpt10
-rw-r--r--src/tests/broken_conf_local_var_4.phpt10
-rw-r--r--src/tests/broken_conf_local_var_5.phpt10
-rw-r--r--src/tests/broken_conf_local_var_6.phpt10
-rw-r--r--src/tests/broken_conf_local_var_7.phpt10
-rw-r--r--src/tests/broken_conf_local_var_8.phpt10
-rw-r--r--src/tests/broken_conf_local_var_9.phpt10
-rw-r--r--src/tests/config/broken_conf_key_value.ini1
-rw-r--r--src/tests/config/broken_conf_local_var_1.ini1
-rw-r--r--src/tests/config/broken_conf_local_var_10.ini1
-rw-r--r--src/tests/config/broken_conf_local_var_11.ini1
-rw-r--r--src/tests/config/broken_conf_local_var_12.ini1
-rw-r--r--src/tests/config/broken_conf_local_var_13.ini1
-rw-r--r--src/tests/config/broken_conf_local_var_14.ini1
-rw-r--r--src/tests/config/broken_conf_local_var_2.ini1
-rw-r--r--src/tests/config/broken_conf_local_var_3.ini1
-rw-r--r--src/tests/config/broken_conf_local_var_4.ini1
-rw-r--r--src/tests/config/broken_conf_local_var_5.ini1
-rw-r--r--src/tests/config/broken_conf_local_var_6.ini1
-rw-r--r--src/tests/config/broken_conf_local_var_7.ini1
-rw-r--r--src/tests/config/broken_conf_local_var_8.ini1
-rw-r--r--src/tests/config/broken_conf_local_var_9.ini1
-rw-r--r--src/tests/config/config_disabled_functions_local_var_array.ini1
-rw-r--r--src/tests/config/config_disabled_functions_local_var_array_key.ini1
-rw-r--r--src/tests/config/config_disabled_functions_name_type.ini2
-rw-r--r--src/tests/config/config_disabled_functions_nul_byte.ini2
-rw-r--r--src/tests/config/config_disabled_functions_param.ini12
-rw-r--r--src/tests/config/config_disabled_functions_param_allow.ini4
-rw-r--r--src/tests/config/config_disabled_functions_param_array.ini11
-rw-r--r--src/tests/config/config_disabled_functions_param_int.ini4
-rw-r--r--src/tests/config/config_disabled_functions_param_r_array.ini2
-rw-r--r--src/tests/config/config_disabled_functions_param_runtime.ini2
-rw-r--r--src/tests/config/disabled_function_local_var.ini12
-rw-r--r--src/tests/config/disabled_function_local_var_2.ini1
-rw-r--r--src/tests/config/disabled_function_local_var_obj.ini3
-rw-r--r--src/tests/config/disabled_function_super_global_var.ini2
-rw-r--r--src/tests/config/disabled_functions_pos.ini1
-rw-r--r--src/tests/disabled_function_local_var_10.phpt44
-rw-r--r--src/tests/disabled_function_local_var_2.phpt46
-rw-r--r--src/tests/disabled_function_local_var_3.phpt45
-rw-r--r--src/tests/disabled_function_local_var_4.phpt56
-rw-r--r--src/tests/disabled_function_local_var_5.phpt33
-rw-r--r--src/tests/disabled_function_local_var_6.phpt31
-rw-r--r--src/tests/disabled_function_local_var_7.phpt31
-rw-r--r--src/tests/disabled_function_local_var_8.phpt20
-rw-r--r--src/tests/disabled_function_local_var_9.phpt20
-rw-r--r--src/tests/disabled_function_local_var_obj.phpt25
-rw-r--r--src/tests/disabled_functions_local_var_array.phpt20
-rw-r--r--src/tests/disabled_functions_local_var_array_key.phpt20
-rw-r--r--src/tests/disabled_functions_name_type.phpt2
-rw-r--r--src/tests/disabled_functions_nul_byte.phpt2
-rw-r--r--src/tests/disabled_functions_param.phpt2
-rw-r--r--src/tests/disabled_functions_param_array.phpt2
-rw-r--r--src/tests/disabled_functions_param_array_deref.phpt2
-rw-r--r--src/tests/disabled_functions_param_array_no_value.phpt2
-rw-r--r--src/tests/disabled_functions_param_array_r.phpt20
-rw-r--r--src/tests/disabled_functions_param_array_r_keys.phpt20
-rw-r--r--src/tests/disabled_functions_param_array_several_levels.phpt2
-rw-r--r--src/tests/disabled_functions_param_array_several_levels_int.phpt20
-rw-r--r--src/tests/disabled_functions_param_array_several_levels_keys.phpt20
-rw-r--r--src/tests/disabled_functions_param_array_several_levels_keys_int.phpt20
-rw-r--r--src/tests/disabled_functions_param_int.phpt2
-rw-r--r--src/tests/disabled_functions_pos_type.phpt14
-rw-r--r--src/tests/disabled_functions_runtime.phpt2
90 files changed, 1449 insertions, 227 deletions
diff --git a/doc/source/config.rst b/doc/source/config.rst
index 41863c8..ceb23bb 100644
--- a/doc/source/config.rst
+++ b/doc/source/config.rst
@@ -255,7 +255,7 @@ In the situation where you have a call to ``system()`` that lacks proper user-in
255:: 255::
256 256
257 # Allow `id.php` to restrict system() calls to `id` 257 # Allow `id.php` to restrict system() calls to `id`
258 sp.disable_function.function("system").filename("id.php").param("cmd").value("id").allow(); 258 sp.disable_function.function("system").filename("id.php").param("$cmd").value("id").allow();
259 sp.disable_function.function("system").filename("id.php").drop() 259 sp.disable_function.function("system").filename("id.php").drop()
260 260
261Of course, this is a trivial example, a lot can be achieved with this feature, as you will see below. 261Of course, this is a trivial example, a lot can be achieved with this feature, as you will see below.
@@ -281,6 +281,8 @@ Filters
281- ``value(value)``: match on a literal ``value`` 281- ``value(value)``: match on a literal ``value``
282- ``value_r(regexp)``: match on a value matching the ``regexp`` 282- ``value_r(regexp)``: match on a value matching the ``regexp``
283- ``var(name)``: match on a **local variable** ``name`` 283- ``var(name)``: match on a **local variable** ``name``
284- ``key(name)``: match on the presence of ``name`` as a key in the hashtable
285- ``key_r(regexp)``: match with ``regexp`` on keys in the hashtable
284 286
285The ``type`` must be one of the following values: 287The ``type`` must be one of the following values:
286 288
@@ -312,11 +314,11 @@ The ``function`` filter is able to do various dereferencing:
312 314
313The ``param`` filter is also able to do some dereferencing: 315The ``param`` filter is also able to do some dereferencing:
314 316
315- ``param(foo[bar])`` will get a match on the value corresponding to the ``bar`` key in the hashtable ``foo``. 317- ``param($foo[bar])`` will get a match on the value corresponding to the ``bar`` key in the hashtable ``foo``.
316 Remember that in PHP, almost every data structure is a hashtable. You can of course nest this like 318 Remember that in PHP, almost every data structure is a hashtable. You can of course nest this like
317 ``param(foo[bar][baz][batman])``. 319 ``param($foo[bar][$object->array['123']][$batman])``.
318- The ``var`` filter will walk the calltrace until it finds the variable name, or the end of the calltrace, 320- The ``var`` filter will walk the calltrace until it finds the variable name, or the end of the calltrace,
319 allowing the filter to match global variables: ``.var("_GET[param]")`` will match on the GET parameter ``param``. 321 allowing the filter to match global variables: ``.var("$_GET[\"param\"]")`` will match on the GET parameter ``param``.
320 322
321The ``filename`` filter requires a leading ``/``, since paths are absolutes (like ``/var/www/mywebsite/lib/parse.php``). 323The ``filename`` filter requires a leading ``/``, since paths are absolutes (like ``/var/www/mywebsite/lib/parse.php``).
322If you would like to have only one configuration file for several vhost in different folders, 324If you would like to have only one configuration file for several vhost in different folders,
@@ -351,9 +353,9 @@ The following rules will:
351 353
352:: 354::
353 355
354 sp.disable_function.function("system").param("cmd").value("id").allow(); 356 sp.disable_function.function("system").param("$cmd").value("id").allow();
355 sp.disable_function.function("system").param("cmd").value_r("^ping").drop().simulation(); 357 sp.disable_function.function("system").param("$cmd").value_r("^ping").drop().simulation();
356 sp.disable_function.function("system").param("cmd").drop(); 358 sp.disable_function.function("system").param("$cmd").drop();
357 359
358Miscellaneous examples 360Miscellaneous examples
359"""""""""""""""""""""" 361""""""""""""""""""""""
diff --git a/src/config.m4 b/src/config.m4
index 8fa22c5..b2c6ed5 100644
--- a/src/config.m4
+++ b/src/config.m4
@@ -5,7 +5,7 @@ sources="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" 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" 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" 7sources="$sources sp_cookie_encryption.c sp_network_utils.c tweetnacl.c"
8sources="$sources sp_config_keywords.c" 8sources="$sources sp_config_keywords.c sp_var_parser.c sp_var_value.c sp_tree.c"
9 9
10PHP_ARG_ENABLE(snuffleupagus, whether to enable snuffleupagus support, 10PHP_ARG_ENABLE(snuffleupagus, whether to enable snuffleupagus support,
11[ --enable-snuffleupagus Enable snuffleupagus support]) 11[ --enable-snuffleupagus Enable snuffleupagus support])
diff --git a/src/php_snuffleupagus.h b/src/php_snuffleupagus.h
index 2ad412d..bccf998 100644
--- a/src/php_snuffleupagus.h
+++ b/src/php_snuffleupagus.h
@@ -26,6 +26,7 @@
26#include "zend_extensions.h" 26#include "zend_extensions.h"
27 27
28#include "sp_list.h" 28#include "sp_list.h"
29#include "sp_var_parser.h"
29#include "sp_config.h" 30#include "sp_config.h"
30#include "sp_config_utils.h" 31#include "sp_config_utils.h"
31#include "sp_config_keywords.h" 32#include "sp_config_keywords.h"
diff --git a/src/sp_config.c b/src/sp_config.c
index 2432cc4..bed81bc 100644
--- a/src/sp_config.c
+++ b/src/sp_config.c
@@ -189,6 +189,10 @@ void sp_disabled_function_list_free(sp_node_t* list) {
189 sp_disabled_function* df = cursor->data; 189 sp_disabled_function* df = cursor->data;
190 if (df && df->functions_list) 190 if (df && df->functions_list)
191 sp_list_free(df->functions_list); 191 sp_list_free(df->functions_list);
192 if (df) {
193 sp_tree_free(df->param);
194 sp_tree_free(df->var);
195 }
192 cursor = cursor->next; 196 cursor = cursor->next;
193 } 197 }
194} 198}
diff --git a/src/sp_config.h b/src/sp_config.h
index 8ef62a2..127c557 100644
--- a/src/sp_config.h
+++ b/src/sp_config.h
@@ -78,7 +78,7 @@ typedef struct {
78 char *hash; 78 char *hash;
79 int simulation; 79 int simulation;
80 80
81 char *param; 81 sp_tree *param;
82 pcre *r_param; 82 pcre *r_param;
83 sp_php_type param_type; 83 sp_php_type param_type;
84 int pos; 84 int pos;
@@ -91,6 +91,9 @@ typedef struct {
91 pcre *value_r; 91 pcre *value_r;
92 char *value; 92 char *value;
93 93
94 pcre *r_key;
95 char *key;
96
94 char *dump; 97 char *dump;
95 char *alias; 98 char *alias;
96 bool param_is_array; 99 bool param_is_array;
@@ -100,7 +103,7 @@ typedef struct {
100 103
101 bool allow; 104 bool allow;
102 105
103 char *var; 106 sp_tree *var;
104 107
105 sp_cidr *cidr; 108 sp_cidr *cidr;
106} sp_disabled_function; 109} sp_disabled_function;
@@ -193,6 +196,8 @@ typedef struct {
193#define SP_TOKEN_RET_TYPE ".ret_type(" 196#define SP_TOKEN_RET_TYPE ".ret_type("
194#define SP_TOKEN_VALUE ".value(" 197#define SP_TOKEN_VALUE ".value("
195#define SP_TOKEN_VALUE_REGEXP ".value_r(" 198#define SP_TOKEN_VALUE_REGEXP ".value_r("
199#define SP_TOKEN_KEY ".key("
200#define SP_TOKEN_KEY_REGEXP ".key_r("
196#define SP_TOKEN_VALUE_ARG_POS ".pos(" 201#define SP_TOKEN_VALUE_ARG_POS ".pos("
197#define SP_TOKEN_LINE_NUMBER ".line(" 202#define SP_TOKEN_LINE_NUMBER ".line("
198 203
diff --git a/src/sp_config_keywords.c b/src/sp_config_keywords.c
index dd9a880..2d294ee 100644
--- a/src/sp_config_keywords.c
+++ b/src/sp_config_keywords.c
@@ -178,7 +178,7 @@ int parse_cookie(char *line) {
178int parse_disabled_functions(char *line) { 178int parse_disabled_functions(char *line) {
179 int ret = 0; 179 int ret = 0;
180 bool enable = true, disable = false, allow = false, drop = false; 180 bool enable = true, disable = false, allow = false, drop = false;
181 char *pos = NULL; 181 char *pos = NULL, *var = NULL, *param = NULL;
182 char *line_number = NULL; 182 char *line_number = NULL;
183 sp_disabled_function *df = pecalloc(sizeof(*df), 1, 1); 183 sp_disabled_function *df = pecalloc(sizeof(*df), 1, 1);
184 df->pos = -1; 184 df->pos = -1;
@@ -196,16 +196,18 @@ int parse_disabled_functions(char *line) {
196 {parse_empty, SP_TOKEN_ALLOW, &(allow)}, 196 {parse_empty, SP_TOKEN_ALLOW, &(allow)},
197 {parse_empty, SP_TOKEN_DROP, &(drop)}, 197 {parse_empty, SP_TOKEN_DROP, &(drop)},
198 {parse_str, SP_TOKEN_HASH, &(df->hash)}, 198 {parse_str, SP_TOKEN_HASH, &(df->hash)},
199 {parse_str, SP_TOKEN_PARAM, &(df->param)}, 199 {parse_str, SP_TOKEN_PARAM, &(param)},
200 {parse_regexp, SP_TOKEN_VALUE_REGEXP, &(df->value_r)}, 200 {parse_regexp, SP_TOKEN_VALUE_REGEXP, &(df->value_r)},
201 {parse_str, SP_TOKEN_VALUE, &(df->value)}, 201 {parse_str, SP_TOKEN_VALUE, &(df->value)},
202 {parse_str, SP_TOKEN_KEY, &(df->key)},
203 {parse_regexp, SP_TOKEN_KEY_REGEXP, &(df->r_key)},
202 {parse_regexp, SP_TOKEN_PARAM_REGEXP, &(df->r_param)}, 204 {parse_regexp, SP_TOKEN_PARAM_REGEXP, &(df->r_param)},
203 {parse_php_type, SP_TOKEN_PARAM_TYPE, &(df->param_type)}, 205 {parse_php_type, SP_TOKEN_PARAM_TYPE, &(df->param_type)},
204 {parse_str, SP_TOKEN_RET, &(df->ret)}, 206 {parse_str, SP_TOKEN_RET, &(df->ret)},
205 {parse_cidr, SP_TOKEN_CIDR, &(df->cidr)}, 207 {parse_cidr, SP_TOKEN_CIDR, &(df->cidr)},
206 {parse_regexp, SP_TOKEN_RET_REGEXP, &(df->r_ret)}, 208 {parse_regexp, SP_TOKEN_RET_REGEXP, &(df->r_ret)},
207 {parse_php_type, SP_TOKEN_RET_TYPE, &(df->ret_type)}, 209 {parse_php_type, SP_TOKEN_RET_TYPE, &(df->ret_type)},
208 {parse_str, SP_TOKEN_LOCAL_VAR, &(df->var)}, 210 {parse_str, SP_TOKEN_LOCAL_VAR, &(var)},
209 {parse_str, SP_TOKEN_VALUE_ARG_POS, &(pos)}, 211 {parse_str, SP_TOKEN_VALUE_ARG_POS, &(pos)},
210 {parse_str, SP_TOKEN_LINE_NUMBER, &(line_number)}, 212 {parse_str, SP_TOKEN_LINE_NUMBER, &(line_number)},
211 {0}}; 213 {0}};
@@ -229,9 +231,10 @@ int parse_disabled_functions(char *line) {
229 MUTUALLY_EXCLUSIVE(df->r_function, df->function, "r_function", "function"); 231 MUTUALLY_EXCLUSIVE(df->r_function, df->function, "r_function", "function");
230 MUTUALLY_EXCLUSIVE(df->filename, df->r_filename, "r_filename", "filename"); 232 MUTUALLY_EXCLUSIVE(df->filename, df->r_filename, "r_filename", "filename");
231 MUTUALLY_EXCLUSIVE(df->ret, df->r_ret, "r_ret", "ret"); 233 MUTUALLY_EXCLUSIVE(df->ret, df->r_ret, "r_ret", "ret");
234 MUTUALLY_EXCLUSIVE(df->key, df->r_key, "r_key", "key");
232#undef MUTUALLY_EXCLUSIVE 235#undef MUTUALLY_EXCLUSIVE
233 236
234 if (1 < ((df->r_param ? 1 : 0) + (df->param ? 1 : 0) + 237 if (1 < ((df->r_param ? 1 : 0) + (param ? 1 : 0) +
235 ((-1 != df->pos) ? 1 : 0))) { 238 ((-1 != df->pos) ? 1 : 0))) {
236 sp_log_err( 239 sp_log_err(
237 "config", 240 "config",
@@ -239,7 +242,13 @@ int parse_disabled_functions(char *line) {
239 "'.r_param', '.param' and '.pos' are mutually exclusive on line %zu.", 242 "'.r_param', '.param' and '.pos' are mutually exclusive on line %zu.",
240 line, sp_line_no); 243 line, sp_line_no);
241 return -1; 244 return -1;
242 } else if ((df->r_ret || df->ret) && (df->r_param || df->param)) { 245 } else if ((df->r_key || df->key) && (df->value_r || df->value)) {
246 sp_log_err("config",
247 "Invalid configuration line: 'sp.disabled_functions%s':"
248 "`key` and `value` are mutually exclusive on line %zu.",
249 line, sp_line_no);
250 return -1;
251 } else if ((df->r_ret || df->ret) && (df->r_param || param)) {
243 sp_log_err("config", 252 sp_log_err("config",
244 "Invalid configuration line: 'sp.disabled_functions%s':" 253 "Invalid configuration line: 'sp.disabled_functions%s':"
245 "`ret` and `param` are mutually exclusive on line %zu.", 254 "`ret` and `param` are mutually exclusive on line %zu.",
@@ -293,22 +302,28 @@ int parse_disabled_functions(char *line) {
293 df->functions_list = parse_functions_list(df->function); 302 df->functions_list = parse_functions_list(df->function);
294 } 303 }
295 304
296 if (df->param && strchr(df->param, '[')) { // assume that this is an array 305 if (param) {
297 df->param_array_keys = sp_list_new(); 306 df->param = parse_var(param);
298 if (0 != array_to_list(&df->param, &df->param_array_keys)) { 307 if (!df->param) {
299 pefree(df->param_array_keys, 1); 308 sp_log_err("config", "Invalid value '%s' for `param` on line %zu.",
309 param, sp_line_no);
300 return -1; 310 return -1;
301 } 311 }
302 df->param_is_array = 1;
303 } 312 }
304 313
305 if (df->var && strchr(df->var, '[')) { // assume that this is an array 314 if (var) {
306 df->var_array_keys = sp_list_new(); 315 if (*var) {
307 if (0 != array_to_list(&df->var, &df->var_array_keys)) { 316 df->var = parse_var(var);
308 pefree(df->var_array_keys, 1); 317 if (!df->var) {
318 sp_log_err("config", "Invalid value '%s' for `var` on line %zu.",
319 var, sp_line_no);
320 return -1;
321 }
322 } else {
323 sp_log_err("config", "Empty value in `var` on line %zu.",
324 sp_line_no);
309 return -1; 325 return -1;
310 } 326 }
311 df->var_is_array = 1;
312 } 327 }
313 328
314 switch (get_construct_type(df)) { 329 switch (get_construct_type(df)) {
diff --git a/src/sp_config_utils.c b/src/sp_config_utils.c
index 1a797e5..ddd2e05 100644
--- a/src/sp_config_utils.c
+++ b/src/sp_config_utils.c
@@ -133,50 +133,6 @@ char *get_param(size_t *consumed, char *restrict line, sp_type type,
133 return NULL; 133 return NULL;
134} 134}
135 135
136// FIXME this is leaking like hell @blotus
137int array_to_list(char **name_ptr, sp_node_t **keys) {
138 int in_key = 0;
139 size_t i = 0;
140 char *name = *name_ptr;
141 char *key_name = ecalloc(strlen(name) + 1, 1); // im way too lazy for
142 // now
143 char *tmp = ecalloc(strlen(name) + 1, 1);
144
145 for (i = 0; name[i] != '['; i++) {
146 tmp[i] = name[i];
147 }
148 tmp[i] = 0;
149
150 for (size_t j = 0; name[i]; i++) {
151 const char c = name[i];
152 if (c == '[') {
153 if (in_key == 0) {
154 in_key = 1;
155 } else {
156 efree(key_name);
157 return -1;
158 }
159 } else if (c == ']') {
160 if (in_key == 0) {
161 efree(key_name);
162 return -1;
163 } else {
164 in_key = 0;
165 j = 0;
166 sp_list_insert(*keys, pestrdup(key_name, 1));
167 memset(key_name, 0, strlen(name) + 1);
168 }
169 } else if (in_key == 1) {
170 key_name[j] = c;
171 j++;
172 }
173 }
174 efree(key_name);
175 *name_ptr = pestrdup(tmp, 1);
176 return in_key;
177}
178
179
180zend_always_inline sp_node_t *parse_functions_list(char *value) { 136zend_always_inline sp_node_t *parse_functions_list(char *value) {
181 const char *sep = ">"; 137 const char *sep = ">";
182 138
diff --git a/src/sp_cookie_encryption.c b/src/sp_cookie_encryption.c
index b7050da..c749040 100644
--- a/src/sp_cookie_encryption.c
+++ b/src/sp_cookie_encryption.c
@@ -8,9 +8,9 @@ static zend_long nonce_d = 0;
8 8
9static inline void generate_key(unsigned char *key) { 9static inline void generate_key(unsigned char *key) {
10 PHP_SHA256_CTX ctx; 10 PHP_SHA256_CTX ctx;
11 const char *user_agent = sp_getenv("HTTP_USER_AGENT"); 11 const char *user_agent = getenv("HTTP_USER_AGENT");
12 const char *env_var = 12 const char *env_var =
13 sp_getenv(SNUFFLEUPAGUS_G(config).config_snuffleupagus->cookies_env_var); 13 getenv(SNUFFLEUPAGUS_G(config).config_snuffleupagus->cookies_env_var);
14 const char *encryption_key = 14 const char *encryption_key =
15 SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key; 15 SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key;
16 16
diff --git a/src/sp_disabled_functions.c b/src/sp_disabled_functions.c
index 6c180aa..c7974ff 100644
--- a/src/sp_disabled_functions.c
+++ b/src/sp_disabled_functions.c
@@ -64,43 +64,30 @@ end:
64static bool is_local_var_matching( 64static bool is_local_var_matching(
65 zend_execute_data* execute_data, 65 zend_execute_data* execute_data,
66 const sp_disabled_function* const config_node) { 66 const sp_disabled_function* const config_node) {
67 zend_execute_data* orig_execute_data = execute_data; 67 zval *var_value;
68 68
69 /*because execute_data points to hooked function data, 69 var_value = get_value(execute_data, config_node->var, false);
70 which we dont care about */ 70 if (var_value) {
71 zend_execute_data* current = execute_data->prev_execute_data; 71 char *var_value_str = sp_convert_to_string(var_value);
72 zval* value = NULL; 72 if (Z_TYPE_P(var_value) == IS_ARRAY) {
73 73 if (config_node->key || config_node->r_key) {
74 while (current) { 74 if (sp_match_array_key(var_value, config_node->key,
75 zend_string* key = NULL; 75 config_node->r_key)) {
76 EG(current_execute_data) = current; 76 efree(var_value_str);
77 zend_array* symtable = zend_rebuild_symbol_table(); 77 return true;
78 ZEND_HASH_FOREACH_STR_KEY_VAL(symtable, key, value) { 78 }
79 if (0 == strcmp(config_node->var, key->val)) { // is the var name right? 79 } else if (sp_match_array_value(var_value, config_node->value,
80 if (Z_TYPE_P(value) == IS_INDIRECT) { 80 config_node->value_r)) {
81 value = Z_INDIRECT_P(value); 81 efree(var_value_str);
82 } 82 return true;
83 if (Z_TYPE_P(value) != IS_ARRAY) {
84 char* var_value_str = sp_convert_to_string(value);
85 if (true == sp_match_value(var_value_str, config_node->value,
86 config_node->value_r)) {
87 efree(var_value_str);
88 EG(current_execute_data) = orig_execute_data;
89 return true;
90 }
91 efree(var_value_str);
92 } else {
93 EG(current_execute_data) = orig_execute_data;
94 return sp_match_array_key_recurse(value, config_node->var_array_keys,
95 config_node->value, NULL);
96 }
97 } 83 }
84 } else if (sp_match_value(var_value_str, config_node->value,
85 config_node->value_r)) {
86 efree(var_value_str);
87 return true;
98 } 88 }
99 ZEND_HASH_FOREACH_END(); 89 efree(var_value_str);
100 current = current->prev_execute_data;
101 } 90 }
102
103 EG(current_execute_data) = orig_execute_data;
104 return false; 91 return false;
105} 92}
106 93
@@ -128,6 +115,7 @@ static bool is_param_matching(zend_execute_data* execute_data,
128 const char** arg_value_str) { 115 const char** arg_value_str) {
129 int nb_param = execute_data->func->common.num_args; 116 int nb_param = execute_data->func->common.num_args;
130 int i = 0; 117 int i = 0;
118 zval *arg_value;
131 119
132 if (config_node->pos != -1) { 120 if (config_node->pos != -1) {
133 if (config_node->pos <= nb_param) { 121 if (config_node->pos <= nb_param) {
@@ -154,7 +142,7 @@ static bool is_param_matching(zend_execute_data* execute_data,
154 *arg_value_str = builtin_param; 142 *arg_value_str = builtin_param;
155 return sp_match_value(builtin_param, config_node->value, 143 return sp_match_value(builtin_param, config_node->value,
156 config_node->value_r); 144 config_node->value_r);
157 } else { 145 } else if (config_node->r_param || config_node->pos != -1) {
158 // We're matching on a function (and not a language construct) 146 // We're matching on a function (and not a language construct)
159 for (; i < nb_param; i++) { 147 for (; i < nb_param; i++) {
160 if (ZEND_USER_CODE(execute_data->func->type)) { // yay consistency 148 if (ZEND_USER_CODE(execute_data->func->type)) { // yay consistency
@@ -162,49 +150,63 @@ static bool is_param_matching(zend_execute_data* execute_data,
162 } else { 150 } else {
163 *arg_name = execute_data->func->internal_function.arg_info[i].name; 151 *arg_name = execute_data->func->internal_function.arg_info[i].name;
164 } 152 }
165 153 const bool pcre_matching = config_node->r_param
166 const bool arg_matching = 154 && (true == is_regexp_matching(config_node->r_param, *arg_name));
167 config_node->param && (0 == strcmp(*arg_name, config_node->param));
168 const bool pcre_matching =
169 config_node->r_param &&
170 (true == is_regexp_matching(config_node->r_param, *arg_name));
171 155
172 /* This is the parameter name we're looking for. */ 156 /* This is the parameter name we're looking for. */
173 if (true == arg_matching || true == pcre_matching || 157 if (true == pcre_matching || config_node->pos != -1) {
174 (config_node->pos != -1)) { 158 arg_value = ZEND_CALL_VAR_NUM(execute_data, i);
175 zval* arg_value = ZEND_CALL_VAR_NUM(execute_data, i);
176 159
177 if (config_node->param_type) { // Are we matching on the `type`? 160 if (config_node->param_type) { // Are we matching on the `type`?
178 if (config_node->param_type == Z_TYPE_P(arg_value)) { 161 if (config_node->param_type == Z_TYPE_P(arg_value)) {
179 return true; 162 return true;
180 } 163 }
181 } else if (Z_TYPE_P(arg_value) == IS_ARRAY) { 164 } else if (Z_TYPE_P(arg_value) == IS_ARRAY) {
182 *arg_value_str = estrdup("Array"); 165 *arg_value_str = sp_convert_to_string(arg_value);
183 // match on arr -> match on all key content, if a key is an array, 166 if (config_node->key || config_node->r_key) {
184 // ignore it 167 if (sp_match_array_key(arg_value, config_node->key,
185 // match on arr[foo] -> match only on key foo, if the key is an 168 config_node->r_key)) {
186 // array, match on all keys content 169 return true;
187 if (config_node->param_is_array == true) { 170 }
188 if (true == sp_match_array_key_recurse( 171 } else if (sp_match_array_value(arg_value, config_node->value,
189 arg_value, config_node->param_array_keys, 172 config_node->value_r)) {
190 config_node->value, config_node->value_r)) { 173 return true;
191 return true; 174 }
192 } 175 } else {
193 } else { // match on all keys, but don't go into subarray 176 *arg_value_str = sp_convert_to_string(arg_value);
194 if (true == sp_match_array_key(arg_value, config_node->value, 177 if (sp_match_value(*arg_value_str, config_node->value,
195 config_node->value_r)) { 178 config_node->value_r)) {
196 return true;
197 }
198 }
199 } else {
200 *arg_value_str = sp_convert_to_string(arg_value);
201 if (true == sp_match_value(*arg_value_str, config_node->value,
202 config_node->value_r)) {
203 return true; 179 return true;
204 } 180 }
205 } 181 }
206 } 182 }
207 } 183 }
184 } else if (config_node->param) {
185 *arg_name = config_node->param->value;
186 arg_value = get_value(execute_data, config_node->param, true);
187
188 if (arg_value) {
189 *arg_value_str = sp_convert_to_string(arg_value);
190 if (config_node->param_type) { // Are we matching on the `type`?
191 if (config_node->param_type
192 && config_node->param_type == Z_TYPE_P(arg_value)) {
193 return true;
194 }
195 } else if (Z_TYPE_P(arg_value) == IS_ARRAY) {
196 if (config_node->key || config_node->r_key) {
197 if (sp_match_array_key(arg_value, config_node->key,
198 config_node->r_key)) {
199 return true;
200 }
201 } else if (sp_match_array_value(arg_value, config_node->value,
202 config_node->value_r)) {
203 return true;
204 }
205 } else if (sp_match_value(*arg_value_str, config_node->value,
206 config_node->value_r)) {
207 return true;
208 }
209 }
208 } 210 }
209 return false; 211 return false;
210} 212}
@@ -214,7 +216,7 @@ bool should_disable(zend_execute_data* execute_data, const char* builtin_name,
214 char current_file_hash[SHA256_SIZE * 2 + 1] = {0}; 216 char current_file_hash[SHA256_SIZE * 2 + 1] = {0};
215 const sp_node_t* config = get_config_node(builtin_name); 217 const sp_node_t* config = get_config_node(builtin_name);
216 char* complete_path_function = get_complete_function_path(execute_data); 218 char* complete_path_function = get_complete_function_path(execute_data);
217 char const* client_ip = sp_getenv("REMOTE_ADDR"); 219 char const* client_ip = getenv("REMOTE_ADDR");
218 const char* current_filename; 220 const char* current_filename;
219 221
220 if (!config || !config->data) { 222 if (!config || !config->data) {
diff --git a/src/sp_list.c b/src/sp_list.c
index c671f51..70d0ebe 100644
--- a/src/sp_list.c
+++ b/src/sp_list.c
@@ -17,6 +17,34 @@ sp_node_t *sp_list_new() {
17 return new; 17 return new;
18} 18}
19 19
20// Thanks to https://en.wikipedia.org/wiki/Insertion_sort :>
21sp_node_t *sp_list_sort(sp_node_t *pList, int (*cmp_func)(sp_node_t *, sp_node_t *)) {
22 sp_node_t *head = NULL;
23
24 if (pList == NULL || pList->next == NULL) {
25 return pList;
26 }
27 while (pList != NULL) {
28 sp_node_t *current = pList;
29 pList = pList->next;
30 if (head == NULL || 0 > cmp_func(current, head)) {
31 current->next = head;
32 head = current;
33 } else {
34 sp_node_t *p = head;
35 while (p != NULL) {
36 if (p->next == NULL || 0 > cmp_func(current, p->next)) {
37 current->next = p->next;
38 p->next = current;
39 break;
40 }
41 p = p->next;
42 }
43 }
44 }
45 return head;
46}
47
20void sp_list_insert(sp_node_t *list, void *data) { 48void sp_list_insert(sp_node_t *list, void *data) {
21 if (list->head == NULL) { 49 if (list->head == NULL) {
22 list->data = data; 50 list->data = data;
diff --git a/src/sp_list.h b/src/sp_list.h
index dda139f..7878f78 100644
--- a/src/sp_list.h
+++ b/src/sp_list.h
@@ -9,6 +9,7 @@ typedef struct sp_node_s {
9} sp_node_t; 9} sp_node_t;
10 10
11sp_node_t *sp_list_new(); 11sp_node_t *sp_list_new();
12sp_node_t *sp_list_sort(sp_node_t *, int (*)(sp_node_t *, sp_node_t *));
12void sp_list_insert(sp_node_t *, void *); 13void sp_list_insert(sp_node_t *, void *);
13void sp_list_free(sp_node_t *); 14void sp_list_free(sp_node_t *);
14void sp_list_prepend(sp_node_t *, void *); 15void sp_list_prepend(sp_node_t *, void *);
diff --git a/src/sp_tree.c b/src/sp_tree.c
new file mode 100644
index 0000000..328a919
--- /dev/null
+++ b/src/sp_tree.c
@@ -0,0 +1,20 @@
1#include "php_snuffleupagus.h"
2
3void sp_tree_free(sp_tree *tree) {
4 while (tree) {
5 sp_tree *tmp;
6 pefree(tree->value, 1);
7 sp_tree_free(tree->idx);
8 tmp = tree;
9 tree = tree->next;
10 pefree(tmp, 1);
11 }
12}
13
14sp_tree *sp_tree_new() {
15 sp_tree *new = pecalloc(sizeof(sp_tree), 1, 1);
16 new->next = new->idx = NULL;
17 new->value = NULL;
18 new->type = 0;
19 return new;
20}
diff --git a/src/sp_upload_validation.c b/src/sp_upload_validation.c
index 731a737..0010984 100644
--- a/src/sp_upload_validation.c
+++ b/src/sp_upload_validation.c
@@ -51,7 +51,7 @@ int sp_rfc1867_callback(unsigned int event, void *event_data, void **extra) {
51 cmd[2] = NULL; 51 cmd[2] = NULL;
52 52
53 spprintf(&env[0], 0, "SP_FILENAME=%s", filename); 53 spprintf(&env[0], 0, "SP_FILENAME=%s", filename);
54 spprintf(&env[1], 0, "SP_REMOTE_ADDR=%s", sp_getenv("REMOTE_ADDR")); 54 spprintf(&env[1], 0, "SP_REMOTE_ADDR=%s", getenv("REMOTE_ADDR"));
55 spprintf(&env[2], 0, "SP_CURRENT_FILE=%s", 55 spprintf(&env[2], 0, "SP_CURRENT_FILE=%s",
56 zend_get_executed_filename(TSRMLS_C)); 56 zend_get_executed_filename(TSRMLS_C));
57 spprintf(&env[3], 0, "SP_FILESIZE=%zu", filesize); 57 spprintf(&env[3], 0, "SP_FILESIZE=%zu", filesize);
@@ -77,7 +77,7 @@ int sp_rfc1867_callback(unsigned int event, void *event_data, void **extra) {
77 int waitstatus; 77 int waitstatus;
78 wait(&waitstatus); 78 wait(&waitstatus);
79 if (WEXITSTATUS(waitstatus) != 0) { // Nope 79 if (WEXITSTATUS(waitstatus) != 0) { // Nope
80 char *uri = sp_getenv("REQUEST_URI"); 80 char *uri = getenv("REQUEST_URI");
81 int sim = SNUFFLEUPAGUS_G(config).config_upload_validation->simulation; 81 int sim = SNUFFLEUPAGUS_G(config).config_upload_validation->simulation;
82 sp_log_msg("upload_validation", sim?SP_LOG_SIMULATION:SP_LOG_DROP, 82 sp_log_msg("upload_validation", sim?SP_LOG_SIMULATION:SP_LOG_DROP,
83 "The upload of %s on %s was rejected.", filename, uri?uri:"?"); 83 "The upload of %s on %s was rejected.", filename, uri?uri:"?");
diff --git a/src/sp_utils.c b/src/sp_utils.c
index 1ed770b..3fe2e44 100644
--- a/src/sp_utils.c
+++ b/src/sp_utils.c
@@ -25,20 +25,11 @@ void sp_log_msg(char const *feature, char const *level, const char* fmt, ...) {
25 vspprintf(&msg, 0, fmt, args); 25 vspprintf(&msg, 0, fmt, args);
26 va_end(args); 26 va_end(args);
27 27
28 char const * const client_ip = sp_getenv("REMOTE_ADDR"); 28 char const * const client_ip = getenv("REMOTE_ADDR");
29 _sp_log_err("[snuffleupagus][%s][%s][%s] %s", client_ip?client_ip:"0.0.0.0", 29 _sp_log_err("[snuffleupagus][%s][%s][%s] %s", client_ip?client_ip:"0.0.0.0",
30 feature, level, msg); 30 feature, level, msg);
31} 31}
32 32
33
34zend_always_inline char* sp_getenv(char* var) {
35 if (sapi_module.getenv) {
36 return sapi_module.getenv(ZEND_STRL(var));
37 } else {
38 return getenv(var);
39 }
40}
41
42zend_always_inline int is_regexp_matching(const pcre* regexp, const char* str) { 33zend_always_inline int is_regexp_matching(const pcre* regexp, const char* str) {
43 int vec[30]; 34 int vec[30];
44 int ret = 0; 35 int ret = 0;
@@ -278,63 +269,50 @@ void sp_log_disable_ret(const char* restrict path,
278 } 269 }
279} 270}
280 271
281int sp_match_array_key(const zval* zv, const char* to_match, const pcre* rx) { 272bool sp_match_array_key(const zval* zv, const char* to_match, const pcre* rx) {
282 zend_string* key; 273 zend_string* key;
283 zval* value; 274 zend_ulong idx;
284 char* arg_value_str;
285 275
286 ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(zv), key, value) { 276 ZEND_HASH_FOREACH_KEY(Z_ARRVAL_P(zv), idx, key) {
287 if (Z_TYPE_P(value) == IS_ARRAY) { 277 if (key) {
288 continue; 278 if (sp_match_value(ZSTR_VAL(key), to_match, rx)) {
289 } 279 return true;
290 arg_value_str = sp_convert_to_string(value); 280 }
291 if (!sp_match_value(arg_value_str, to_match, rx)) {
292 efree(arg_value_str);
293 continue;
294 } else { 281 } else {
295 efree(arg_value_str); 282 char *idx_str = NULL;
296 return 1; 283
284 // Could use a log.
285 idx_str = emalloc(snprintf(NULL, 0, "%lu", idx));
286 sprintf(idx_str, "%lu", idx);
287 if (sp_match_value(idx_str, to_match, rx)) {
288 efree(idx_str);
289 return true;
290 }
291 efree(idx_str);
297 } 292 }
298 } 293 }
299 ZEND_HASH_FOREACH_END(); 294 ZEND_HASH_FOREACH_END();
300 295 return false;
301 (void)key; // silence a compiler warning
302
303 return 0;
304} 296}
305 297
306int sp_match_array_key_recurse(const zval* arr, sp_node_t* keys, 298bool sp_match_array_value(const zval* arr, const char* to_match, const pcre* rx) {
307 const char* to_match, const pcre* rx) {
308 zend_string* key;
309 zval* value; 299 zval* value;
310 sp_node_t* current = keys; 300
311 if (current == NULL) { 301 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(arr), value) {
312 return 0; 302 if (Z_TYPE_P(value) != IS_ARRAY) {
313 } 303 char *value_str = sp_convert_to_string(value);
314 ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(arr), key, value) { 304 if (sp_match_value(value_str, to_match, rx)) {
315 if (Z_TYPE_P(value) == IS_ARRAY && !strcmp(ZSTR_VAL(key), current->data)) { 305 efree(value_str);
316 return sp_match_array_key_recurse(value, current->next, to_match, rx); 306 return true;
317 }
318 if (!strcmp(ZSTR_VAL(key), current->data) && current->next == NULL) {
319 if (!to_match && !rx) {
320 return 1;
321 }
322 if (Z_TYPE_P(value) == IS_ARRAY) {
323 return sp_match_array_key(value, to_match, rx);
324 } else { 307 } else {
325 char *value_str = sp_convert_to_string(value); 308 efree (value_str);
326 if (sp_match_value(value_str, to_match, rx)) {
327 efree(value_str);
328 return 1;
329 } else {
330 efree (value_str);
331 return 0;
332 }
333 } 309 }
310 } else if (sp_match_array_value(value, to_match, rx)) {
311 return true;
334 } 312 }
335 } 313 }
336 ZEND_HASH_FOREACH_END(); 314 ZEND_HASH_FOREACH_END();
337 return 0; 315 return false;
338} 316}
339 317
340 318
diff --git a/src/sp_utils.h b/src/sp_utils.h
index a17ac4f..e54f307 100644
--- a/src/sp_utils.h
+++ b/src/sp_utils.h
@@ -57,14 +57,12 @@ void sp_log_msg(char const *feature, char const *level, const char* fmt, ...);
57int compute_hash(const char *const filename, char *file_hash); 57int compute_hash(const char *const filename, char *file_hash);
58char *sp_convert_to_string(zval *); 58char *sp_convert_to_string(zval *);
59bool sp_match_value(const char *, const char *, const pcre *); 59bool sp_match_value(const char *, const char *, const pcre *);
60int sp_match_array_key(const zval *, const char *, const pcre *); 60bool sp_match_array_key(const zval *, const char *, const pcre *);
61int sp_match_array_key_recurse(const zval *, sp_node_t *, const char *, 61bool sp_match_array_value(const zval *, const char *, const pcre *);
62 const pcre *);
63void sp_log_disable(const char *restrict, const char *restrict, 62void sp_log_disable(const char *restrict, const char *restrict,
64 const char *restrict, const sp_disabled_function *); 63 const char *restrict, const sp_disabled_function *);
65void sp_log_disable_ret(const char *restrict, const char *restrict, 64void sp_log_disable_ret(const char *restrict, const char *restrict,
66 const sp_disabled_function *); 65 const sp_disabled_function *);
67char *sp_getenv(char *);
68int is_regexp_matching(const pcre *, const char *); 66int is_regexp_matching(const pcre *, const char *);
69int hook_function(const char *, HashTable *, 67int hook_function(const char *, HashTable *,
70 void (*)(INTERNAL_FUNCTION_PARAMETERS), bool); 68 void (*)(INTERNAL_FUNCTION_PARAMETERS), bool);
diff --git a/src/sp_var_parser.c b/src/sp_var_parser.c
new file mode 100644
index 0000000..bc0a80e
--- /dev/null
+++ b/src/sp_var_parser.c
@@ -0,0 +1,247 @@
1#include "php_snuffleupagus.h"
2
3static int parse_str_tokens(const char *str, const sp_token_t token,
4 sp_node_t *tokens_list) {
5 const char *cur_str = str;
6
7 while ((cur_str = strchr(cur_str, token.token[0]))) {
8 if (0 == strncmp(cur_str, token.token, strlen(token.token))) {
9 sp_token_t *token_elm = pecalloc(sizeof(sp_token_t), 1, 1);
10 token_elm->pos = cur_str - str;
11 token_elm->token = token.token;
12 token_elm->type = token.type;
13 sp_list_insert(tokens_list, token_elm);
14 cur_str += strlen(token.token);
15 } else {
16 cur_str++;
17 }
18 }
19 return 0;
20}
21
22static bool is_var_name_valid(const char *name) {
23 static pcre *regexp_const = NULL;
24 static pcre *regexp_var = NULL;
25 const char *pcre_error;
26 int pcre_error_offset;
27
28 if (!name) {
29 return false;
30 }
31 if (NULL == regexp_var || NULL == regexp_const) {
32 regexp_var = sp_pcre_compile(REGEXP_VAR, PCRE_CASELESS, &pcre_error,
33 &pcre_error_offset, NULL);
34 regexp_const = sp_pcre_compile(REGEXP_CONST, PCRE_CASELESS, &pcre_error,
35 &pcre_error_offset, NULL);
36 }
37 if (NULL == regexp_var || NULL == regexp_const) {
38 sp_log_err("config", "Could not compile regexp.");
39 return false;
40 }
41 if (0 > sp_pcre_exec(regexp_var, NULL, name, strlen(name), 0, 0, NULL, 0)
42 && 0 > sp_pcre_exec(regexp_const, NULL, name, strlen(name), 0, 0, NULL, 0)) {
43 return false;
44 }
45 return true;
46}
47
48static int create_var(sp_tree *tree, const char *restrict value,
49 size_t value_len, elem_type _type, const char *restrict idx) {
50 sp_tree *var_node = NULL;
51
52 if (!tree) {
53 return -1;
54 }
55 if (tree->next == NULL && tree->type == 0) {
56 var_node = tree;
57 } else {
58 var_node = pecalloc(sizeof(sp_tree), 1, 1);
59 }
60
61 var_node->value = NULL;
62 var_node->next = NULL;
63 var_node->idx = NULL;
64 var_node->type = _type;
65 // Check if a constant is a variable
66 if (value && value[0] == VARIABLE_TOKEN && _type == CONSTANT) {
67 var_node->type = VAR;
68 }
69 if (!(var_node->value = pestrndup(value, value_len, 1))) {
70 sp_log_err("config", "Can't allocate a strndup");
71 return -1;
72 }
73 if (var_node->type != STRING_DELIMITER && !is_var_name_valid(var_node->value)) {
74 sp_log_err("config", "Invalid var name: %s.", var_node->value);
75 return -1;
76 }
77 var_node->idx = parse_var(idx);
78
79 if (tree != var_node) {
80 while (tree->next) {
81 tree = tree->next;
82 }
83 tree->next = var_node;
84 }
85 return 0;
86}
87
88int cmp_tokens(sp_node_t *list1, sp_node_t *list2) {
89 return (((sp_token_t *)list1->data)->pos
90 - ((sp_token_t *)list2->data)->pos);
91}
92
93static int is_next_token_empty(sp_token_t *token, sp_token_t *token_next,
94 const char * restrict str) {
95 if ((token_next && token_next->pos == token->pos + strlen(token->token))
96 || (!token_next && token->pos == strlen(str) - strlen(token->token))) {
97 return -1;
98 }
99 return 0;
100}
101
102static int is_token_valid(sp_node_t *tokens_list, elem_type ignore,
103 int array_count, const char * restrict str,
104 size_t pos) {
105 sp_token_t *token = (sp_token_t *)tokens_list->data;
106 sp_token_t *token_next = NULL;
107
108 if (tokens_list->next) {
109 token_next = (sp_token_t *)tokens_list->next->data;
110 }
111 switch (token->type) {
112 case ESC_STRING_DELIMITER:
113 case STRING_DELIMITER:
114 if (ignore == token->type) {
115 if (token_next) {
116 if (token_next->pos != token->pos + 1) {
117 return -1;
118 }
119 } else if (token->pos != strlen(str) - 1) {
120 return -1;
121 }
122 }
123 break;
124 case ARRAY_END:
125 if (!ignore) {
126 if (array_count < 1) {
127 return -1;
128 } else if (token_next) {
129 if (token_next->type == STRING_DELIMITER
130 || token_next->type == ESC_STRING_DELIMITER) {
131 return -1;
132 }
133 } else if (token->pos != strlen(str) - strlen(token->token)) {
134 return -1;
135 }
136 }
137 break;
138 case OBJECT:
139 if (!ignore && -1 == is_next_token_empty(token, token_next, str)) {
140 return -1;
141 }
142 if (pos == 0 && *str != VARIABLE_TOKEN) {
143 return -1;
144 }
145 break;
146 case CLASS:
147 if (!ignore && -1 == is_next_token_empty(token, token_next, str)) {
148 return -1;
149 }
150 break;
151 default:
152 break;
153 }
154 return 0;
155}
156
157static sp_tree *parse_tokens(const char * restrict str,
158 sp_node_t *tokens_list) {
159 size_t pos = 0;
160 int array_count = 0, pos_idx_start = -1;
161 elem_type ignore = 0;
162 sp_tree *tree = sp_tree_new();
163
164 for (; tokens_list && tokens_list->data; tokens_list = tokens_list->next) {
165 sp_token_t *token = (sp_token_t *)tokens_list->data;
166 size_t value_len;
167 char *idx = NULL;
168
169 if (-1 == is_token_valid(tokens_list, ignore, array_count, str, pos)) {
170 sp_log_err("config", "Invalid `%s` position.", token->token);
171 goto error;
172 }
173 if (token->type == STRING_DELIMITER || token->type == ESC_STRING_DELIMITER) {
174 pos = (!ignore && !array_count) ? pos + strlen(token->token) : pos;
175 ignore = (!ignore) ? token->type : (ignore == token->type) ? 0 : ignore;
176 token->type = STRING_DELIMITER;
177 }
178 if (ignore == 0) {
179 if (token->type == ARRAY) {
180 pos_idx_start = (array_count) ? pos_idx_start :
181 (int)(token->pos + strlen(token->token));
182 array_count++;
183 } else if (token->type == ARRAY_END) {
184 array_count--;
185 token->type = ARRAY;
186 }
187 if (array_count == 0) {
188 value_len = token->pos - pos;
189 if (token->type == ARRAY) {
190 value_len -= strlen(token->token);
191 }
192 if (pos_idx_start > 0) {
193 idx = estrndup(&(str[pos_idx_start]), token->pos - pos_idx_start);
194 value_len -= token->pos - pos_idx_start;
195 }
196 if (create_var(tree, &str[pos], value_len, token->type, idx)) {
197 goto error;
198 }
199 efree(idx);
200 pos = token->pos + strlen(token->token);
201 pos_idx_start = -1;
202 }
203 }
204 }
205
206 if (ignore != 0 || array_count != 0) {
207error:
208 sp_tree_free(tree);
209 return NULL;
210 }
211 if (pos != strlen(str)
212 && create_var(tree, &str[pos], strlen(str) - pos, CONSTANT, NULL)) {
213 goto error;
214 }
215 return tree;
216}
217
218sp_tree *parse_var(const char *line) {
219 sp_node_t *tokens_list = NULL;
220 sp_tree *tree = NULL;
221 const sp_token_t delimiter_list[] = {
222 {.type=OBJECT, .token=OBJECT_TOKEN},
223 {.type=ARRAY, .token=ARRAY_TOKEN},
224 {.type=ARRAY_END, .token=ARRAY_END_TOKEN},
225 {.type=STRING_DELIMITER, .token=STRING_TOKEN},
226 {.type=ESC_STRING_DELIMITER, .token=ESC_STRING_TOKEN},
227 {.type=CLASS, .token=CLASS_TOKEN}
228 };
229
230
231 if (!line) {
232 return NULL;
233 }
234 tokens_list = sp_list_new();
235 for (unsigned int i = 0; i < sizeof(delimiter_list) / sizeof(sp_token_t); i++) {
236 parse_str_tokens(line, delimiter_list[i], tokens_list);
237 }
238 tokens_list = sp_list_sort(tokens_list, cmp_tokens);
239 tree = parse_tokens(line, tokens_list);
240 sp_list_free(tokens_list);
241 // Check if tree is empty.
242 if (tree && tree->next == NULL && tree->type == 0) {
243 tree->type = CONSTANT;
244 tree->value = pestrdup("", 1);
245 }
246 return tree;
247}
diff --git a/src/sp_var_parser.h b/src/sp_var_parser.h
new file mode 100644
index 0000000..eec1d06
--- /dev/null
+++ b/src/sp_var_parser.h
@@ -0,0 +1,51 @@
1#ifndef SP_VAR_PARSER_H
2# define SP_VAR_PARSER_H
3# include "php_snuffleupagus.h"
4# include "sp_list.h"
5
6typedef enum {
7 OBJECT = 1,
8 ARRAY,
9 ARRAY_END,
10 STRING_DELIMITER,
11 CLASS,
12 VAR,
13 ESC_STRING_DELIMITER,
14 CONSTANT
15} elem_type;
16
17typedef struct sp_token_s {
18 elem_type type;
19 char *token;
20 unsigned int pos;
21} sp_token_t;
22
23typedef struct parser_s {
24 elem_type type;
25 char *value;
26 struct parser_s *idx;
27 struct parser_s *next;
28} sp_tree;
29
30zval *get_value(zend_execute_data *, const sp_tree *, bool);
31sp_tree *sp_tree_new();
32sp_tree *parse_var(const char *);
33void print_type_list(const char *, sp_tree*, int);
34void sp_tree_free(sp_tree *);
35
36# define OBJECT_TOKEN "->"
37# define ARRAY_TOKEN "["
38# define ARRAY_END_TOKEN "]"
39# define STRING_TOKEN "\""
40# define ESC_STRING_TOKEN "\'"
41# define CLASS_TOKEN "::"
42
43# define VARIABLE_TOKEN '$'
44
45# define PRIVATE_PROP_FMT "%c%s%c%s"
46# define PROTECTED_PROP_FMT "%c*%c%s"
47
48# define REGEXP_VAR "^\\$[a-z_][a-z0-9_]*$"
49# define REGEXP_CONST "^[a-z_0-9\\\\]*$"
50
51#endif
diff --git a/src/sp_var_value.c b/src/sp_var_value.c
new file mode 100644
index 0000000..304ece9
--- /dev/null
+++ b/src/sp_var_value.c
@@ -0,0 +1,226 @@
1#include "php_snuffleupagus.h"
2
3static zval *get_param_var(zend_execute_data *ed, const char *var_name) {
4 unsigned int nb_param = ed->func->common.num_args;
5
6 for (unsigned int i = 0; i < nb_param; i++) {
7 const char *arg_name;
8 if (ZEND_USER_CODE(ed->func->type)) {
9 arg_name = ZSTR_VAL(ed->func->common.arg_info[i].name);
10 } else {
11 arg_name = ed->func->internal_function.arg_info[i].name;
12 }
13 if (0 == strcmp(arg_name, var_name)) {
14 return ZEND_CALL_VAR_NUM(ed, i);
15 }
16 }
17 return NULL;
18}
19
20static zval *get_local_var(zend_execute_data *ed, const char *var_name) {
21 zend_execute_data *orig_execute_data = ed;
22 zend_execute_data *current = ed;
23 zval *value = NULL;
24
25 while (current) {
26 zend_string* key = NULL;
27 EG(current_execute_data) = current;
28 zend_array* symtable = zend_rebuild_symbol_table();
29 ZEND_HASH_FOREACH_STR_KEY_VAL(symtable, key, value) {
30 if (0 == strcmp(var_name, key->val)) {
31 if (Z_TYPE_P(value) == IS_INDIRECT) {
32 value = Z_INDIRECT_P(value);
33 }
34 EG(current_execute_data) = orig_execute_data;
35 return value;
36 }
37 }
38 ZEND_HASH_FOREACH_END();
39 current = current->prev_execute_data;
40 }
41 EG(current_execute_data) = orig_execute_data;
42 return NULL;
43}
44
45static zval *get_constant(const char *value) {
46 zend_string *name = zend_string_init(value, strlen(value), 0);
47 zval *zvalue = zend_get_constant_ex(name, NULL, 0);
48
49 zend_string_release(name);
50 return zvalue;
51}
52
53static zval *get_var_value(zend_execute_data *ed, const char *var_name,
54 bool is_param) {
55 zval *zvalue = NULL;
56
57 if (!var_name) {
58 return NULL;
59 }
60 if (*var_name != VARIABLE_TOKEN) {
61 return get_constant(var_name);
62 } else {
63 var_name++;
64 }
65 if (is_param) {
66 zvalue = get_param_var(ed, var_name);
67 if (!zvalue) {
68 return get_local_var(ed, var_name);
69 }
70 return zvalue;
71 }
72 return get_local_var(ed, var_name);
73}
74
75static void *get_entry_hashtable(const HashTable *ht, const char *entry,
76 size_t entry_len) {
77 zval *zvalue = zend_hash_str_find(ht, entry, entry_len);
78
79 if (!zvalue) {
80 zvalue = zend_hash_index_find(ht, atol(entry));
81 }
82 while (zvalue && (Z_TYPE_P(zvalue) == IS_INDIRECT
83 || Z_TYPE_P(zvalue) == IS_PTR)) {
84 if (Z_TYPE_P(zvalue) == IS_INDIRECT) {
85 zvalue = Z_INDIRECT_P(zvalue);
86 } else {
87 zvalue = Z_PTR_P(zvalue);
88 }
89 }
90 return zvalue;
91}
92
93static zval *get_array_value(zend_execute_data *ed, zval *zvalue,
94 const sp_tree *tree) {
95 zval *idx_value, *ret = NULL;
96 char *idx = NULL;
97
98 idx_value = get_value(ed, tree->idx, false);
99 if (!zvalue || !idx_value) {
100 return NULL;
101 }
102 if (Z_TYPE_P(zvalue) == IS_ARRAY) {
103 idx = sp_convert_to_string(idx_value);
104 ret = get_entry_hashtable(Z_ARRVAL_P(zvalue), idx, strlen(idx));
105 efree(idx);
106 }
107 return ret;
108}
109
110static zval *get_object_property(zend_execute_data *ed, zval *object,
111 const char *property, bool is_param) {
112 char *class_name = object->value.obj->ce->name->val;
113 HashTable *array = Z_OBJPROP_P(object);
114 zval *zvalue = NULL;
115 zval *property_val = get_var_value(ed, property, is_param);
116 size_t len;
117
118 if (property_val) {
119 if (Z_TYPE_P(property_val) != IS_STRING) {
120 return NULL;
121 } else {
122 property = Z_STRVAL_P(property_val);
123 }
124 }
125 zvalue = get_entry_hashtable(array, property, strlen(property));
126 if (!zvalue) {
127 char *protected_property = emalloc(strlen(property) + 4);
128 len = sprintf(protected_property, PROTECTED_PROP_FMT, 0, 0, property);
129 zvalue = get_entry_hashtable(array, protected_property, len);
130 efree(protected_property);
131 }
132 if (!zvalue) {
133 char *private_property = emalloc(strlen(class_name) + 3 + strlen(property));
134 len = sprintf(private_property, PRIVATE_PROP_FMT, 0, class_name, 0, property);
135 zvalue = get_entry_hashtable(array, private_property, len);
136 efree(private_property);
137 }
138 return zvalue;
139}
140
141static zend_class_entry *get_class(const char *value) {
142 zend_string *name;
143 zend_class_entry *ce;
144
145 name = zend_string_init(value, strlen(value), 0);
146 ce = zend_lookup_class(name);
147 zend_string_release(name);
148 return ce;
149}
150
151static zval *get_unknown_type(const char *restrict value, zval *zvalue,
152 zend_class_entry *ce, zend_execute_data *ed,
153 const sp_tree *tree, bool is_param) {
154 if (ce) {
155 zvalue = get_entry_hashtable(&ce->constants_table, value, strlen(value));
156 ce = NULL;
157 } else if (zvalue && Z_TYPE_P(zvalue) == IS_OBJECT && value[0]) {
158 zvalue = get_object_property(ed, zvalue, value, is_param);
159 } else if (!tree->next && !zvalue) {
160 if (tree->type == CONSTANT) {
161 zvalue = get_constant(value);
162 }
163 if (!zvalue) {
164 zvalue = emalloc(sizeof(zval));
165 zvalue->value.str = zend_string_init(value, strlen(value), 0);
166 zvalue->u1.v.type = IS_STRING;
167 }
168 } else {
169 return NULL;
170 }
171 return zvalue;
172}
173
174zval *get_value(zend_execute_data *ed, const sp_tree *tree,
175 bool is_param) {
176 zval *zvalue = NULL;
177 zend_class_entry *ce = NULL;
178
179 while (tree) {
180 switch (tree->type) {
181 case ARRAY:
182 if (ce) {
183 zvalue = get_entry_hashtable(&ce->constants_table, tree->value,
184 strlen(tree->value));
185 ce = NULL;
186 } else if (!zvalue) {
187 zvalue = get_var_value(ed, tree->value, is_param);
188 } else if (Z_TYPE_P(zvalue) == IS_OBJECT) {
189 zvalue = get_object_property(ed, zvalue, tree->value, is_param);
190 }
191 zvalue = get_array_value(ed, zvalue, tree);
192 break;
193 case VAR:
194 if (zvalue && Z_TYPE_P(zvalue) == IS_OBJECT) {
195 zvalue = get_object_property(ed, zvalue, tree->value, is_param);
196 } else {
197 zvalue = get_var_value(ed, tree->value, is_param);
198 }
199 break;
200 case OBJECT:
201 if (!zvalue) {
202 zvalue = get_var_value(ed, tree->value, is_param);
203 } else if (Z_TYPE_P(zvalue) == IS_OBJECT) {
204 if (0 != strlen(tree->value)) {
205 zvalue = get_object_property(ed, zvalue, tree->value, is_param);
206 }
207 } else {
208 return NULL;
209 }
210 break;
211 case CLASS:
212 ce = get_class(tree->value);
213 zvalue = NULL;
214 break;
215 default:
216 zvalue = get_unknown_type(tree->value, zvalue, ce, ed, tree, is_param);
217 ce = NULL;
218 break;
219 }
220 if (!zvalue && !ce) {
221 return NULL;
222 }
223 tree = tree->next;
224 }
225 return zvalue;
226}
diff --git a/src/tests/broken_conf_key_value.phpt b/src/tests/broken_conf_key_value.phpt
new file mode 100644
index 0000000..e9ee4a9
--- /dev/null
+++ b/src/tests/broken_conf_key_value.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_key_value.ini
7--FILE--
8--EXPECT--
9[snuffleupagus][0.0.0.0][config][error] Invalid configuration line: 'sp.disabled_functions.function("system").var("").value("").key("").drop();':`key` and `value` are mutually exclusive on line 1.
diff --git a/src/tests/broken_conf_local_var_1.phpt b/src/tests/broken_conf_local_var_1.phpt
new file mode 100644
index 0000000..a91d275
--- /dev/null
+++ b/src/tests/broken_conf_local_var_1.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_local_var_1.ini
7--FILE--
8--EXPECT--
9[snuffleupagus][0.0.0.0][config][error] Invalid `]` position.
10[snuffleupagus][0.0.0.0][config][error] Invalid value ']' for `var` on line 1.
diff --git a/src/tests/broken_conf_local_var_10.phpt b/src/tests/broken_conf_local_var_10.phpt
new file mode 100644
index 0000000..8a7d9b9
--- /dev/null
+++ b/src/tests/broken_conf_local_var_10.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_local_var_10.ini
7--FILE--
8--EXPECT--
9[snuffleupagus][0.0.0.0][config][error] Invalid `]` position.
10[snuffleupagus][0.0.0.0][config][error] Invalid value 'asd[asd]asd' for `var` on line 1.
diff --git a/src/tests/broken_conf_local_var_11.phpt b/src/tests/broken_conf_local_var_11.phpt
new file mode 100644
index 0000000..1817a3f
--- /dev/null
+++ b/src/tests/broken_conf_local_var_11.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_local_var_11.ini
7--FILE--
8--EXPECT--
9[snuffleupagus][0.0.0.0][config][error] Invalid `::` position.
10[snuffleupagus][0.0.0.0][config][error] Invalid value 'asd::' for `param` on line 1.
diff --git a/src/tests/broken_conf_local_var_12.phpt b/src/tests/broken_conf_local_var_12.phpt
new file mode 100644
index 0000000..0b52e2a
--- /dev/null
+++ b/src/tests/broken_conf_local_var_12.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_local_var_12.ini
7--FILE--
8--EXPECT--
9[snuffleupagus][0.0.0.0][config][error] Empty value in `var` on line 1.
diff --git a/src/tests/broken_conf_local_var_13.phpt b/src/tests/broken_conf_local_var_13.phpt
new file mode 100644
index 0000000..ca6be6d
--- /dev/null
+++ b/src/tests/broken_conf_local_var_13.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_local_var_13.ini
7--FILE--
8--EXPECT--
9[snuffleupagus][0.0.0.0][config][error] Invalid `->` position.
10[snuffleupagus][0.0.0.0][config][error] Invalid value 'asd->asd' for `var` on line 1.
diff --git a/src/tests/broken_conf_local_var_14.phpt b/src/tests/broken_conf_local_var_14.phpt
new file mode 100644
index 0000000..cb7e455
--- /dev/null
+++ b/src/tests/broken_conf_local_var_14.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_local_var_14.ini
7--FILE--
8--EXPECT--
9[snuffleupagus][0.0.0.0][config][error] Invalid var name: $i+valid var name .
10[snuffleupagus][0.0.0.0][config][error] Invalid value '$i+valid var name ' for `var` on line 1.
diff --git a/src/tests/broken_conf_local_var_2.phpt b/src/tests/broken_conf_local_var_2.phpt
new file mode 100644
index 0000000..b67a492
--- /dev/null
+++ b/src/tests/broken_conf_local_var_2.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_local_var_2.ini
7--FILE--
8--EXPECT--
9[snuffleupagus][0.0.0.0][config][error] Invalid `"` position.
10[snuffleupagus][0.0.0.0][config][error] Invalid value '""asd' for `var` on line 1.
diff --git a/src/tests/broken_conf_local_var_3.phpt b/src/tests/broken_conf_local_var_3.phpt
new file mode 100644
index 0000000..639d2ea
--- /dev/null
+++ b/src/tests/broken_conf_local_var_3.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_local_var_3.ini
7--FILE--
8--EXPECT--
9[snuffleupagus][0.0.0.0][config][error] Invalid `->` position.
10[snuffleupagus][0.0.0.0][config][error] Invalid value '$qwe->::' for `var` on line 1.
diff --git a/src/tests/broken_conf_local_var_4.phpt b/src/tests/broken_conf_local_var_4.phpt
new file mode 100644
index 0000000..e50f9a6
--- /dev/null
+++ b/src/tests/broken_conf_local_var_4.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_local_var_4.ini
7--FILE--
8--EXPECT--
9[snuffleupagus][0.0.0.0][config][error] Invalid `"` position.
10[snuffleupagus][0.0.0.0][config][error] Invalid value '"asd"asd[]' for `var` on line 1.
diff --git a/src/tests/broken_conf_local_var_5.phpt b/src/tests/broken_conf_local_var_5.phpt
new file mode 100644
index 0000000..0c0d59a
--- /dev/null
+++ b/src/tests/broken_conf_local_var_5.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_local_var_5.ini
7--FILE--
8--EXPECT--
9[snuffleupagus][0.0.0.0][config][error] Invalid `'` position.
10[snuffleupagus][0.0.0.0][config][error] Invalid value ''asd'asd[]' for `var` on line 1.
diff --git a/src/tests/broken_conf_local_var_6.phpt b/src/tests/broken_conf_local_var_6.phpt
new file mode 100644
index 0000000..c51de24
--- /dev/null
+++ b/src/tests/broken_conf_local_var_6.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_local_var_6.ini
7--FILE--
8--EXPECT--
9[snuffleupagus][0.0.0.0][config][error] Invalid `'` position.
10[snuffleupagus][0.0.0.0][config][error] Invalid value '''asd' for `var` on line 1.
diff --git a/src/tests/broken_conf_local_var_7.phpt b/src/tests/broken_conf_local_var_7.phpt
new file mode 100644
index 0000000..d3a0fa4
--- /dev/null
+++ b/src/tests/broken_conf_local_var_7.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_local_var_7.ini
7--FILE--
8--EXPECT--
9[snuffleupagus][0.0.0.0][config][error] Invalid `->` position.
10[snuffleupagus][0.0.0.0][config][error] Invalid value 'asd-->' for `var` on line 1.
diff --git a/src/tests/broken_conf_local_var_8.phpt b/src/tests/broken_conf_local_var_8.phpt
new file mode 100644
index 0000000..749a1aa
--- /dev/null
+++ b/src/tests/broken_conf_local_var_8.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_local_var_8.ini
7--FILE--
8--EXPECT--
9[snuffleupagus][0.0.0.0][config][error] Invalid `]` position.
10[snuffleupagus][0.0.0.0][config][error] Invalid value 'asd[asd]"asd"' for `var` on line 1.
diff --git a/src/tests/broken_conf_local_var_9.phpt b/src/tests/broken_conf_local_var_9.phpt
new file mode 100644
index 0000000..6f706db
--- /dev/null
+++ b/src/tests/broken_conf_local_var_9.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_local_var_9.ini
7--FILE--
8--EXPECT--
9[snuffleupagus][0.0.0.0][config][error] Invalid `]` position.
10[snuffleupagus][0.0.0.0][config][error] Invalid value 'asd[asd]'asd'' for `var` on line 1.
diff --git a/src/tests/config/broken_conf_key_value.ini b/src/tests/config/broken_conf_key_value.ini
new file mode 100644
index 0000000..a0edaf2
--- /dev/null
+++ b/src/tests/config/broken_conf_key_value.ini
@@ -0,0 +1 @@
sp.disable_function.function("system").var("").value("").key("").drop();
diff --git a/src/tests/config/broken_conf_local_var_1.ini b/src/tests/config/broken_conf_local_var_1.ini
new file mode 100644
index 0000000..ae5165c
--- /dev/null
+++ b/src/tests/config/broken_conf_local_var_1.ini
@@ -0,0 +1 @@
sp.disable_function.function("system").var("]").drop();
diff --git a/src/tests/config/broken_conf_local_var_10.ini b/src/tests/config/broken_conf_local_var_10.ini
new file mode 100644
index 0000000..93dd07f
--- /dev/null
+++ b/src/tests/config/broken_conf_local_var_10.ini
@@ -0,0 +1 @@
sp.disable_function.function("system").var("asd[asd]asd").drop();
diff --git a/src/tests/config/broken_conf_local_var_11.ini b/src/tests/config/broken_conf_local_var_11.ini
new file mode 100644
index 0000000..028b1bd
--- /dev/null
+++ b/src/tests/config/broken_conf_local_var_11.ini
@@ -0,0 +1 @@
sp.disable_function.function("system").param("asd::").drop();
diff --git a/src/tests/config/broken_conf_local_var_12.ini b/src/tests/config/broken_conf_local_var_12.ini
new file mode 100644
index 0000000..a151960
--- /dev/null
+++ b/src/tests/config/broken_conf_local_var_12.ini
@@ -0,0 +1 @@
sp.disable_function.function("system").var("").drop();
diff --git a/src/tests/config/broken_conf_local_var_13.ini b/src/tests/config/broken_conf_local_var_13.ini
new file mode 100644
index 0000000..e7c9778
--- /dev/null
+++ b/src/tests/config/broken_conf_local_var_13.ini
@@ -0,0 +1 @@
sp.disable_function.function("system").var("asd->asd").drop();
diff --git a/src/tests/config/broken_conf_local_var_14.ini b/src/tests/config/broken_conf_local_var_14.ini
new file mode 100644
index 0000000..6c98ec3
--- /dev/null
+++ b/src/tests/config/broken_conf_local_var_14.ini
@@ -0,0 +1 @@
sp.disable_function.function("system").var("$i+valid var name ").drop();
diff --git a/src/tests/config/broken_conf_local_var_2.ini b/src/tests/config/broken_conf_local_var_2.ini
new file mode 100644
index 0000000..145a3b5
--- /dev/null
+++ b/src/tests/config/broken_conf_local_var_2.ini
@@ -0,0 +1 @@
sp.disable_function.function("system").var("\"\"asd").drop();
diff --git a/src/tests/config/broken_conf_local_var_3.ini b/src/tests/config/broken_conf_local_var_3.ini
new file mode 100644
index 0000000..5d89076
--- /dev/null
+++ b/src/tests/config/broken_conf_local_var_3.ini
@@ -0,0 +1 @@
sp.disable_function.function("system").var("\$qwe->::").drop();
diff --git a/src/tests/config/broken_conf_local_var_4.ini b/src/tests/config/broken_conf_local_var_4.ini
new file mode 100644
index 0000000..3ec073b
--- /dev/null
+++ b/src/tests/config/broken_conf_local_var_4.ini
@@ -0,0 +1 @@
sp.disable_function.function("system").var("\"asd\"asd[]").drop();
diff --git a/src/tests/config/broken_conf_local_var_5.ini b/src/tests/config/broken_conf_local_var_5.ini
new file mode 100644
index 0000000..cd350b6
--- /dev/null
+++ b/src/tests/config/broken_conf_local_var_5.ini
@@ -0,0 +1 @@
sp.disable_function.function("system").var("'asd'asd[]").drop();
diff --git a/src/tests/config/broken_conf_local_var_6.ini b/src/tests/config/broken_conf_local_var_6.ini
new file mode 100644
index 0000000..02f4f1a
--- /dev/null
+++ b/src/tests/config/broken_conf_local_var_6.ini
@@ -0,0 +1 @@
sp.disable_function.function("system").var("''asd").drop();
diff --git a/src/tests/config/broken_conf_local_var_7.ini b/src/tests/config/broken_conf_local_var_7.ini
new file mode 100644
index 0000000..abbd223
--- /dev/null
+++ b/src/tests/config/broken_conf_local_var_7.ini
@@ -0,0 +1 @@
sp.disable_function.function("system").var("asd-->").drop();
diff --git a/src/tests/config/broken_conf_local_var_8.ini b/src/tests/config/broken_conf_local_var_8.ini
new file mode 100644
index 0000000..fd18487
--- /dev/null
+++ b/src/tests/config/broken_conf_local_var_8.ini
@@ -0,0 +1 @@
sp.disable_function.function("system").var("asd[asd]\"asd\"").drop();
diff --git a/src/tests/config/broken_conf_local_var_9.ini b/src/tests/config/broken_conf_local_var_9.ini
new file mode 100644
index 0000000..a311b86
--- /dev/null
+++ b/src/tests/config/broken_conf_local_var_9.ini
@@ -0,0 +1 @@
sp.disable_function.function("system").var("asd[asd]\'asd\'").drop();
diff --git a/src/tests/config/config_disabled_functions_local_var_array.ini b/src/tests/config/config_disabled_functions_local_var_array.ini
new file mode 100644
index 0000000..15dd5a1
--- /dev/null
+++ b/src/tests/config/config_disabled_functions_local_var_array.ini
@@ -0,0 +1 @@
sp.disable_function.function("foo").var("$a[test2][foo]").value("aaa").drop();
diff --git a/src/tests/config/config_disabled_functions_local_var_array_key.ini b/src/tests/config/config_disabled_functions_local_var_array_key.ini
new file mode 100644
index 0000000..75c840d
--- /dev/null
+++ b/src/tests/config/config_disabled_functions_local_var_array_key.ini
@@ -0,0 +1 @@
sp.disable_function.function("foo").var("$a[test2][foo]").key("aaa").drop();
diff --git a/src/tests/config/config_disabled_functions_name_type.ini b/src/tests/config/config_disabled_functions_name_type.ini
index 25bdf98..c25b92c 100644
--- a/src/tests/config/config_disabled_functions_name_type.ini
+++ b/src/tests/config/config_disabled_functions_name_type.ini
@@ -1 +1 @@
sp.disable_function.function_r("^strcmp$").param("str1").param_type("array").drop(); sp.disable_function.function_r("^strcmp$").param("$str1").param_type("array").drop();
diff --git a/src/tests/config/config_disabled_functions_nul_byte.ini b/src/tests/config/config_disabled_functions_nul_byte.ini
index d5eb847..e664cba 100644
--- a/src/tests/config/config_disabled_functions_nul_byte.ini
+++ b/src/tests/config/config_disabled_functions_nul_byte.ini
@@ -1 +1 @@
sp.disable_function.function("system").param("command").value_r("id").drop(); \ No newline at end of file sp.disable_function.function("system").param("$command").value_r("id").drop();
diff --git a/src/tests/config/config_disabled_functions_param.ini b/src/tests/config/config_disabled_functions_param.ini
index 87f1b3c..dc1c949 100644
--- a/src/tests/config/config_disabled_functions_param.ini
+++ b/src/tests/config/config_disabled_functions_param.ini
@@ -1,6 +1,6 @@
1sp.disable_function.function("system").param("command").value_r("^id$").alias("1").drop(); 1sp.disable_function.function("system").param("$command").value_r("^id$").alias("1").drop();
2sp.disable_function.function("array_sum").param("array").value_r("^8$").alias("2").drop(); 2sp.disable_function.function("array_sum").param("$array").value_r("^8$").alias("2").drop();
3sp.disable_function.function("shell_exec").param("cmd").value("id").alias("3").drop(); 3sp.disable_function.function("shell_exec").param("$cmd").value("id").alias("3").drop();
4sp.disable_function.function("shell_exec").param("cmd").value("bla").alias("4").drop(); 4sp.disable_function.function("shell_exec").param("$cmd").value("bla").alias("4").drop();
5sp.disable_function.function("strcmp").param("str1").value("bla").alias("5").drop().simulation(); 5sp.disable_function.function("strcmp").param("$str1").value("bla").alias("5").drop().simulation();
6sp.disable_function.function("strncmp").param("str1").value("bla").drop().simulation(); 6sp.disable_function.function("strncmp").param("$str1").value("bla").drop().simulation();
diff --git a/src/tests/config/config_disabled_functions_param_allow.ini b/src/tests/config/config_disabled_functions_param_allow.ini
index 8e139e4..27d919a 100644
--- a/src/tests/config/config_disabled_functions_param_allow.ini
+++ b/src/tests/config/config_disabled_functions_param_allow.ini
@@ -1,3 +1,3 @@
1sp.disable_function.function("system").param("command").value("echo win").filename("/test.php").drop(); 1sp.disable_function.function("system").param("$command").value("echo win").filename("/test.php").drop();
2sp.disable_function.function("system").param("command").value("echo win").allow(); 2sp.disable_function.function("system").param("$command").value("echo win").allow();
3sp.disable_function.function("system").drop(); 3sp.disable_function.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
index 0589ad8..6fe0615 100644
--- a/src/tests/config/config_disabled_functions_param_array.ini
+++ b/src/tests/config/config_disabled_functions_param_array.ini
@@ -1,4 +1,7 @@
1sp.disable_function.function("foo").param("arr").value("abcd").alias("1").drop(); 1sp.disable_function.function("foo").param("$arr[a]").value("abcd").alias("1").drop();
2sp.disable_function.function("foo").param("arr[bla]").value("abcdef").alias("2").drop(); 2sp.disable_function.function("foo").param("$arr[bla]").value("abcdef").alias("2").drop();
3sp.disable_function.function("foo").param("arr[test]").alias("3").drop(); 3sp.disable_function.function("foo").param("$arr[test]").alias("3").drop();
4sp.disable_function.function("foo").param("arr[test2][foo][lol]").value("aaa").alias("4").drop(); 4sp.disable_function.function("foo").param("$arr[test2][foo]").value("aaa").alias("4").drop();
5sp.disable_function.function("foo").param("$arr[test2][bar]").key("lol").alias("5").drop();
6sp.disable_function.function("foo").param("$arr[test2][bar]").key("123").alias("6").drop();
7sp.disable_function.function("foo").param("$qwe[a]").value("abcd").alias("7").drop();
diff --git a/src/tests/config/config_disabled_functions_param_int.ini b/src/tests/config/config_disabled_functions_param_int.ini
index 1c93c2f..2a7d962 100644
--- a/src/tests/config/config_disabled_functions_param_int.ini
+++ b/src/tests/config/config_disabled_functions_param_int.ini
@@ -1,2 +1,2 @@
1sp.disable_function.function("foobar").param("id").value("42").drop(); 1sp.disable_function.function("foobar").param("$id").value("42").drop();
2sp.disable_function.function("foobar").param("id").value_r("^1337").drop(); 2sp.disable_function.function("foobar").param("$id").value_r("^1337").drop();
diff --git a/src/tests/config/config_disabled_functions_param_r_array.ini b/src/tests/config/config_disabled_functions_param_r_array.ini
new file mode 100644
index 0000000..fcac71d
--- /dev/null
+++ b/src/tests/config/config_disabled_functions_param_r_array.ini
@@ -0,0 +1,2 @@
1sp.disable_function.function("foo").param_r("arr").value("abcd").alias("1").drop();
2sp.disable_function.function("foo").param_r("arr").key_r("abc").alias("2").drop();
diff --git a/src/tests/config/config_disabled_functions_param_runtime.ini b/src/tests/config/config_disabled_functions_param_runtime.ini
index e7a011f..e9d44a2 100644
--- a/src/tests/config/config_disabled_functions_param_runtime.ini
+++ b/src/tests/config/config_disabled_functions_param_runtime.ini
@@ -1 +1 @@
sp.disable_function.function("test").param("param").value_r("1337").drop(); sp.disable_function.function("test").param("$param").value_r("1337").drop();
diff --git a/src/tests/config/disabled_function_local_var.ini b/src/tests/config/disabled_function_local_var.ini
index cba2ae3..3d553c0 100644
--- a/src/tests/config/disabled_function_local_var.ini
+++ b/src/tests/config/disabled_function_local_var.ini
@@ -1,2 +1,10 @@
1sp.disable_function.function("phpinfo").var("b").value("1337").drop(); 1sp.disable_function.function("phpinfo").var("$b").value("1337").drop();
2sp.disable_function.function("strlen").var("a").value("1337").drop(); 2sp.disable_function.function("strlen").var("$a").value("1337").drop();
3sp.disable_function.function("strlen").var("$a['123']").value("block").drop();
4sp.disable_function.function("strlen").var("$a[$c]->prop").value("block").drop();
5sp.disable_function.function("strlen").var("$a->zxc").value("not a good value").drop();
6sp.disable_function.function("strlen").var("\\asd\\test_object::TEST_VALUE['constant']").value("no good").drop();
7sp.disable_function.function("strlen").var("\\asd\\test_object::TEST_VALUE").value("qwerty").drop();
8sp.disable_function.function("strlen").var("\\qwe\\ASD").value("qwerty").drop();
9sp.disable_function.function("strlen").var("\\qwe\\QWE['123']").value("asdfgh").drop();
10sp.disable_function.function("strlen").var("$qwe").value("block this").drop();
diff --git a/src/tests/config/disabled_function_local_var_2.ini b/src/tests/config/disabled_function_local_var_2.ini
new file mode 100644
index 0000000..e3e9ae6
--- /dev/null
+++ b/src/tests/config/disabled_function_local_var_2.ini
@@ -0,0 +1 @@
sp.disable_function.function("strlen").var("$b['_GET[obj->nop]'][$b[456][$d->$idk->qwe[\\qwe\\UNE_CONSTANTE]]][$a]->uio").value("valeur de apres").drop();
diff --git a/src/tests/config/disabled_function_local_var_obj.ini b/src/tests/config/disabled_function_local_var_obj.ini
new file mode 100644
index 0000000..df6b617
--- /dev/null
+++ b/src/tests/config/disabled_function_local_var_obj.ini
@@ -0,0 +1,3 @@
1sp.disable_function.function("strlen").var("$test->$test_array").value("value").drop();
2sp.disable_function.function("strlen").var("$arg->$test_array").value("value").drop();
3sp.disable_function.function("strlen").var("$test->$arg").value("nop_object").drop();
diff --git a/src/tests/config/disabled_function_super_global_var.ini b/src/tests/config/disabled_function_super_global_var.ini
index feac314..178a01a 100644
--- a/src/tests/config/disabled_function_super_global_var.ini
+++ b/src/tests/config/disabled_function_super_global_var.ini
@@ -1 +1 @@
sp.disable_function.function("strlen").var("_GET[bla]").value("test2").drop(); sp.disable_function.function("strlen").var("$_GET[bla]").value("test2").drop();
diff --git a/src/tests/config/disabled_functions_pos.ini b/src/tests/config/disabled_functions_pos.ini
index e7d12a9..2b4650d 100644
--- a/src/tests/config/disabled_functions_pos.ini
+++ b/src/tests/config/disabled_functions_pos.ini
@@ -1,2 +1,3 @@
1sp.disable_function.function("system").pos("1337").value("id").drop(); 1sp.disable_function.function("system").pos("1337").value("id").drop();
2sp.disable_function.function("system").pos("0").value("id").drop(); 2sp.disable_function.function("system").pos("0").value("id").drop();
3sp.disable_function.function("system").pos("1").param_type("ARRAY").alias("1").drop();
diff --git a/src/tests/disabled_function_local_var_10.phpt b/src/tests/disabled_function_local_var_10.phpt
new file mode 100644
index 0000000..538d693
--- /dev/null
+++ b/src/tests/disabled_function_local_var_10.phpt
@@ -0,0 +1,44 @@
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$qwe = Array('123' => Array('qwe'), '456' => Array('no block this'));
10var_dump($qwe);
11strlen("qwe");
12$qwe = Array('123' => Array('qwe'), '456' => Array(Array('block this')));
13var_dump($qwe);
14strlen("qwe");
15?>
16--EXPECTF--
17array(2) {
18 [123]=>
19 array(1) {
20 [0]=>
21 string(3) "qwe"
22 }
23 [456]=>
24 array(1) {
25 [0]=>
26 string(13) "no block this"
27 }
28}
29array(2) {
30 [123]=>
31 array(1) {
32 [0]=>
33 string(3) "qwe"
34 }
35 [456]=>
36 array(1) {
37 [0]=>
38 array(1) {
39 [0]=>
40 string(10) "block this"
41 }
42 }
43}
44[snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'strlen' in %a/tests/disabled_function_local_var_10.php:%d has been disabled.
diff --git a/src/tests/disabled_function_local_var_2.phpt b/src/tests/disabled_function_local_var_2.phpt
new file mode 100644
index 0000000..da0a3d2
--- /dev/null
+++ b/src/tests/disabled_function_local_var_2.phpt
@@ -0,0 +1,46 @@
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 = Array();
17$a['qwe'] = 'block';
18$a['123'] = 'nop';
19echo "Value of a:\n";
20var_dump($a);
21test();
22
23$a['123'] = 'block';
24echo "Value of a:\n";
25var_dump($a);
26test();
27?>
28--EXPECTF--
29Value of a: 1338
302
31Value of a:
32array(2) {
33 ["qwe"]=>
34 string(5) "block"
35 [123]=>
36 string(3) "nop"
37}
382
39Value of a:
40array(2) {
41 ["qwe"]=>
42 string(5) "block"
43 [123]=>
44 string(5) "block"
45}
46[snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'strlen' in %a/tests/disabled_function_local_var_2.php:%d has been disabled.
diff --git a/src/tests/disabled_function_local_var_3.phpt b/src/tests/disabled_function_local_var_3.phpt
new file mode 100644
index 0000000..d26b636
--- /dev/null
+++ b/src/tests/disabled_function_local_var_3.phpt
@@ -0,0 +1,45 @@
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
9function test(){
10 echo strlen("id") . "\n";
11}
12
13$a = Array();
14$c = '123';
15$a['qwe'] = 'qwe';
16$a['123'] = 'nop';
17echo "Value of a:\n";
18var_dump($a);
19test();
20
21$a[$c] = (Object)['prop' => 'block'];
22echo "Value of a:\n";
23var_dump($a);
24test();
25?>
26--EXPECTF--
27Value of a:
28array(2) {
29 ["qwe"]=>
30 string(3) "qwe"
31 [123]=>
32 string(3) "nop"
33}
342
35Value of a:
36array(2) {
37 ["qwe"]=>
38 string(3) "qwe"
39 [123]=>
40 object(stdClass)#1 (1) {
41 ["prop"]=>
42 string(5) "block"
43 }
44}
45[snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'strlen' in %a/tests/disabled_function_local_var_3.php:%d has been disabled.
diff --git a/src/tests/disabled_function_local_var_4.phpt b/src/tests/disabled_function_local_var_4.phpt
new file mode 100644
index 0000000..ae8d713
--- /dev/null
+++ b/src/tests/disabled_function_local_var_4.phpt
@@ -0,0 +1,56 @@
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_2.ini
7--FILE--
8<?php
9namespace qwe {
10 const UNE_CONSTANTE = 'constant';
11}
12namespace asd {
13$b = Array();
14$b['_GET[obj->nop]'] = Array();
15$b['_GET[obj->nop]']["qwe"] = Array();
16$b[456] = Array();
17$b[456]['zxc'] = "qwe";
18$b[456]['nop'] = "nop";
19$b['_GET[obj->nop]']["qwe"][321] = "Yeay";
20$b["123"] = "qwe";
21$b["123a"] = "foo";
22$b["asd"] = "zxc";
23$b['_GET[obj->nop]']["qwe"][1337] = (Object)(['uio' => "valeur de apres"]);
24$b['_GET[obj->nop]']["qwe"][1338] = (Object)(['uio' => "valeur de a"]);
25$c = (Object)(['qwe' => Array(\qwe\UNE_CONSTANTE => 'zxc')]);
26$idk = 'test_asd';
27$class_name = 'test_object';
28class test_object {
29 const TEST_VALUE = ['constant' => 'truc'];
30 private $asd = "qwe";
31 public $qwe = 'bar';
32 private $test_asd = '';
33 function __construct($asd) {
34 $this->test_asd = $asd;
35 }
36 function do_a_barell_roll() {
37 var_dump($this->test_asd);
38 }
39}
40$d = new test_object($c);
41$a = 1338;
42function test(){
43 strlen("qwe");
44}
45echo "Valeur: " . $b['_GET[obj->nop]']["qwe"][$a]->uio . "\n";
46test();
47
48$a = 1337;
49echo "Valeur: " . $b['_GET[obj->nop]']["qwe"][$a]->uio . "\n";
50test();
51}
52?>
53--EXPECTF--
54Valeur: valeur de a
55Valeur: valeur de apres
56[snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'strlen' in %a/tests/disabled_function_local_var_4.php:%d has been disabled.
diff --git a/src/tests/disabled_function_local_var_5.phpt b/src/tests/disabled_function_local_var_5.phpt
new file mode 100644
index 0000000..d82574d
--- /dev/null
+++ b/src/tests/disabled_function_local_var_5.phpt
@@ -0,0 +1,33 @@
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
9function test(){
10 echo strlen("id") . "\n";
11}
12
13$a = Array();
14echo "Value of a:\n";
15var_dump($a);
16test();
17
18$a = (Object)['zxc' => 'not a good value'];
19echo "Value of a:\n";
20var_dump($a);
21test();
22?>
23--EXPECTF--
24Value of a:
25array(0) {
26}
272
28Value of a:
29object(stdClass)#1 (1) {
30 ["zxc"]=>
31 string(16) "not a good value"
32}
33[snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'strlen' in %a/tests/disabled_function_local_var_5.php:%d has been disabled.
diff --git a/src/tests/disabled_function_local_var_6.phpt b/src/tests/disabled_function_local_var_6.phpt
new file mode 100644
index 0000000..90c1815
--- /dev/null
+++ b/src/tests/disabled_function_local_var_6.phpt
@@ -0,0 +1,31 @@
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
9namespace asd {
10function test(){
11 strlen("qwe");
12}
13echo "Valeur: " . \asd\test_object::TEST_VALUE['constant'] . "\n";
14test();
15class test_object {
16 const TEST_VALUE = ['constant' => 'no good'];
17 private $asd = "qwe";
18 public $qwe = 'bar';
19 private $test_asd = '';
20 function __construct($asd) {
21 $this->test_asd = $asd;
22 }
23 function do_a_barell_roll() {
24 var_dump($this->test_asd);
25 }
26}
27}
28?>
29--EXPECTF--
30Valeur: no good
31[snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'strlen' in %a/tests/disabled_function_local_var_6.php:%d has been disabled.
diff --git a/src/tests/disabled_function_local_var_7.phpt b/src/tests/disabled_function_local_var_7.phpt
new file mode 100644
index 0000000..7ab249a
--- /dev/null
+++ b/src/tests/disabled_function_local_var_7.phpt
@@ -0,0 +1,31 @@
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
9namespace asd {
10function test(){
11 strlen("qwe");
12}
13echo "Valeur: " . \asd\test_object::TEST_VALUE . "\n";
14test();
15class test_object {
16 const TEST_VALUE = "qwerty";
17 private $asd = "qwe";
18 public $qwe = 'bar';
19 private $test_asd = '';
20 function __construct($asd) {
21 $this->test_asd = $asd;
22 }
23 function do_a_barell_roll() {
24 var_dump($this->test_asd);
25 }
26}
27}
28?>
29--EXPECTF--
30Valeur: qwerty
31[snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'strlen' in %a/tests/disabled_function_local_var_7.php:%d has been disabled.
diff --git a/src/tests/disabled_function_local_var_8.phpt b/src/tests/disabled_function_local_var_8.phpt
new file mode 100644
index 0000000..475b472
--- /dev/null
+++ b/src/tests/disabled_function_local_var_8.phpt
@@ -0,0 +1,20 @@
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
9namespace qwe {
10 const ASD = 'qwerty';
11}
12namespace asd {
13 const asd = 'qwe';
14 echo "Valeur: " . \qwe\ASD . "\n";
15 strlen("qwe");
16}
17?>
18--EXPECTF--
19Valeur: qwerty
20[snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'strlen' in %a/tests/disabled_function_local_var_8.php:%d has been disabled.
diff --git a/src/tests/disabled_function_local_var_9.phpt b/src/tests/disabled_function_local_var_9.phpt
new file mode 100644
index 0000000..fb65bc4
--- /dev/null
+++ b/src/tests/disabled_function_local_var_9.phpt
@@ -0,0 +1,20 @@
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
9namespace qwe {
10 const QWE = Array('123'=>'asdfgh');
11}
12namespace asd {
13 const asd = 'qwe';
14 echo "Valeur: " . \qwe\QWE[123]. "\n";
15 strlen("qwe");
16}
17?>
18--EXPECTF--
19Valeur: asdfgh
20[snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'strlen' in %a/tests/disabled_function_local_var_9.php:%d has been disabled.
diff --git a/src/tests/disabled_function_local_var_obj.phpt b/src/tests/disabled_function_local_var_obj.phpt
new file mode 100644
index 0000000..868ea4c
--- /dev/null
+++ b/src/tests/disabled_function_local_var_obj.phpt
@@ -0,0 +1,25 @@
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_obj.ini
7--FILE--
8<?php
9class test_class {
10 public $qwe = 'value';
11 function __construct($arg, $value) {
12 $this->$arg = $value;
13 }
14}
15
16$test_array = ['qwe'];
17$arg = 'qwe';
18$test = new test_class('qwe', 'qwe');
19echo strlen($test->$arg) . "\n";
20$test = new test_class('qwe', 'nop_object');
21echo strlen($test->$arg) . "\n";
22?>
23--EXPECTF--
243
25[snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'strlen' in %a/tests/disabled_function_local_var_obj.php:%d has been disabled.
diff --git a/src/tests/disabled_functions_local_var_array.phpt b/src/tests/disabled_functions_local_var_array.phpt
new file mode 100644
index 0000000..2255cbf
--- /dev/null
+++ b/src/tests/disabled_functions_local_var_array.phpt
@@ -0,0 +1,20 @@
1--TEST--
2Disable functions - match on an array value buried in several levels
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/config_disabled_functions_local_var_array.ini
7--FILE--
8<?php
9function foo($arr) {
10 echo $arr["a"]."\n";
11}
12$a=Array("test2"=>Array("pof"=>"pif", "foo"=>Array("lol"=>"bbb")), "a"=>"cccc");
13foo($a);
14
15$a=Array("test2"=>Array("foo"=>Array("lol"=>"aaa")), "a"=>"dddd");
16foo($a);
17?>
18--EXPECTF--
19cccc
20[snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'foo' in %a/tests/disabled_functions_local_var_array.php:3 has been disabled.
diff --git a/src/tests/disabled_functions_local_var_array_key.phpt b/src/tests/disabled_functions_local_var_array_key.phpt
new file mode 100644
index 0000000..4014c05
--- /dev/null
+++ b/src/tests/disabled_functions_local_var_array_key.phpt
@@ -0,0 +1,20 @@
1--TEST--
2Disable functions - match on an array value buried in several levels
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/config_disabled_functions_local_var_array_key.ini
7--FILE--
8<?php
9function foo($arr) {
10 echo $arr["a"]."\n";
11}
12$a=Array("test2"=>Array("pof"=>"pif", "foo"=>Array("lol"=>"bbb")), "a"=>"cccc");
13foo($a);
14
15$a=Array("test2"=>Array("foo"=>Array("aaa"=>"ccc")), "a"=>"dddd");
16foo($a);
17?>
18--EXPECTF--
19cccc
20[snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'foo' in %a/tests/disabled_functions_local_var_array_key.php:3 has been disabled.
diff --git a/src/tests/disabled_functions_name_type.phpt b/src/tests/disabled_functions_name_type.phpt
index c5b24d6..1022238 100644
--- a/src/tests/disabled_functions_name_type.phpt
+++ b/src/tests/disabled_functions_name_type.phpt
@@ -11,4 +11,4 @@ echo strcmp([1,23], "pouet") . "\n";
11?> 11?>
12--EXPECTF-- 12--EXPECTF--
130 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. 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 (ARRAY) matched a rule.
diff --git a/src/tests/disabled_functions_nul_byte.phpt b/src/tests/disabled_functions_nul_byte.phpt
index b4974a9..f03a8e4 100644
--- a/src/tests/disabled_functions_nul_byte.phpt
+++ b/src/tests/disabled_functions_nul_byte.phpt
@@ -11,4 +11,4 @@ system("id");
11 11
12?> 12?>
13--EXPECTF-- 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. 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.
diff --git a/src/tests/disabled_functions_param.phpt b/src/tests/disabled_functions_param.phpt
index d9f8767..fe0e244 100644
--- a/src/tests/disabled_functions_param.phpt
+++ b/src/tests/disabled_functions_param.phpt
@@ -15,4 +15,4 @@ strcmp("bla", "ble");
15strncmp("bla", "ble", 2); 15strncmp("bla", "ble", 2);
16?> 16?>
17--EXPECTF-- 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'. 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'.
diff --git a/src/tests/disabled_functions_param_array.phpt b/src/tests/disabled_functions_param_array.phpt
index 5ca13aa..f023cfc 100644
--- a/src/tests/disabled_functions_param_array.phpt
+++ b/src/tests/disabled_functions_param_array.phpt
@@ -21,4 +21,4 @@ foo($a);
21--EXPECTF-- 21--EXPECTF--
22test1 22test1
23abcde 23abcde
24[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'. 24[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 (abcd) matched the rule '1'.
diff --git a/src/tests/disabled_functions_param_array_deref.phpt b/src/tests/disabled_functions_param_array_deref.phpt
index 556cb06..1e8e31b 100644
--- a/src/tests/disabled_functions_param_array_deref.phpt
+++ b/src/tests/disabled_functions_param_array_deref.phpt
@@ -22,4 +22,4 @@ foo($a);
22--EXPECTF-- 22--EXPECTF--
23eee 23eee
24abcdef 24abcdef
25[snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'foo' in %a/tests/disabled_functions_param_array_deref.php:3 has been disabled, because its argument 'arr' content (Array) matched the rule '2'. 25[snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'foo' in %a/tests/disabled_functions_param_array_deref.php:3 has been disabled, because its argument '$arr' content (abcdef) matched the rule '2'.
diff --git a/src/tests/disabled_functions_param_array_no_value.phpt b/src/tests/disabled_functions_param_array_no_value.phpt
index 06b9839..ac1b5e0 100644
--- a/src/tests/disabled_functions_param_array_no_value.phpt
+++ b/src/tests/disabled_functions_param_array_no_value.phpt
@@ -19,4 +19,4 @@ foo($a);
19?> 19?>
20--EXPECTF-- 20--EXPECTF--
21cccc 21cccc
22[snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'foo' in %a/tests/disabled_functions_param_array_no_value.php:3 has been disabled, because its argument 'arr' content (Array) matched the rule '3'. 22[snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'foo' in %a/tests/disabled_functions_param_array_no_value.php:3 has been disabled, because its argument '$arr' content (aaa) matched the rule '3'.
diff --git a/src/tests/disabled_functions_param_array_r.phpt b/src/tests/disabled_functions_param_array_r.phpt
new file mode 100644
index 0000000..8bd85ce
--- /dev/null
+++ b/src/tests/disabled_functions_param_array_r.phpt
@@ -0,0 +1,20 @@
1--TEST--
2Disable functions - match on an array using regexp
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/config_disabled_functions_param_r_array.ini
7--FILE--
8<?php
9function foo($arr) {
10 echo $arr["a"]."\n";
11}
12$a=Array("test2"=>"pof", "pof"=>"pif", "a"=>Array("qwe"=>"bbb"), "a"=>"cccc");
13foo($a);
14
15$a=Array("a"=>"abcd", "pof"=>"pif", "bar"=>Array("qwe"=>"bbb"), "b"=>"cccc");
16foo($a);
17?>
18--EXPECTF--
19cccc
20[snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'foo' in %a/tests/disabled_functions_param_array_r.php:3 has been disabled, because its argument 'arr' content (ARRAY) matched the rule '1'.
diff --git a/src/tests/disabled_functions_param_array_r_keys.phpt b/src/tests/disabled_functions_param_array_r_keys.phpt
new file mode 100644
index 0000000..e9ef50d
--- /dev/null
+++ b/src/tests/disabled_functions_param_array_r_keys.phpt
@@ -0,0 +1,20 @@
1--TEST--
2Disable functions - match on an array using regexp
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/config_disabled_functions_param_r_array.ini
7--FILE--
8<?php
9function foo($arr) {
10 echo $arr["a"]."\n";
11}
12$a=Array("test2"=>"pof", "pof"=>"pif", "qwe"=>Array("qwe"=>"bbb"), "a"=>"cccc");
13foo($a);
14
15$a=Array("a"=>"", "pof"=>"pif", "bar"=>Array("qwe"=>"bbb"), "qweabcqwe"=>"nop");
16foo($a);
17?>
18--EXPECTF--
19cccc
20[snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'foo' in %a/tests/disabled_functions_param_array_r_keys.php:3 has been disabled, because its argument 'arr' content (ARRAY) matched the rule '2'.
diff --git a/src/tests/disabled_functions_param_array_several_levels.phpt b/src/tests/disabled_functions_param_array_several_levels.phpt
index cef6ded..f5665fb 100644
--- a/src/tests/disabled_functions_param_array_several_levels.phpt
+++ b/src/tests/disabled_functions_param_array_several_levels.phpt
@@ -17,4 +17,4 @@ foo($a);
17?> 17?>
18--EXPECTF-- 18--EXPECTF--
19cccc 19cccc
20[snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'foo' in %a/tests/disabled_functions_param_array_several_levels.php:3 has been disabled, because its argument 'arr' content (Array) matched the rule '4'. 20[snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'foo' in %a/tests/disabled_functions_param_array_several_levels.php:3 has been disabled, because its argument '$arr' content (ARRAY) matched the rule '4'.
diff --git a/src/tests/disabled_functions_param_array_several_levels_int.phpt b/src/tests/disabled_functions_param_array_several_levels_int.phpt
new file mode 100644
index 0000000..2e546f4
--- /dev/null
+++ b/src/tests/disabled_functions_param_array_several_levels_int.phpt
@@ -0,0 +1,20 @@
1--TEST--
2Disable functions - match on an array value buried in several levels
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("test2"=>Array("pof"=>"pif", "foo"=>Array("lol"=>"bbb")), "a"=>"cccc");
13foo($a);
14
15$a=Array("test2"=>Array("foo"=>Array("123"=>"aaa")), "a"=>"dddd");
16foo($a);
17?>
18--EXPECTF--
19cccc
20[snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'foo' in %a/tests/disabled_functions_param_array_several_levels_int.php:3 has been disabled, because its argument '$arr' content (ARRAY) matched the rule '4'.
diff --git a/src/tests/disabled_functions_param_array_several_levels_keys.phpt b/src/tests/disabled_functions_param_array_several_levels_keys.phpt
new file mode 100644
index 0000000..1be59fc
--- /dev/null
+++ b/src/tests/disabled_functions_param_array_several_levels_keys.phpt
@@ -0,0 +1,20 @@
1--TEST--
2Disable functions - match on an array value buried in several levels
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("test2"=>Array("pof"=>"pif", "bar"=>Array("qwe"=>"bbb")), "a"=>"cccc");
13foo($a);
14
15$a=Array("test2"=>Array("bar"=>Array("lol"=>"aaa")), "a"=>"dddd");
16foo($a);
17?>
18--EXPECTF--
19cccc
20[snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'foo' in %a/tests/disabled_functions_param_array_several_levels_keys.php:3 has been disabled, because its argument '$arr' content (ARRAY) matched the rule '5'.
diff --git a/src/tests/disabled_functions_param_array_several_levels_keys_int.phpt b/src/tests/disabled_functions_param_array_several_levels_keys_int.phpt
new file mode 100644
index 0000000..acb696f
--- /dev/null
+++ b/src/tests/disabled_functions_param_array_several_levels_keys_int.phpt
@@ -0,0 +1,20 @@
1--TEST--
2Disable functions - match on an array value buried in several levels
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("test2"=>Array("pof"=>"pif", "bar"=>Array("qwe"=>"bbb")), "a"=>"cccc");
13foo($a);
14
15$a=Array("test2"=>Array("bar"=>Array("123"=>"aaa")), "a"=>"dddd");
16foo($a);
17?>
18--EXPECTF--
19cccc
20[snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'foo' in %a/tests/disabled_functions_param_array_several_levels_keys_int.php:3 has been disabled, because its argument '$arr' content (ARRAY) matched the rule '6'.
diff --git a/src/tests/disabled_functions_param_int.phpt b/src/tests/disabled_functions_param_int.phpt
index 0e6a62c..692009a 100644
--- a/src/tests/disabled_functions_param_int.phpt
+++ b/src/tests/disabled_functions_param_int.phpt
@@ -18,4 +18,4 @@ foobar("10");
18?> 18?>
19--EXPECTF-- 19--EXPECTF--
201 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. 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.
diff --git a/src/tests/disabled_functions_pos_type.phpt b/src/tests/disabled_functions_pos_type.phpt
new file mode 100644
index 0000000..7556440
--- /dev/null
+++ b/src/tests/disabled_functions_pos_type.phpt
@@ -0,0 +1,14 @@
1--TEST--
2Disable functions - match on argument's position
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/disabled_functions_pos.ini
7--FILE--
8<?php
9system([123, 456]);
10?>
11--EXPECTF--
12[snuffleupagus][0.0.0.0][config][error] It seems that you wrote a rule filtering on the 0th argument of the function 'system', but it takes only 2 arguments. Matching on _all_ arguments instead.
13[snuffleupagus][0.0.0.0][config][error] It seems that you wrote a rule filtering on the 1st argument of the function 'system', but it takes only 2 arguments. Matching on _all_ arguments instead.
14[snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'system' in %a/disabled_functions_pos_type.php:2 has been disabled, because its argument 'command' content (?) matched the rule '1'.
diff --git a/src/tests/disabled_functions_runtime.phpt b/src/tests/disabled_functions_runtime.phpt
index 1c6a141..1508735 100644
--- a/src/tests/disabled_functions_runtime.phpt
+++ b/src/tests/disabled_functions_runtime.phpt
@@ -23,7 +23,7 @@ test('1338');test('1337');
23?> 23?>
24--EXPECTF-- 24--EXPECTF--
251338 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. 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-- 27--CLEAN--
28<?php 28<?php
29unlink("file_to_include1.php"); 29unlink("file_to_include1.php");