summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThibault "bui" Koechlin2017-12-28 17:04:06 +0100
committerjvoisin2017-12-28 17:04:06 +0100
commit9f5e8d12f05fb24c915a5266a1e908a75c8aed08 (patch)
tree9160075ea943c7fd29a3923f844a0ac0d6b8b457
parent62c48bf9a85e0294b7b32cea438e904e1cd50669 (diff)
Clang-format pass
- `clang-format --style="{BasedOnStyle: google, SortIncludes: false}" -i snuffleu*.c sp_*.c sp_*.h` - Update the documentation accordingly
-rw-r--r--CONTRIBUTING.md2
-rw-r--r--src/snuffleupagus.c91
-rw-r--r--src/sp_config.c61
-rw-r--r--src/sp_config.h13
-rw-r--r--src/sp_config_keywords.c66
-rw-r--r--src/sp_config_keywords.h8
-rw-r--r--src/sp_config_utils.c14
-rw-r--r--src/sp_cookie_encryption.c79
-rw-r--r--src/sp_cookie_encryption.h3
-rw-r--r--src/sp_disabled_functions.c95
-rw-r--r--src/sp_disabled_functions.h5
-rw-r--r--src/sp_execute.c68
-rw-r--r--src/sp_list.c17
-rw-r--r--src/sp_list.h3
-rw-r--r--src/sp_network_utils.c6
-rw-r--r--src/sp_unserialize.c33
-rw-r--r--src/sp_upload_validation.c5
-rw-r--r--src/sp_upload_validation.h3
-rw-r--r--src/sp_utils.c132
-rw-r--r--src/sp_utils.h25
-rw-r--r--src/sp_var_parser.c102
-rw-r--r--src/sp_var_value.c102
22 files changed, 496 insertions, 437 deletions
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 34cfd02..f8e8f37 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -58,7 +58,7 @@ launching it, in order to run the failing test inside GDB.
58 58
59Your patch should follow the same conventions & pass the same code quality 59Your patch should follow the same conventions & pass the same code quality
60checks as the rest of the project. We're using [clang-format](http://clang.llvm.org/docs/ClangFormat.html) to 60checks as the rest of the project. We're using [clang-format](http://clang.llvm.org/docs/ClangFormat.html) to
61ensure a consistent code-style. Please run it with `clang-format -style=google` 61ensure a consistent code-style. Please run it with `clang-format --style="{BasedOnStyle: google, SortIncludes: false}"`
62before committing, or even better, use a [pre-commit hook](https://github.com/andrewseidl/githook-clang-format). 62before committing, or even better, use a [pre-commit hook](https://github.com/andrewseidl/githook-clang-format).
63 63
64### 6. Make a Pull Request 64### 6. Make a Pull Request
diff --git a/src/snuffleupagus.c b/src/snuffleupagus.c
index b823a87..dd2d941 100644
--- a/src/snuffleupagus.c
+++ b/src/snuffleupagus.c
@@ -30,7 +30,7 @@ ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus)
30 30
31PHP_INI_BEGIN() 31PHP_INI_BEGIN()
32PHP_INI_ENTRY("sp.configuration_file", "", PHP_INI_SYSTEM, 32PHP_INI_ENTRY("sp.configuration_file", "", PHP_INI_SYSTEM,
33 OnUpdateConfiguration) 33 OnUpdateConfiguration)
34PHP_INI_END() 34PHP_INI_END()
35 35
36ZEND_DLEXPORT zend_extension zend_extension_entry = { 36ZEND_DLEXPORT zend_extension zend_extension_entry = {
@@ -41,22 +41,22 @@ ZEND_DLEXPORT zend_extension zend_extension_entry = {
41 PHP_SNUFFLEUPAGUS_COPYRIGHT, 41 PHP_SNUFFLEUPAGUS_COPYRIGHT,
42 sp_zend_startup, 42 sp_zend_startup,
43 NULL, 43 NULL,
44 NULL, /* activate_func_t */ 44 NULL, /* activate_func_t */
45 NULL, /* deactivate_func_t */ 45 NULL, /* deactivate_func_t */
46 NULL, /* message_handler_func_t */ 46 NULL, /* message_handler_func_t */
47 sp_op_array_handler,//zend_global_strict, /* op_array_handler_func_t */ 47 sp_op_array_handler, // zend_global_strict, /* op_array_handler_func_t */
48 NULL, /* statement_handler_func_t */ 48 NULL, /* statement_handler_func_t */
49 NULL, /* fcall_begin_handler_func_t */ 49 NULL, /* fcall_begin_handler_func_t */
50 NULL, /* fcall_end_handler_func_t */ 50 NULL, /* fcall_end_handler_func_t */
51 NULL, /* op_array_ctor_func_t */ 51 NULL, /* op_array_ctor_func_t */
52 NULL, /* op_array_dtor_func_t */ 52 NULL, /* op_array_dtor_func_t */
53 STANDARD_ZEND_EXTENSION_PROPERTIES}; 53 STANDARD_ZEND_EXTENSION_PROPERTIES};
54 54
55PHP_GINIT_FUNCTION(snuffleupagus) { 55PHP_GINIT_FUNCTION(snuffleupagus) {
56#define SP_INIT(F) F = pecalloc(sizeof(*F), 1, 1); 56#define SP_INIT(F) F = pecalloc(sizeof(*F), 1, 1);
57#define SP_INIT_HT(F) \ 57#define SP_INIT_HT(F) \
58 F = pemalloc(sizeof(*F), 1); \ 58 F = pemalloc(sizeof(*F), 1); \
59 zend_hash_init(F, 10, NULL, NULL, 1); 59 zend_hash_init(F, 10, NULL, NULL, 1);
60 60
61 SP_INIT_HT(snuffleupagus_globals->disabled_functions_hook); 61 SP_INIT_HT(snuffleupagus_globals->disabled_functions_hook);
62 SP_INIT_HT(snuffleupagus_globals->sp_internal_functions_hook); 62 SP_INIT_HT(snuffleupagus_globals->sp_internal_functions_hook);
@@ -74,10 +74,14 @@ PHP_GINIT_FUNCTION(snuffleupagus) {
74 SP_INIT(snuffleupagus_globals->config.config_cookie); 74 SP_INIT(snuffleupagus_globals->config.config_cookie);
75 SP_INIT(snuffleupagus_globals->config.config_disabled_constructs); 75 SP_INIT(snuffleupagus_globals->config.config_disabled_constructs);
76 76
77 snuffleupagus_globals->config.config_disabled_constructs->construct_include = sp_list_new(); 77 snuffleupagus_globals->config.config_disabled_constructs->construct_include =
78 snuffleupagus_globals->config.config_disabled_constructs->construct_eval = sp_list_new(); 78 sp_list_new();
79 snuffleupagus_globals->config.config_disabled_functions->disabled_functions = sp_list_new(); 79 snuffleupagus_globals->config.config_disabled_constructs->construct_eval =
80 snuffleupagus_globals->config.config_disabled_functions_ret->disabled_functions = sp_list_new(); 80 sp_list_new();
81 snuffleupagus_globals->config.config_disabled_functions->disabled_functions =
82 sp_list_new();
83 snuffleupagus_globals->config.config_disabled_functions_ret
84 ->disabled_functions = sp_list_new();
81 snuffleupagus_globals->config.config_cookie->cookies = sp_list_new(); 85 snuffleupagus_globals->config.config_cookie->cookies = sp_list_new();
82 86
83#undef SP_INIT 87#undef SP_INIT
@@ -91,7 +95,7 @@ PHP_MINIT_FUNCTION(snuffleupagus) {
91} 95}
92 96
93PHP_MSHUTDOWN_FUNCTION(snuffleupagus) { 97PHP_MSHUTDOWN_FUNCTION(snuffleupagus) {
94#define FREE_HT(F) \ 98#define FREE_HT(F) \
95 zend_hash_destroy(SNUFFLEUPAGUS_G(F)); \ 99 zend_hash_destroy(SNUFFLEUPAGUS_G(F)); \
96 pefree(SNUFFLEUPAGUS_G(F), 1); 100 pefree(SNUFFLEUPAGUS_G(F), 1);
97 101
@@ -108,12 +112,12 @@ PHP_MSHUTDOWN_FUNCTION(snuffleupagus) {
108 pefree(SNUFFLEUPAGUS_G(config.config_disable_xxe), 1); 112 pefree(SNUFFLEUPAGUS_G(config.config_disable_xxe), 1);
109 pefree(SNUFFLEUPAGUS_G(config.config_upload_validation), 1); 113 pefree(SNUFFLEUPAGUS_G(config.config_upload_validation), 1);
110 114
111#define FREE_LST_DISABLE(L) \ 115#define FREE_LST_DISABLE(L) \
112 do { \ 116 do { \
113 sp_list_node* _n = SNUFFLEUPAGUS_G(L); \ 117 sp_list_node *_n = SNUFFLEUPAGUS_G(L); \
114 sp_disabled_function_list_free(_n); \ 118 sp_disabled_function_list_free(_n); \
115 sp_list_free(_n); \ 119 sp_list_free(_n); \
116 } while(0) 120 } while (0)
117 121
118 FREE_LST_DISABLE(config.config_disabled_functions->disabled_functions); 122 FREE_LST_DISABLE(config.config_disabled_functions->disabled_functions);
119 FREE_LST_DISABLE(config.config_disabled_functions_ret->disabled_functions); 123 FREE_LST_DISABLE(config.config_disabled_functions_ret->disabled_functions);
@@ -140,7 +144,7 @@ PHP_RINIT_FUNCTION(snuffleupagus) {
140 if (NULL != SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key) { 144 if (NULL != SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key) {
141 if (NULL != SNUFFLEUPAGUS_G(config).config_cookie->cookies) { 145 if (NULL != SNUFFLEUPAGUS_G(config).config_cookie->cookies) {
142 zend_hash_apply_with_arguments( 146 zend_hash_apply_with_arguments(
143 Z_ARRVAL(PG(http_globals)[TRACK_VARS_COOKIE]), decrypt_cookie, 0); 147 Z_ARRVAL(PG(http_globals)[TRACK_VARS_COOKIE]), decrypt_cookie, 0);
144 } 148 }
145 } 149 }
146 return SUCCESS; 150 return SUCCESS;
@@ -152,8 +156,9 @@ PHP_MINFO_FUNCTION(snuffleupagus) {
152 php_info_print_table_start(); 156 php_info_print_table_start();
153 php_info_print_table_row(2, "snuffleupagus support", "enabled"); 157 php_info_print_table_row(2, "snuffleupagus support", "enabled");
154 php_info_print_table_row(2, "Version", PHP_SNUFFLEUPAGUS_VERSION); 158 php_info_print_table_row(2, "Version", PHP_SNUFFLEUPAGUS_VERSION);
155 php_info_print_table_row(2, "Valid config", 159 php_info_print_table_row(
156 (SNUFFLEUPAGUS_G(is_config_valid) == true)?"yes":"no"); 160 2, "Valid config",
161 (SNUFFLEUPAGUS_G(is_config_valid) == true) ? "yes" : "no");
157 php_info_print_table_end(); 162 php_info_print_table_end();
158 DISPLAY_INI_ENTRIES(); 163 DISPLAY_INI_ENTRIES();
159} 164}
@@ -169,7 +174,7 @@ static PHP_INI_MH(OnUpdateConfiguration) {
169 174
170 config_file = strtok(new_value->val, ","); 175 config_file = strtok(new_value->val, ",");
171 if (sp_parse_config(config_file) != SUCCESS) { 176 if (sp_parse_config(config_file) != SUCCESS) {
172 SNUFFLEUPAGUS_G(is_config_valid) = false; 177 SNUFFLEUPAGUS_G(is_config_valid) = false;
173 return FAILURE; 178 return FAILURE;
174 } 179 }
175 while ((config_file = strtok(NULL, ","))) { 180 while ((config_file = strtok(NULL, ","))) {
@@ -214,21 +219,21 @@ static PHP_INI_MH(OnUpdateConfiguration) {
214 219
215const zend_function_entry snuffleupagus_functions[] = {PHP_FE_END}; 220const zend_function_entry snuffleupagus_functions[] = {PHP_FE_END};
216 221
217zend_module_entry snuffleupagus_module_entry = 222zend_module_entry snuffleupagus_module_entry = {
218 {STANDARD_MODULE_HEADER, 223 STANDARD_MODULE_HEADER,
219 PHP_SNUFFLEUPAGUS_EXTNAME, 224 PHP_SNUFFLEUPAGUS_EXTNAME,
220 snuffleupagus_functions, 225 snuffleupagus_functions,
221 PHP_MINIT(snuffleupagus), 226 PHP_MINIT(snuffleupagus),
222 PHP_MSHUTDOWN(snuffleupagus), 227 PHP_MSHUTDOWN(snuffleupagus),
223 PHP_RINIT(snuffleupagus), 228 PHP_RINIT(snuffleupagus),
224 PHP_RSHUTDOWN(snuffleupagus), 229 PHP_RSHUTDOWN(snuffleupagus),
225 PHP_MINFO(snuffleupagus), 230 PHP_MINFO(snuffleupagus),
226 PHP_SNUFFLEUPAGUS_VERSION, 231 PHP_SNUFFLEUPAGUS_VERSION,
227 PHP_MODULE_GLOBALS(snuffleupagus), 232 PHP_MODULE_GLOBALS(snuffleupagus),
228 PHP_GINIT(snuffleupagus), 233 PHP_GINIT(snuffleupagus),
229 NULL, 234 NULL,
230 NULL, 235 NULL,
231 STANDARD_MODULE_PROPERTIES_EX}; 236 STANDARD_MODULE_PROPERTIES_EX};
232 237
233#ifdef COMPILE_DL_SNUFFLEUPAGUS 238#ifdef COMPILE_DL_SNUFFLEUPAGUS
234#ifdef ZTS 239#ifdef ZTS
diff --git a/src/sp_config.c b/src/sp_config.c
index f1c7b65..aeadd9d 100644
--- a/src/sp_config.c
+++ b/src/sp_config.c
@@ -35,7 +35,8 @@ static int parse_line(char *line) {
35 } 35 }
36 36
37 if (strncmp(ptr, SP_TOKEN_BASE, strlen(SP_TOKEN_BASE))) { 37 if (strncmp(ptr, SP_TOKEN_BASE, strlen(SP_TOKEN_BASE))) {
38 sp_log_err("config", "Invalid configuration prefix for '%s' on line %zu.", line, sp_line_no); 38 sp_log_err("config", "Invalid configuration prefix for '%s' on line %zu.",
39 line, sp_line_no);
39 return -1; 40 return -1;
40 } 41 }
41 ptr += strlen(SP_TOKEN_BASE); 42 ptr += strlen(SP_TOKEN_BASE);
@@ -45,7 +46,8 @@ static int parse_line(char *line) {
45 return sp_func[i].func(ptr + strlen(sp_func[i].token)); 46 return sp_func[i].func(ptr + strlen(sp_func[i].token));
46 } 47 }
47 } 48 }
48 sp_log_err("config", "Invalid configuration section '%s' on line %zu.", line, sp_line_no); 49 sp_log_err("config", "Invalid configuration section '%s' on line %zu.", line,
50 sp_line_no);
49 return -1; 51 return -1;
50} 52}
51 53
@@ -60,32 +62,35 @@ int parse_php_type(char *restrict line, char *restrict keyword, void *retval) {
60 char *value = get_param(&consumed, line, SP_TYPE_STR, keyword); 62 char *value = get_param(&consumed, line, SP_TYPE_STR, keyword);
61 if (value) { 63 if (value) {
62 if (0 == strcasecmp("undef", value)) { 64 if (0 == strcasecmp("undef", value)) {
63 *(sp_php_type*)retval = SP_PHP_TYPE_UNDEF; 65 *(sp_php_type *)retval = SP_PHP_TYPE_UNDEF;
64 } else if (0 == strcasecmp("null", value)) { 66 } else if (0 == strcasecmp("null", value)) {
65 *(sp_php_type*)retval = SP_PHP_TYPE_NULL; 67 *(sp_php_type *)retval = SP_PHP_TYPE_NULL;
66 } else if (0 == strcasecmp("true", value)) { 68 } else if (0 == strcasecmp("true", value)) {
67 *(sp_php_type*)retval = SP_PHP_TYPE_TRUE; 69 *(sp_php_type *)retval = SP_PHP_TYPE_TRUE;
68 } else if (0 == strcasecmp("false", value)) { 70 } else if (0 == strcasecmp("false", value)) {
69 *(sp_php_type*)retval = SP_PHP_TYPE_FALSE; 71 *(sp_php_type *)retval = SP_PHP_TYPE_FALSE;
70 } else if (0 == strcasecmp("long", value)) { 72 } else if (0 == strcasecmp("long", value)) {
71 *(sp_php_type*)retval = SP_PHP_TYPE_LONG; 73 *(sp_php_type *)retval = SP_PHP_TYPE_LONG;
72 } else if (0 == strcasecmp("double", value)) { 74 } else if (0 == strcasecmp("double", value)) {
73 *(sp_php_type*)retval = SP_PHP_TYPE_DOUBLE; 75 *(sp_php_type *)retval = SP_PHP_TYPE_DOUBLE;
74 } else if (0 == strcasecmp("string", value)) { 76 } else if (0 == strcasecmp("string", value)) {
75 *(sp_php_type*)retval = SP_PHP_TYPE_STRING; 77 *(sp_php_type *)retval = SP_PHP_TYPE_STRING;
76 } else if (0 == strcasecmp("array", value)) { 78 } else if (0 == strcasecmp("array", value)) {
77 *(sp_php_type*)retval = SP_PHP_TYPE_ARRAY; 79 *(sp_php_type *)retval = SP_PHP_TYPE_ARRAY;
78 } else if (0 == strcasecmp("object", value)) { 80 } else if (0 == strcasecmp("object", value)) {
79 *(sp_php_type*)retval = SP_PHP_TYPE_OBJECT; 81 *(sp_php_type *)retval = SP_PHP_TYPE_OBJECT;
80 } else if (0 == strcasecmp("resource", value)) { 82 } else if (0 == strcasecmp("resource", value)) {
81 *(sp_php_type*)retval = SP_PHP_TYPE_RESOURCE; 83 *(sp_php_type *)retval = SP_PHP_TYPE_RESOURCE;
82 } else if (0 == strcasecmp("reference", value)) { 84 } else if (0 == strcasecmp("reference", value)) {
83 *(sp_php_type*)retval = SP_PHP_TYPE_REFERENCE; 85 *(sp_php_type *)retval = SP_PHP_TYPE_REFERENCE;
84 } else { 86 } else {
85 pefree(value, 1); 87 pefree(value, 1);
86 sp_log_err("error", "%s) is expecting a valid php type ('false', 'true'," 88 sp_log_err("error",
87 " 'array'. 'object', 'long', 'double', 'null', 'resource', 'reference'," 89 "%s) is expecting a valid php type ('false', 'true',"
88 " 'undef') on line %zu.", keyword, sp_line_no); 90 " 'array'. 'object', 'long', 'double', 'null', 'resource', "
91 "'reference',"
92 " 'undef') on line %zu.",
93 keyword, sp_line_no);
89 return -1; 94 return -1;
90 } 95 }
91 pefree(value, 1); 96 pefree(value, 1);
@@ -119,7 +124,8 @@ int parse_cidr(char *restrict line, char *restrict keyword, void *retval) {
119 *(sp_cidr **)retval = cidr; 124 *(sp_cidr **)retval = cidr;
120 return consumed; 125 return consumed;
121 } else { 126 } else {
122 sp_log_err("config", "%s doesn't contain a valid cidr on line %zu.", line, sp_line_no); 127 sp_log_err("config", "%s doesn't contain a valid cidr on line %zu.", line,
128 sp_line_no);
123 return -1; 129 return -1;
124 } 130 }
125} 131}
@@ -135,9 +141,10 @@ int parse_regexp(char *restrict line, char *restrict keyword, void *retval) {
135 const char *pcre_error; 141 const char *pcre_error;
136 int pcre_error_offset; 142 int pcre_error_offset;
137 pcre *compiled_re = sp_pcre_compile(value, PCRE_CASELESS, &pcre_error, 143 pcre *compiled_re = sp_pcre_compile(value, PCRE_CASELESS, &pcre_error,
138 &pcre_error_offset, NULL); 144 &pcre_error_offset, NULL);
139 if (NULL == compiled_re) { 145 if (NULL == compiled_re) {
140 sp_log_err("config", "Failed to compile '%s': %s on line %zu.", value, pcre_error, sp_line_no); 146 sp_log_err("config", "Failed to compile '%s': %s on line %zu.", value,
147 pcre_error, sp_line_no);
141 } else { 148 } else {
142 *(pcre **)retval = compiled_re; 149 *(pcre **)retval = compiled_re;
143 return consumed; 150 return consumed;
@@ -147,7 +154,8 @@ int parse_regexp(char *restrict line, char *restrict keyword, void *retval) {
147 if (NULL != closing_paren) { 154 if (NULL != closing_paren) {
148 closing_paren[0] = '\0'; 155 closing_paren[0] = '\0';
149 } 156 }
150 sp_log_err("config", "'%s)' is expecting a valid regexp, and not '%s' on line %zu.", 157 sp_log_err("config",
158 "'%s)' is expecting a valid regexp, and not '%s' on line %zu.",
151 keyword, line, sp_line_no); 159 keyword, line, sp_line_no);
152 return -1; 160 return -1;
153} 161}
@@ -183,12 +191,11 @@ int sp_parse_config(const char *conf_file) {
183 return SUCCESS; 191 return SUCCESS;
184} 192}
185 193
186void sp_disabled_function_list_free(sp_list_node* list) { 194void sp_disabled_function_list_free(sp_list_node *list) {
187 sp_list_node* cursor = list; 195 sp_list_node *cursor = list;
188 while(cursor) { 196 while (cursor) {
189 sp_disabled_function* df = cursor->data; 197 sp_disabled_function *df = cursor->data;
190 if (df && df->functions_list) 198 if (df && df->functions_list) sp_list_free(df->functions_list);
191 sp_list_free(df->functions_list);
192 if (df) { 199 if (df) {
193 sp_tree_free(df->param); 200 sp_tree_free(df->param);
194 sp_tree_free(df->var); 201 sp_tree_free(df->var);
diff --git a/src/sp_config.h b/src/sp_config.h
index aca9ff6..2417cf9 100644
--- a/src/sp_config.h
+++ b/src/sp_config.h
@@ -43,8 +43,8 @@ typedef struct {
43} sp_config_global; 43} sp_config_global;
44 44
45typedef struct { 45typedef struct {
46 bool enable; 46 bool enable;
47 bool simulation; 47 bool simulation;
48} sp_config_readonly_exec; 48} sp_config_readonly_exec;
49 49
50typedef struct { bool enable; } sp_config_global_strict; 50typedef struct { bool enable; } sp_config_global_strict;
@@ -56,7 +56,7 @@ typedef struct { bool enable; } sp_config_auto_cookie_secure;
56typedef struct { bool enable; } sp_config_disable_xxe; 56typedef struct { bool enable; } sp_config_disable_xxe;
57 57
58typedef struct { 58typedef struct {
59 enum samesite_type {strict=1, lax=2} samesite; 59 enum samesite_type { strict = 1, lax = 2 } samesite;
60 bool encrypt; 60 bool encrypt;
61 char *name; 61 char *name;
62 pcre *name_r; 62 pcre *name_r;
@@ -116,11 +116,12 @@ typedef struct {
116} sp_config_disabled_functions; 116} sp_config_disabled_functions;
117 117
118typedef struct { 118typedef struct {
119 sp_list_node *cookies; //list of sp_cookie for regexp/names 119 sp_list_node *cookies; // list of sp_cookie for regexp/names
120} sp_config_cookie; 120} sp_config_cookie;
121 121
122typedef struct { 122typedef struct {
123 sp_list_node *construct_include; // list of rules for `(include|require)_(once)?` 123 sp_list_node
124 *construct_include; // list of rules for `(include|require)_(once)?`
124 sp_list_node *construct_eval; 125 sp_list_node *construct_eval;
125 sp_list_node *construct_echo; 126 sp_list_node *construct_echo;
126} sp_config_disabled_constructs; 127} sp_config_disabled_constructs;
@@ -231,6 +232,6 @@ int parse_cidr(char *restrict, char *restrict, void *);
231int parse_php_type(char *restrict, char *restrict, void *); 232int parse_php_type(char *restrict, char *restrict, void *);
232 233
233// cleanup 234// cleanup
234void sp_disabled_function_list_free(sp_list_node*); 235void sp_disabled_function_list_free(sp_list_node *);
235 236
236#endif /* SP_CONFIG_H */ 237#endif /* SP_CONFIG_H */
diff --git a/src/sp_config_keywords.c b/src/sp_config_keywords.c
index b3e71fe..998b692 100644
--- a/src/sp_config_keywords.c
+++ b/src/sp_config_keywords.c
@@ -108,12 +108,12 @@ int parse_cookie(char *line) {
108 sp_cookie *cookie = pecalloc(sizeof(sp_cookie), 1, 1); 108 sp_cookie *cookie = pecalloc(sizeof(sp_cookie), 1, 1);
109 109
110 sp_config_functions sp_config_funcs_cookie_encryption[] = { 110 sp_config_functions sp_config_funcs_cookie_encryption[] = {
111 {parse_str, SP_TOKEN_NAME, &(cookie->name)}, 111 {parse_str, SP_TOKEN_NAME, &(cookie->name)},
112 {parse_regexp, SP_TOKEN_NAME_REGEXP, &(cookie->name_r)}, 112 {parse_regexp, SP_TOKEN_NAME_REGEXP, &(cookie->name_r)},
113 {parse_str, SP_TOKEN_SAMESITE, &samesite}, 113 {parse_str, SP_TOKEN_SAMESITE, &samesite},
114 {parse_empty, SP_TOKEN_ENCRYPT, &cookie->encrypt}, 114 {parse_empty, SP_TOKEN_ENCRYPT, &cookie->encrypt},
115 {parse_empty, SP_TOKEN_SIMULATION, &cookie->simulation}, 115 {parse_empty, SP_TOKEN_SIMULATION, &cookie->simulation},
116 {0}}; 116 {0}};
117 117
118 ret = parse_keywords(sp_config_funcs_cookie_encryption, line); 118 ret = parse_keywords(sp_config_funcs_cookie_encryption, line);
119 if (0 != ret) { 119 if (0 != ret) {
@@ -122,18 +122,21 @@ int parse_cookie(char *line) {
122 122
123 if (cookie->encrypt) { 123 if (cookie->encrypt) {
124 if (0 == (SNUFFLEUPAGUS_G(config).config_snuffleupagus->cookies_env_var)) { 124 if (0 == (SNUFFLEUPAGUS_G(config).config_snuffleupagus->cookies_env_var)) {
125 sp_log_err("config", 125 sp_log_err(
126 "You're trying to use the cookie encryption feature" 126 "config",
127 "on line %zu without having set the `.cookie_env_var` option in" 127 "You're trying to use the cookie encryption feature"
128 "`sp.global`: please set it first.", 128 "on line %zu without having set the `.cookie_env_var` option in"
129 "`sp.global`: please set it first.",
129 sp_line_no); 130 sp_line_no);
130 return -1; 131 return -1;
131 } else if (0 == (SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key)) { 132 } else if (0 ==
132 sp_log_err("config", 133 (SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key)) {
133 "You're trying to use the cookie encryption feature" 134 sp_log_err(
134 "on line %zu without having set the `.encryption_key` option in" 135 "config",
135 "`sp.global`: please set it first.", 136 "You're trying to use the cookie encryption feature"
136 sp_line_no); 137 "on line %zu without having set the `.encryption_key` option in"
138 "`sp.global`: please set it first.",
139 sp_line_no);
137 return -1; 140 return -1;
138 } 141 }
139 } else if (!samesite) { 142 } else if (!samesite) {
@@ -163,16 +166,16 @@ int parse_cookie(char *line) {
163 } else if (0 == strcasecmp(samesite, SP_TOKEN_SAMESITE_STRICT)) { 166 } else if (0 == strcasecmp(samesite, SP_TOKEN_SAMESITE_STRICT)) {
164 cookie->samesite = strict; 167 cookie->samesite = strict;
165 } else { 168 } else {
166 sp_log_err("config", 169 sp_log_err(
167 "%s is an invalid value to samesite (expected %s or %s) on line " 170 "config",
168 "%zu.", 171 "%s is an invalid value to samesite (expected %s or %s) on line "
169 samesite, SP_TOKEN_SAMESITE_LAX, SP_TOKEN_SAMESITE_STRICT, 172 "%zu.",
170 sp_line_no); 173 samesite, SP_TOKEN_SAMESITE_LAX, SP_TOKEN_SAMESITE_STRICT,
174 sp_line_no);
171 return -1; 175 return -1;
172 } 176 }
173 } 177 }
174 sp_list_insert(SNUFFLEUPAGUS_G(config).config_cookie->cookies, 178 sp_list_insert(SNUFFLEUPAGUS_G(config).config_cookie->cookies, cookie);
175 cookie);
176 return SUCCESS; 179 return SUCCESS;
177} 180}
178 181
@@ -235,8 +238,8 @@ int parse_disabled_functions(char *line) {
235 MUTUALLY_EXCLUSIVE(df->key, df->r_key, "r_key", "key"); 238 MUTUALLY_EXCLUSIVE(df->key, df->r_key, "r_key", "key");
236#undef MUTUALLY_EXCLUSIVE 239#undef MUTUALLY_EXCLUSIVE
237 240
238 if (1 < ((df->r_param ? 1 : 0) + (param ? 1 : 0) + 241 if (1 <
239 ((-1 != df->pos) ? 1 : 0))) { 242 ((df->r_param ? 1 : 0) + (param ? 1 : 0) + ((-1 != df->pos) ? 1 : 0))) {
240 sp_log_err( 243 sp_log_err(
241 "config", 244 "config",
242 "Invalid configuration line: 'sp.disabled_functions%s':" 245 "Invalid configuration line: 'sp.disabled_functions%s':"
@@ -306,8 +309,8 @@ int parse_disabled_functions(char *line) {
306 if (param) { 309 if (param) {
307 df->param = parse_var(param); 310 df->param = parse_var(param);
308 if (!df->param) { 311 if (!df->param) {
309 sp_log_err("config", "Invalid value '%s' for `param` on line %zu.", 312 sp_log_err("config", "Invalid value '%s' for `param` on line %zu.", param,
310 param, sp_line_no); 313 sp_line_no);
311 return -1; 314 return -1;
312 } 315 }
313 } 316 }
@@ -316,13 +319,12 @@ int parse_disabled_functions(char *line) {
316 if (*var) { 319 if (*var) {
317 df->var = parse_var(var); 320 df->var = parse_var(var);
318 if (!df->var) { 321 if (!df->var) {
319 sp_log_err("config", "Invalid value '%s' for `var` on line %zu.", 322 sp_log_err("config", "Invalid value '%s' for `var` on line %zu.", var,
320 var, sp_line_no); 323 sp_line_no);
321 return -1; 324 return -1;
322 } 325 }
323 } else { 326 } else {
324 sp_log_err("config", "Empty value in `var` on line %zu.", 327 sp_log_err("config", "Empty value in `var` on line %zu.", sp_line_no);
325 sp_line_no);
326 return -1; 328 return -1;
327 } 329 }
328 } 330 }
diff --git a/src/sp_config_keywords.h b/src/sp_config_keywords.h
index fdea1c5..8286997 100644
--- a/src/sp_config_keywords.h
+++ b/src/sp_config_keywords.h
@@ -6,11 +6,11 @@ int parse_random(char *line);
6int parse_disable_xxe(char *line); 6int parse_disable_xxe(char *line);
7int parse_auto_cookie_secure(char *line); 7int parse_auto_cookie_secure(char *line);
8int parse_global_strict(char *line); 8int parse_global_strict(char *line);
9int parse_global(char *line) ; 9int parse_global(char *line);
10int parse_cookie(char *line); 10int parse_cookie(char *line);
11int parse_unserialize(char *line) ; 11int parse_unserialize(char *line);
12int parse_readonly_exec(char *line); 12int parse_readonly_exec(char *line);
13int parse_disabled_functions(char *line) ; 13int parse_disabled_functions(char *line);
14int parse_upload_validation(char *line); 14int parse_upload_validation(char *line);
15 15
16#endif // __SP_CONFIG_KEYWORDS_H 16#endif // __SP_CONFIG_KEYWORDS_H
diff --git a/src/sp_config_utils.c b/src/sp_config_utils.c
index bf558d4..20d4d79 100644
--- a/src/sp_config_utils.c
+++ b/src/sp_config_utils.c
@@ -26,14 +26,14 @@ int parse_keywords(sp_config_functions *funcs, char *line) {
26 26
27 if (*line) { 27 if (*line) {
28 sp_log_err("config", "Trailing chars '%s' at the end of '%s' on line %zu.", 28 sp_log_err("config", "Trailing chars '%s' at the end of '%s' on line %zu.",
29 line, original_line, sp_line_no); 29 line, original_line, sp_line_no);
30 return -1; 30 return -1;
31 } 31 }
32 return 0; 32 return 0;
33} 33}
34 34
35char *get_param(size_t *consumed, char *restrict line, sp_type type, 35char *get_param(size_t *consumed, char *restrict line, sp_type type,
36 const char *restrict keyword) { 36 const char *restrict keyword) {
37 enum { IN_ESCAPE, NONE } state = NONE; 37 enum { IN_ESCAPE, NONE } state = NONE;
38 char *original_line = line; 38 char *original_line = line;
39 size_t j = 0; 39 size_t j = 0;
@@ -86,10 +86,12 @@ char *get_param(size_t *consumed, char *restrict line, sp_type type,
86 } 86 }
87err: 87err:
88 if (0 == j) { 88 if (0 == j) {
89 sp_log_err("error", "A valid string as parameter is expected on line %zu.", sp_line_no); 89 sp_log_err("error", "A valid string as parameter is expected on line %zu.",
90 sp_line_no);
90 } else { 91 } else {
91 sp_log_err("error", 92 sp_log_err("error",
92 "There is an issue with the parsing of '%s': it doesn't look like a valid string on line %zu.", 93 "There is an issue with the parsing of '%s': it doesn't look "
94 "like a valid string on line %zu.",
93 original_line ? original_line : "NULL", sp_line_no); 95 original_line ? original_line : "NULL", sp_line_no);
94 } 96 }
95 line = NULL; 97 line = NULL;
@@ -104,8 +106,8 @@ zend_always_inline sp_list_node *parse_functions_list(char *value) {
104 } 106 }
105 107
106 sp_list_node *list = sp_list_new(); 108 sp_list_node *list = sp_list_new();
107 char* tmp = strdup(value); 109 char *tmp = strdup(value);
108 char* function_name; 110 char *function_name;
109 char *next_token = tmp; 111 char *next_token = tmp;
110 while ((function_name = strtok_r(NULL, sep, &next_token))) { 112 while ((function_name = strtok_r(NULL, sep, &next_token))) {
111 sp_list_prepend(list, strdup(function_name)); 113 sp_list_prepend(list, strdup(function_name));
diff --git a/src/sp_cookie_encryption.c b/src/sp_cookie_encryption.c
index 4e9818f..6abc20a 100644
--- a/src/sp_cookie_encryption.c
+++ b/src/sp_cookie_encryption.c
@@ -10,12 +10,12 @@ static inline void generate_key(unsigned char *key) {
10 PHP_SHA256_CTX ctx; 10 PHP_SHA256_CTX ctx;
11 const char *user_agent = getenv("HTTP_USER_AGENT"); 11 const char *user_agent = getenv("HTTP_USER_AGENT");
12 const char *env_var = 12 const char *env_var =
13 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
17 assert(32 == crypto_secretbox_KEYBYTES); // 32 is the size of a SHA256. 17 assert(32 == crypto_secretbox_KEYBYTES); // 32 is the size of a SHA256.
18 assert(encryption_key); // Encryption key can't be NULL 18 assert(encryption_key); // Encryption key can't be NULL
19 19
20 PHP_SHA256Init(&ctx); 20 PHP_SHA256Init(&ctx);
21 21
@@ -24,11 +24,12 @@ static inline void generate_key(unsigned char *key) {
24 } 24 }
25 25
26 if (env_var) { 26 if (env_var) {
27 PHP_SHA256Update(&ctx, (unsigned char*)env_var, strlen(env_var)); 27 PHP_SHA256Update(&ctx, (unsigned char *)env_var, strlen(env_var));
28 } else { 28 } else {
29 sp_log_err("cookie_encryption", "The environment variable '%s'" 29 sp_log_err("cookie_encryption",
30 "is empty, cookies are weakly encrypted.", 30 "The environment variable '%s'"
31 SNUFFLEUPAGUS_G(config).config_snuffleupagus->cookies_env_var); 31 "is empty, cookies are weakly encrypted.",
32 SNUFFLEUPAGUS_G(config).config_snuffleupagus->cookies_env_var);
32 } 33 }
33 34
34 if (encryption_key) { 35 if (encryption_key) {
@@ -41,9 +42,9 @@ static inline void generate_key(unsigned char *key) {
41 42
42static inline const sp_cookie *sp_lookup_cookie_config(const char *key) { 43static inline const sp_cookie *sp_lookup_cookie_config(const char *key) {
43 sp_list_node *it = SNUFFLEUPAGUS_G(config).config_cookie->cookies; 44 sp_list_node *it = SNUFFLEUPAGUS_G(config).config_cookie->cookies;
44 45
45 while (it) { 46 while (it) {
46 const sp_cookie *config = it->data; 47 const sp_cookie *config = it->data;
47 if (config && sp_match_value(key, config->name, config->name_r)) { 48 if (config && sp_match_value(key, config->name, config->name_r)) {
48 return config; 49 return config;
49 } 50 }
@@ -60,7 +61,7 @@ int decrypt_cookie(zval *pDest, int num_args, va_list args,
60 unsigned char *decrypted; 61 unsigned char *decrypted;
61 const sp_cookie *cookie = sp_lookup_cookie_config(ZSTR_VAL(hash_key->key)); 62 const sp_cookie *cookie = sp_lookup_cookie_config(ZSTR_VAL(hash_key->key));
62 int ret = 0; 63 int ret = 0;
63 64
64 /* If the cookie isn't in the conf, it shouldn't be encrypted. */ 65 /* If the cookie isn't in the conf, it shouldn't be encrypted. */
65 if (!cookie || !cookie->encrypt) { 66 if (!cookie || !cookie->encrypt) {
66 return ZEND_HASH_APPLY_KEEP; 67 return ZEND_HASH_APPLY_KEEP;
@@ -72,18 +73,20 @@ int decrypt_cookie(zval *pDest, int num_args, va_list args,
72 } 73 }
73 74
74 debase64 = php_base64_decode((unsigned char *)(Z_STRVAL_P(pDest)), 75 debase64 = php_base64_decode((unsigned char *)(Z_STRVAL_P(pDest)),
75 Z_STRLEN_P(pDest)); 76 Z_STRLEN_P(pDest));
76 77
77 if (ZSTR_LEN(debase64) < 78 if (ZSTR_LEN(debase64) <
78 crypto_secretbox_NONCEBYTES + crypto_secretbox_ZEROBYTES) { 79 crypto_secretbox_NONCEBYTES + crypto_secretbox_ZEROBYTES) {
79 if (true == cookie->simulation) { 80 if (true == cookie->simulation) {
80 sp_log_msg("cookie_encryption", SP_LOG_SIMULATION, 81 sp_log_msg(
82 "cookie_encryption", SP_LOG_SIMULATION,
81 "Buffer underflow tentative detected in cookie encryption handling " 83 "Buffer underflow tentative detected in cookie encryption handling "
82 "for %s. Using the cookie 'as it' instead of decrypting it.", 84 "for %s. Using the cookie 'as it' instead of decrypting it.",
83 ZSTR_VAL(hash_key->key)); 85 ZSTR_VAL(hash_key->key));
84 return ZEND_HASH_APPLY_KEEP; 86 return ZEND_HASH_APPLY_KEEP;
85 } else { 87 } else {
86 sp_log_msg("cookie_encryption", SP_LOG_DROP, 88 sp_log_msg(
89 "cookie_encryption", SP_LOG_DROP,
87 "Buffer underflow tentative detected in cookie encryption handling."); 90 "Buffer underflow tentative detected in cookie encryption handling.");
88 return ZEND_HASH_APPLY_REMOVE; 91 return ZEND_HASH_APPLY_REMOVE;
89 } 92 }
@@ -101,14 +104,16 @@ int decrypt_cookie(zval *pDest, int num_args, va_list args,
101 104
102 if (-1 == ret) { 105 if (-1 == ret) {
103 if (true == cookie->simulation) { 106 if (true == cookie->simulation) {
104 sp_log_msg("cookie_encryption", SP_LOG_SIMULATION, 107 sp_log_msg(
105 "Something went wrong with the decryption of %s. Using the cookie " 108 "cookie_encryption", SP_LOG_SIMULATION,
106 "'as it' instead of decrypting it", ZSTR_VAL(hash_key->key)); 109 "Something went wrong with the decryption of %s. Using the cookie "
110 "'as it' instead of decrypting it",
111 ZSTR_VAL(hash_key->key));
107 return ZEND_HASH_APPLY_KEEP; 112 return ZEND_HASH_APPLY_KEEP;
108 } else { 113 } else {
109 sp_log_msg("cookie_encryption", SP_LOG_DROP, 114 sp_log_msg("cookie_encryption", SP_LOG_DROP,
110 "Something went wrong with the decryption of %s.", 115 "Something went wrong with the decryption of %s.",
111 ZSTR_VAL(hash_key->key)); 116 ZSTR_VAL(hash_key->key));
112 return ZEND_HASH_APPLY_REMOVE; 117 return ZEND_HASH_APPLY_REMOVE;
113 } 118 }
114 } 119 }
@@ -127,7 +132,8 @@ int decrypt_cookie(zval *pDest, int num_args, va_list args,
127*/ 132*/
128static zend_string *encrypt_data(char *data, unsigned long long data_len) { 133static zend_string *encrypt_data(char *data, unsigned long long data_len) {
129 const size_t encrypted_msg_len = crypto_secretbox_ZEROBYTES + data_len + 1; 134 const size_t encrypted_msg_len = crypto_secretbox_ZEROBYTES + data_len + 1;
130 const size_t emsg_and_nonce_len = encrypted_msg_len + crypto_secretbox_NONCEBYTES; 135 const size_t emsg_and_nonce_len =
136 encrypted_msg_len + crypto_secretbox_NONCEBYTES;
131 137
132 unsigned char key[crypto_secretbox_KEYBYTES] = {0}; 138 unsigned char key[crypto_secretbox_KEYBYTES] = {0};
133 unsigned char nonce[crypto_secretbox_NONCEBYTES] = {0}; 139 unsigned char nonce[crypto_secretbox_NONCEBYTES] = {0};
@@ -149,7 +155,7 @@ static zend_string *encrypt_data(char *data, unsigned long long data_len) {
149 } 155 }
150 } 156 }
151 nonce_d++; 157 nonce_d++;
152 sscanf((char*)nonce, "%ld", &nonce_d); 158 sscanf((char *)nonce, "%ld", &nonce_d);
153 159
154 memcpy(encrypted_data, nonce, crypto_secretbox_NONCEBYTES); 160 memcpy(encrypted_data, nonce, crypto_secretbox_NONCEBYTES);
155 crypto_secretbox(encrypted_data + crypto_secretbox_NONCEBYTES, 161 crypto_secretbox(encrypted_data + crypto_secretbox_NONCEBYTES,
@@ -161,15 +167,15 @@ static zend_string *encrypt_data(char *data, unsigned long long data_len) {
161} 167}
162 168
163PHP_FUNCTION(sp_setcookie) { 169PHP_FUNCTION(sp_setcookie) {
164 zval params[7] = { 0 }; 170 zval params[7] = {0};
165 zend_string *name = NULL, *value = NULL, *path = NULL, *domain = NULL, *samesite = NULL; 171 zend_string *name = NULL, *value = NULL, *path = NULL, *domain = NULL,
172 *samesite = NULL;
166 zend_long expires = 0; 173 zend_long expires = 0;
167 zend_bool secure = 0, httponly = 0; 174 zend_bool secure = 0, httponly = 0;
168 const sp_cookie *cookie_node = NULL; 175 const sp_cookie *cookie_node = NULL;
169 zval func_name; 176 zval func_name;
170 char *cookie_samesite; 177 char *cookie_samesite;
171 178
172
173 // LCOV_EXCL_BR_START 179 // LCOV_EXCL_BR_START
174 ZEND_PARSE_PARAMETERS_START(1, 7) 180 ZEND_PARSE_PARAMETERS_START(1, 7)
175 Z_PARAM_STR(name) 181 Z_PARAM_STR(name)
@@ -197,7 +203,7 @@ PHP_FUNCTION(sp_setcookie) {
197 203
198 /* lookup existing configuration for said cookie */ 204 /* lookup existing configuration for said cookie */
199 cookie_node = sp_lookup_cookie_config(ZSTR_VAL(name)); 205 cookie_node = sp_lookup_cookie_config(ZSTR_VAL(name));
200 206
201 /* If the cookie's value is encrypted, it won't be usable by 207 /* If the cookie's value is encrypted, it won't be usable by
202 * javascript anyway. 208 * javascript anyway.
203 */ 209 */
@@ -233,12 +239,15 @@ PHP_FUNCTION(sp_setcookie) {
233 if (!path) { 239 if (!path) {
234 path = zend_string_init("", 0, 0); 240 path = zend_string_init("", 0, 0);
235 } 241 }
236 cookie_samesite = (cookie_node->samesite == lax) ? SAMESITE_COOKIE_FORMAT SP_TOKEN_SAMESITE_LAX 242 cookie_samesite = (cookie_node->samesite == lax)
237 : SAMESITE_COOKIE_FORMAT SP_TOKEN_SAMESITE_STRICT; 243 ? SAMESITE_COOKIE_FORMAT SP_TOKEN_SAMESITE_LAX
244 : SAMESITE_COOKIE_FORMAT SP_TOKEN_SAMESITE_STRICT;
238 /* Concatenating everything, as is in PHP internals */ 245 /* Concatenating everything, as is in PHP internals */
239 samesite = zend_string_init(ZSTR_VAL(path), ZSTR_LEN(path), 0); 246 samesite = zend_string_init(ZSTR_VAL(path), ZSTR_LEN(path), 0);
240 samesite = zend_string_extend(samesite, ZSTR_LEN(path) + strlen(cookie_samesite) + 1, 0); 247 samesite = zend_string_extend(
241 memcpy(ZSTR_VAL(samesite) + ZSTR_LEN(path), cookie_samesite, strlen(cookie_samesite) + 1); 248 samesite, ZSTR_LEN(path) + strlen(cookie_samesite) + 1, 0);
249 memcpy(ZSTR_VAL(samesite) + ZSTR_LEN(path), cookie_samesite,
250 strlen(cookie_samesite) + 1);
242 ZVAL_STR_COPY(&params[3], samesite); 251 ZVAL_STR_COPY(&params[3], samesite);
243 } else if (path) { 252 } else if (path) {
244 ZVAL_STR_COPY(&params[3], path); 253 ZVAL_STR_COPY(&params[3], path);
@@ -250,20 +259,22 @@ PHP_FUNCTION(sp_setcookie) {
250 This is why were replacing our hook with the original function, calling 259 This is why were replacing our hook with the original function, calling
251 the function, and then re-hooking it. */ 260 the function, and then re-hooking it. */
252 void (*handler)(INTERNAL_FUNCTION_PARAMETERS); 261 void (*handler)(INTERNAL_FUNCTION_PARAMETERS);
253 handler = zend_hash_str_find_ptr(SNUFFLEUPAGUS_G(sp_internal_functions_hook), "setcookie", 262 handler = zend_hash_str_find_ptr(SNUFFLEUPAGUS_G(sp_internal_functions_hook),
254 strlen("setcookie")); 263 "setcookie", strlen("setcookie"));
255 zend_internal_function *func = zend_hash_str_find_ptr( 264 zend_internal_function *func = zend_hash_str_find_ptr(
256 CG(function_table), "setcookie", strlen("setcookie")); 265 CG(function_table), "setcookie", strlen("setcookie"));
257 func->handler = handler; 266 func->handler = handler;
258 267
259 call_user_function(CG(function_table), NULL, &func_name, return_value, 7, params); 268 call_user_function(CG(function_table), NULL, &func_name, return_value, 7,
269 params);
260 270
261 func->handler = PHP_FN(sp_setcookie); 271 func->handler = PHP_FN(sp_setcookie);
262 RETURN_TRUE; 272 RETURN_TRUE;
263} 273}
264 274
265int hook_cookies() { 275int hook_cookies() {
266 HOOK_FUNCTION("setcookie", sp_internal_functions_hook, PHP_FN(sp_setcookie), false); 276 HOOK_FUNCTION("setcookie", sp_internal_functions_hook, PHP_FN(sp_setcookie),
277 false);
267 278
268 return SUCCESS; 279 return SUCCESS;
269} 280}
diff --git a/src/sp_cookie_encryption.h b/src/sp_cookie_encryption.h
index 889a89c..6d204bb 100644
--- a/src/sp_cookie_encryption.h
+++ b/src/sp_cookie_encryption.h
@@ -14,6 +14,7 @@
14#define SAMESITE_COOKIE_FORMAT "; samesite=" 14#define SAMESITE_COOKIE_FORMAT "; samesite="
15 15
16int hook_cookies(); 16int hook_cookies();
17int decrypt_cookie(zval *pDest, int num_args, va_list args, zend_hash_key *hash_key); 17int decrypt_cookie(zval *pDest, int num_args, va_list args,
18 zend_hash_key *hash_key);
18 19
19#endif /* __SP_COOKIE_ENCRYPTION */ 20#endif /* __SP_COOKIE_ENCRYPTION */
diff --git a/src/sp_disabled_functions.c b/src/sp_disabled_functions.c
index 9736d2b..9382b09 100644
--- a/src/sp_disabled_functions.c
+++ b/src/sp_disabled_functions.c
@@ -64,25 +64,25 @@ 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 zval *var_value; 67 zval* var_value;
68 68
69 var_value = get_value(execute_data, config_node->var, false); 69 var_value = get_value(execute_data, config_node->var, false);
70 if (var_value) { 70 if (var_value) {
71 char *var_value_str = sp_convert_to_string(var_value); 71 char* var_value_str = sp_convert_to_string(var_value);
72 if (Z_TYPE_P(var_value) == IS_ARRAY) { 72 if (Z_TYPE_P(var_value) == IS_ARRAY) {
73 if (config_node->key || config_node->r_key) { 73 if (config_node->key || config_node->r_key) {
74 if (sp_match_array_key(var_value, config_node->key, 74 if (sp_match_array_key(var_value, config_node->key,
75 config_node->r_key)) { 75 config_node->r_key)) {
76 efree(var_value_str); 76 efree(var_value_str);
77 return true; 77 return true;
78 } 78 }
79 } else if (sp_match_array_value(var_value, config_node->value, 79 } else if (sp_match_array_value(var_value, config_node->value,
80 config_node->value_r)) { 80 config_node->value_r)) {
81 efree(var_value_str); 81 efree(var_value_str);
82 return true; 82 return true;
83 } 83 }
84 } else if (sp_match_value(var_value_str, config_node->value, 84 } else if (sp_match_value(var_value_str, config_node->value,
85 config_node->value_r)) { 85 config_node->value_r)) {
86 efree(var_value_str); 86 efree(var_value_str);
87 return true; 87 return true;
88 } 88 }
@@ -115,7 +115,7 @@ static bool is_param_matching(zend_execute_data* execute_data,
115 const char** arg_value_str) { 115 const char** arg_value_str) {
116 int nb_param = execute_data->func->common.num_args; 116 int nb_param = execute_data->func->common.num_args;
117 int i = 0; 117 int i = 0;
118 zval *arg_value; 118 zval* arg_value;
119 119
120 if (config_node->pos != -1) { 120 if (config_node->pos != -1) {
121 if (config_node->pos <= nb_param) { 121 if (config_node->pos <= nb_param) {
@@ -150,8 +150,9 @@ static bool is_param_matching(zend_execute_data* execute_data,
150 } else { 150 } else {
151 *arg_name = execute_data->func->internal_function.arg_info[i].name; 151 *arg_name = execute_data->func->internal_function.arg_info[i].name;
152 } 152 }
153 const bool pcre_matching = config_node->r_param 153 const bool pcre_matching =
154 && (true == is_regexp_matching(config_node->r_param, *arg_name)); 154 config_node->r_param &&
155 (true == is_regexp_matching(config_node->r_param, *arg_name));
155 156
156 /* This is the parameter name we're looking for. */ 157 /* This is the parameter name we're looking for. */
157 if (true == pcre_matching || config_node->pos != -1) { 158 if (true == pcre_matching || config_node->pos != -1) {
@@ -159,23 +160,23 @@ static bool is_param_matching(zend_execute_data* execute_data,
159 160
160 if (config_node->param_type) { // Are we matching on the `type`? 161 if (config_node->param_type) { // Are we matching on the `type`?
161 if (config_node->param_type == Z_TYPE_P(arg_value)) { 162 if (config_node->param_type == Z_TYPE_P(arg_value)) {
162 return true; 163 return true;
163 } 164 }
164 } else if (Z_TYPE_P(arg_value) == IS_ARRAY) { 165 } else if (Z_TYPE_P(arg_value) == IS_ARRAY) {
165 *arg_value_str = sp_convert_to_string(arg_value); 166 *arg_value_str = sp_convert_to_string(arg_value);
166 if (config_node->key || config_node->r_key) { 167 if (config_node->key || config_node->r_key) {
167 if (sp_match_array_key(arg_value, config_node->key, 168 if (sp_match_array_key(arg_value, config_node->key,
168 config_node->r_key)) { 169 config_node->r_key)) {
169 return true; 170 return true;
170 } 171 }
171 } else if (sp_match_array_value(arg_value, config_node->value, 172 } else if (sp_match_array_value(arg_value, config_node->value,
172 config_node->value_r)) { 173 config_node->value_r)) {
173 return true; 174 return true;
174 } 175 }
175 } else { 176 } else {
176 *arg_value_str = sp_convert_to_string(arg_value); 177 *arg_value_str = sp_convert_to_string(arg_value);
177 if (sp_match_value(*arg_value_str, config_node->value, 178 if (sp_match_value(*arg_value_str, config_node->value,
178 config_node->value_r)) { 179 config_node->value_r)) {
179 return true; 180 return true;
180 } 181 }
181 } 182 }
@@ -188,23 +189,23 @@ static bool is_param_matching(zend_execute_data* execute_data,
188 if (arg_value) { 189 if (arg_value) {
189 *arg_value_str = sp_convert_to_string(arg_value); 190 *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) { // Are we matching on the `type`?
191 if (config_node->param_type 192 if (config_node->param_type &&
192 && config_node->param_type == Z_TYPE_P(arg_value)) { 193 config_node->param_type == Z_TYPE_P(arg_value)) {
193 return true; 194 return true;
194 } 195 }
195 } else if (Z_TYPE_P(arg_value) == IS_ARRAY) { 196 } else if (Z_TYPE_P(arg_value) == IS_ARRAY) {
196 if (config_node->key || config_node->r_key) { 197 if (config_node->key || config_node->r_key) {
197 if (sp_match_array_key(arg_value, config_node->key, 198 if (sp_match_array_key(arg_value, config_node->key,
198 config_node->r_key)) { 199 config_node->r_key)) {
199 return true; 200 return true;
200 } 201 }
201 } else if (sp_match_array_value(arg_value, config_node->value, 202 } else if (sp_match_array_value(arg_value, config_node->value,
202 config_node->value_r)) { 203 config_node->value_r)) {
203 return true; 204 return true;
204 } 205 }
205 } else if (sp_match_value(*arg_value_str, config_node->value, 206 } else if (sp_match_value(*arg_value_str, config_node->value,
206 config_node->value_r)) { 207 config_node->value_r)) {
207 return true; 208 return true;
208 } 209 }
209 } 210 }
210 } 211 }
@@ -340,7 +341,7 @@ allow:
340} 341}
341 342
342bool should_drop_on_ret(zval* return_value, 343bool should_drop_on_ret(zval* return_value,
343 const zend_execute_data* const execute_data) { 344 const zend_execute_data* const execute_data) {
344 const sp_list_node* config = 345 const sp_list_node* config =
345 SNUFFLEUPAGUS_G(config).config_disabled_functions_ret->disabled_functions; 346 SNUFFLEUPAGUS_G(config).config_disabled_functions_ret->disabled_functions;
346 char* complete_path_function = get_complete_function_path(execute_data); 347 char* complete_path_function = get_complete_function_path(execute_data);
diff --git a/src/sp_disabled_functions.h b/src/sp_disabled_functions.h
index e43afe8..f80c9c2 100644
--- a/src/sp_disabled_functions.h
+++ b/src/sp_disabled_functions.h
@@ -2,7 +2,8 @@
2#define __SP_DISABLE_FUNCTIONS_H 2#define __SP_DISABLE_FUNCTIONS_H
3 3
4int hook_disabled_functions(); 4int hook_disabled_functions();
5bool should_disable(zend_execute_data*, const char *, const char *, const char *); 5bool should_disable(zend_execute_data *, const char *, const char *,
6bool should_drop_on_ret(zval*, const zend_execute_data* const); 6 const char *);
7bool should_drop_on_ret(zval *, const zend_execute_data *const);
7 8
8#endif /* __SP_DISABLE_FUNCTIONS_H */ 9#endif /* __SP_DISABLE_FUNCTIONS_H */
diff --git a/src/sp_execute.c b/src/sp_execute.c
index a541bfb..7dd0798 100644
--- a/src/sp_execute.c
+++ b/src/sp_execute.c
@@ -7,34 +7,37 @@ ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus)
7 7
8static void (*orig_execute_ex)(zend_execute_data *execute_data); 8static void (*orig_execute_ex)(zend_execute_data *execute_data);
9static int (*orig_zend_stream_open)(const char *filename, 9static int (*orig_zend_stream_open)(const char *filename,
10 zend_file_handle *handle); 10 zend_file_handle *handle);
11 11
12// FIXME handle symlink 12// FIXME handle symlink
13ZEND_COLD static inline void terminate_if_writable(const char *filename) { 13ZEND_COLD static inline void terminate_if_writable(const char *filename) {
14 if (0 == access(filename, W_OK)) { 14 if (0 == access(filename, W_OK)) {
15 if (true == SNUFFLEUPAGUS_G(config).config_readonly_exec->simulation) { 15 if (true == SNUFFLEUPAGUS_G(config).config_readonly_exec->simulation) {
16 sp_log_msg("readonly_exec", SP_LOG_SIMULATION, 16 sp_log_msg("readonly_exec", SP_LOG_SIMULATION,
17 "Attempted execution of a writable file (%s).", filename); 17 "Attempted execution of a writable file (%s).", filename);
18 } else { 18 } else {
19 sp_log_msg("readonly_exec", SP_LOG_DROP, 19 sp_log_msg("readonly_exec", SP_LOG_DROP,
20 "Attempted execution of a writable file (%s).", filename); 20 "Attempted execution of a writable file (%s).", filename);
21 sp_terminate(); 21 sp_terminate();
22 } 22 }
23 } else { 23 } else {
24 if (EACCES != errno) { 24 if (EACCES != errno) {
25 sp_log_err("Writable execution", "Error while accessing %s: %s", filename, 25 sp_log_err("Writable execution", "Error while accessing %s: %s", filename,
26 strerror(errno)); 26 strerror(errno));
27 } 27 }
28 } 28 }
29} 29}
30 30
31static void is_builtin_matching(const char * restrict const filename, 31static void is_builtin_matching(const char *restrict const filename,
32 char* restrict function_name, char* restrict param_name, sp_list_node *config) { 32 char *restrict function_name,
33 char *restrict param_name,
34 sp_list_node *config) {
33 if (!config || !config->data) { 35 if (!config || !config->data) {
34 return; 36 return;
35 } 37 }
36 38
37 if (true == should_disable(EG(current_execute_data), function_name, filename, param_name)) { 39 if (true == should_disable(EG(current_execute_data), function_name, filename,
40 param_name)) {
38 sp_terminate(); 41 sp_terminate();
39 } 42 }
40} 43}
@@ -63,9 +66,10 @@ static void sp_execute_ex(zend_execute_data *execute_data) {
63 if (true == should_disable(execute_data, NULL, NULL, NULL)) { 66 if (true == should_disable(execute_data, NULL, NULL, NULL)) {
64 sp_terminate(); 67 sp_terminate();
65 } 68 }
66 69
67 if (execute_data->func->op_array.type == ZEND_EVAL_CODE) { 70 if (execute_data->func->op_array.type == ZEND_EVAL_CODE) {
68 sp_list_node* config = SNUFFLEUPAGUS_G(config).config_disabled_constructs->construct_eval; 71 sp_list_node *config =
72 SNUFFLEUPAGUS_G(config).config_disabled_constructs->construct_eval;
69 char *filename = get_eval_filename((char *)zend_get_executed_filename()); 73 char *filename = get_eval_filename((char *)zend_get_executed_filename());
70 is_builtin_matching(filename, "eval", NULL, config); 74 is_builtin_matching(filename, "eval", NULL, config);
71 efree(filename); 75 efree(filename);
@@ -85,36 +89,40 @@ static void sp_execute_ex(zend_execute_data *execute_data) {
85} 89}
86 90
87static int sp_stream_open(const char *filename, zend_file_handle *handle) { 91static int sp_stream_open(const char *filename, zend_file_handle *handle) {
88 zend_execute_data const * const data = EG(current_execute_data); 92 zend_execute_data const *const data = EG(current_execute_data);
89 93
90 if ((NULL == data) || (NULL == data->opline) || (data->func->type != ZEND_USER_FUNCTION)) { 94 if ((NULL == data) || (NULL == data->opline) ||
95 (data->func->type != ZEND_USER_FUNCTION)) {
91 goto end; 96 goto end;
92 } 97 }
93 98
94 switch(data->opline->opcode) { 99 switch (data->opline->opcode) {
95 case ZEND_INCLUDE_OR_EVAL: 100 case ZEND_INCLUDE_OR_EVAL:
96 if (true == SNUFFLEUPAGUS_G(config).config_readonly_exec->enable) { 101 if (true == SNUFFLEUPAGUS_G(config).config_readonly_exec->enable) {
97 terminate_if_writable(filename); 102 terminate_if_writable(filename);
98 } 103 }
99 sp_list_node* config = SNUFFLEUPAGUS_G(config).config_disabled_constructs->construct_include; 104 sp_list_node *config =
105 SNUFFLEUPAGUS_G(config).config_disabled_constructs->construct_include;
100 switch (data->opline->extended_value) { 106 switch (data->opline->extended_value) {
101 case ZEND_INCLUDE: 107 case ZEND_INCLUDE:
102 is_builtin_matching(filename, "include", "inclusion path", config); 108 is_builtin_matching(filename, "include", "inclusion path", config);
103 break; 109 break;
104 case ZEND_REQUIRE: 110 case ZEND_REQUIRE:
105 is_builtin_matching(filename, "require", "inclusion path", config); 111 is_builtin_matching(filename, "require", "inclusion path", config);
106 break; 112 break;
107 case ZEND_REQUIRE_ONCE: 113 case ZEND_REQUIRE_ONCE:
108 is_builtin_matching(filename, "require_once", "inclusion path", config); 114 is_builtin_matching(filename, "require_once", "inclusion path",
109 break; 115 config);
110 case ZEND_INCLUDE_ONCE: 116 break;
111 is_builtin_matching(filename, "include_once", "inclusion path", config); 117 case ZEND_INCLUDE_ONCE:
112 break; 118 is_builtin_matching(filename, "include_once", "inclusion path",
113 case ZEND_EVAL: 119 config);
114 is_builtin_matching(filename, "eval", NULL, config); 120 break;
115 break; 121 case ZEND_EVAL:
116 default: 122 is_builtin_matching(filename, "eval", NULL, config);
117 break; 123 break;
124 default:
125 break;
118 } 126 }
119 } 127 }
120 128
diff --git a/src/sp_list.c b/src/sp_list.c
index 2a9d680..447f479 100644
--- a/src/sp_list.c
+++ b/src/sp_list.c
@@ -4,7 +4,7 @@
4#include "php_snuffleupagus.h" 4#include "php_snuffleupagus.h"
5 5
6void sp_list_free(sp_list_node *node) { 6void sp_list_free(sp_list_node *node) {
7 while(node) { 7 while (node) {
8 sp_list_node *tmp = node->next; 8 sp_list_node *tmp = node->next;
9 pefree(node, 1); 9 pefree(node, 1);
10 node = tmp; 10 node = tmp;
@@ -18,7 +18,8 @@ sp_list_node *sp_list_new() {
18} 18}
19 19
20// Thanks to https://en.wikipedia.org/wiki/Insertion_sort :> 20// Thanks to https://en.wikipedia.org/wiki/Insertion_sort :>
21sp_list_node *sp_list_sort(sp_list_node *pList, int (*cmp_func)(sp_list_node *, sp_list_node *)) { 21sp_list_node *sp_list_sort(sp_list_node *pList,
22 int (*cmp_func)(sp_list_node *, sp_list_node *)) {
22 sp_list_node *head = NULL; 23 sp_list_node *head = NULL;
23 24
24 if (pList == NULL || pList->next == NULL) { 25 if (pList == NULL || pList->next == NULL) {
@@ -33,12 +34,12 @@ sp_list_node *sp_list_sort(sp_list_node *pList, int (*cmp_func)(sp_list_node *,
33 } else { 34 } else {
34 sp_list_node *p = head; 35 sp_list_node *p = head;
35 while (p != NULL) { 36 while (p != NULL) {
36 if (p->next == NULL || 0 > cmp_func(current, p->next)) { 37 if (p->next == NULL || 0 > cmp_func(current, p->next)) {
37 current->next = p->next; 38 current->next = p->next;
38 p->next = current; 39 p->next = current;
39 break; 40 break;
40 } 41 }
41 p = p->next; 42 p = p->next;
42 } 43 }
43 } 44 }
44 } 45 }
diff --git a/src/sp_list.h b/src/sp_list.h
index b6760ef..8477463 100644
--- a/src/sp_list.h
+++ b/src/sp_list.h
@@ -9,7 +9,8 @@ typedef struct sp_node_s {
9} sp_list_node; 9} sp_list_node;
10 10
11sp_list_node *sp_list_new(); 11sp_list_node *sp_list_new();
12sp_list_node *sp_list_sort(sp_list_node *, int (*)(sp_list_node *, sp_list_node *)); 12sp_list_node *sp_list_sort(sp_list_node *,
13 int (*)(sp_list_node *, sp_list_node *));
13void sp_list_insert(sp_list_node *, void *); 14void sp_list_insert(sp_list_node *, void *);
14void sp_list_free(sp_list_node *); 15void sp_list_free(sp_list_node *);
15void sp_list_prepend(sp_list_node *, void *); 16void sp_list_prepend(sp_list_node *, void *);
diff --git a/src/sp_network_utils.c b/src/sp_network_utils.c
index 6fc0b1f..51911a8 100644
--- a/src/sp_network_utils.c
+++ b/src/sp_network_utils.c
@@ -91,9 +91,9 @@ int get_ip_and_cidr(char *ip, sp_cidr *cidr) {
91 char *mask = strchr(ip, '/'); 91 char *mask = strchr(ip, '/');
92 92
93 if (NULL == mask) { 93 if (NULL == mask) {
94 sp_log_err("config", 94 sp_log_err(
95 "'%s' isn't a valid network mask, it seems that you forgot a '/'.", 95 "config",
96 ip); 96 "'%s' isn't a valid network mask, it seems that you forgot a '/'.", ip);
97 return -1; 97 return -1;
98 } 98 }
99 99
diff --git a/src/sp_unserialize.c b/src/sp_unserialize.c
index 7f3add0..312ba2e 100644
--- a/src/sp_unserialize.c
+++ b/src/sp_unserialize.c
@@ -6,11 +6,12 @@ PHP_FUNCTION(sp_serialize) {
6 void (*orig_handler)(INTERNAL_FUNCTION_PARAMETERS); 6 void (*orig_handler)(INTERNAL_FUNCTION_PARAMETERS);
7 7
8 /* Call the original `serialize` function. */ 8 /* Call the original `serialize` function. */
9 if ((orig_handler = zend_hash_str_find_ptr(SNUFFLEUPAGUS_G(sp_internal_functions_hook), 9 if ((orig_handler = zend_hash_str_find_ptr(
10 "serialize", 9))) { 10 SNUFFLEUPAGUS_G(sp_internal_functions_hook), "serialize", 9))) {
11 orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); 11 orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU);
12 } else { 12 } else {
13 sp_log_err("disabled_functions", 13 sp_log_err(
14 "disabled_functions",
14 "Unable to find the pointer to the original function 'serialize' in " 15 "Unable to find the pointer to the original function 'serialize' in "
15 "the hashtable.\n"); 16 "the hashtable.\n");
16 return; 17 return;
@@ -57,7 +58,8 @@ PHP_FUNCTION(sp_unserialize) {
57 58
58 /* 64 is the length of HMAC-256 */ 59 /* 64 is the length of HMAC-256 */
59 if (buf_len < 64) { 60 if (buf_len < 64) {
60 sp_log_msg("unserialize", SP_LOG_DROP, "The serialized object is too small."); 61 sp_log_msg("unserialize", SP_LOG_DROP,
62 "The serialized object is too small.");
61 RETURN_FALSE; 63 RETURN_FALSE;
62 } 64 }
63 65
@@ -82,19 +84,22 @@ PHP_FUNCTION(sp_unserialize) {
82 } 84 }
83 85
84 if (0 == status) { 86 if (0 == status) {
85 if ((orig_handler = zend_hash_str_find_ptr(SNUFFLEUPAGUS_G(sp_internal_functions_hook), 87 if ((orig_handler = zend_hash_str_find_ptr(
86 "unserialize", 11))) { 88 SNUFFLEUPAGUS_G(sp_internal_functions_hook), "unserialize", 11))) {
87 orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); 89 orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU);
88 } 90 }
89 } else { 91 } else {
90 if ( true == SNUFFLEUPAGUS_G(config).config_unserialize->simulation) { 92 if (true == SNUFFLEUPAGUS_G(config).config_unserialize->simulation) {
91 sp_log_msg("unserialize", SP_LOG_SIMULATION, "Invalid HMAC for %s", serialized_str); 93 sp_log_msg("unserialize", SP_LOG_SIMULATION, "Invalid HMAC for %s",
92 if ((orig_handler = zend_hash_str_find_ptr(SNUFFLEUPAGUS_G(sp_internal_functions_hook), 94 serialized_str);
93 "unserialize", 11))) { 95 if ((orig_handler = zend_hash_str_find_ptr(
96 SNUFFLEUPAGUS_G(sp_internal_functions_hook), "unserialize",
97 11))) {
94 orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); 98 orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU);
95 } 99 }
96 } else { 100 } else {
97 sp_log_msg("unserialize", SP_LOG_DROP, "Invalid HMAC for %s", serialized_str); 101 sp_log_msg("unserialize", SP_LOG_DROP, "Invalid HMAC for %s",
102 serialized_str);
98 } 103 }
99 } 104 }
100 efree(serialized_str); 105 efree(serialized_str);
@@ -104,8 +109,10 @@ PHP_FUNCTION(sp_unserialize) {
104int hook_serialize(void) { 109int hook_serialize(void) {
105 TSRMLS_FETCH(); 110 TSRMLS_FETCH();
106 111
107 HOOK_FUNCTION("serialize", sp_internal_functions_hook, PHP_FN(sp_serialize), false); 112 HOOK_FUNCTION("serialize", sp_internal_functions_hook, PHP_FN(sp_serialize),
108 HOOK_FUNCTION("unserialize", sp_internal_functions_hook, PHP_FN(sp_unserialize), false); 113 false);
114 HOOK_FUNCTION("unserialize", sp_internal_functions_hook,
115 PHP_FN(sp_unserialize), false);
109 116
110 return SUCCESS; 117 return SUCCESS;
111} 118}
diff --git a/src/sp_upload_validation.c b/src/sp_upload_validation.c
index 0010984..4d52266 100644
--- a/src/sp_upload_validation.c
+++ b/src/sp_upload_validation.c
@@ -79,8 +79,9 @@ int sp_rfc1867_callback(unsigned int event, void *event_data, void **extra) {
79 if (WEXITSTATUS(waitstatus) != 0) { // Nope 79 if (WEXITSTATUS(waitstatus) != 0) { // Nope
80 char *uri = 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,
84 uri ? uri : "?");
84 if (!SNUFFLEUPAGUS_G(config).config_upload_validation->simulation) { 85 if (!SNUFFLEUPAGUS_G(config).config_upload_validation->simulation) {
85 zend_bailout(); 86 zend_bailout();
86 } 87 }
diff --git a/src/sp_upload_validation.h b/src/sp_upload_validation.h
index 3d59527..ae3871b 100644
--- a/src/sp_upload_validation.h
+++ b/src/sp_upload_validation.h
@@ -3,7 +3,8 @@
3 3
4void hook_upload(); 4void hook_upload();
5 5
6int (*sp_rfc1867_orig_callback)(unsigned int event, void *event_data, void **extra); 6int (*sp_rfc1867_orig_callback)(unsigned int event, void *event_data,
7 void **extra);
7int sp_rfc1867_callback(unsigned int event, void *event_data, void **extra); 8int sp_rfc1867_callback(unsigned int event, void *event_data, void **extra);
8 9
9#endif 10#endif
diff --git a/src/sp_utils.c b/src/sp_utils.c
index 3fe2e44..8a1ed87 100644
--- a/src/sp_utils.c
+++ b/src/sp_utils.c
@@ -17,7 +17,7 @@ static inline void _sp_log_err(const char* fmt, ...) {
17 php_log_err(msg); 17 php_log_err(msg);
18} 18}
19 19
20void sp_log_msg(char const *feature, char const *level, const char* fmt, ...) { 20void sp_log_msg(char const* feature, char const* level, const char* fmt, ...) {
21 char* msg; 21 char* msg;
22 va_list args; 22 va_list args;
23 23
@@ -25,9 +25,9 @@ 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 = 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",
30 feature, level, msg); 30 client_ip ? client_ip : "0.0.0.0", feature, level, msg);
31} 31}
32 32
33zend_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) {
@@ -38,7 +38,7 @@ zend_always_inline int is_regexp_matching(const pcre* regexp, const char* str) {
38 assert(NULL != str); 38 assert(NULL != str);
39 39
40 ret = sp_pcre_exec(regexp, NULL, str, strlen(str), 0, 0, vec, 40 ret = sp_pcre_exec(regexp, NULL, str, strlen(str), 0, 0, vec,
41 sizeof(vec)/sizeof(int)); 41 sizeof(vec) / sizeof(int));
42 42
43 if (ret < 0) { 43 if (ret < 0) {
44 if (ret != PCRE_ERROR_NOMATCH) { 44 if (ret != PCRE_ERROR_NOMATCH) {
@@ -58,7 +58,8 @@ int compute_hash(const char* const filename, char* file_hash) {
58 php_stream* stream = 58 php_stream* stream =
59 php_stream_open_wrapper(filename, "rb", REPORT_ERRORS, NULL); 59 php_stream_open_wrapper(filename, "rb", REPORT_ERRORS, NULL);
60 if (!stream) { 60 if (!stream) {
61 sp_log_err("hash_computation", "Can not open the file %s to compute its hash.\n", filename); 61 sp_log_err("hash_computation",
62 "Can not open the file %s to compute its hash.\n", filename);
62 return FAILURE; 63 return FAILURE;
63 } 64 }
64 65
@@ -73,14 +74,13 @@ int compute_hash(const char* const filename, char* file_hash) {
73} 74}
74 75
75static int construct_filename(char* filename, const char* folder, 76static int construct_filename(char* filename, const char* folder,
76 const char* textual) { 77 const char* textual) {
77 PHP_SHA256_CTX context; 78 PHP_SHA256_CTX context;
78 unsigned char digest[SHA256_SIZE] = {0}; 79 unsigned char digest[SHA256_SIZE] = {0};
79 char strhash[65] = {0}; 80 char strhash[65] = {0};
80 81
81 if (-1 == mkdir(folder, 0700) && errno != EEXIST) { 82 if (-1 == mkdir(folder, 0700) && errno != EEXIST) {
82 sp_log_err("request_logging", "Unable to create the folder '%s'.", 83 sp_log_err("request_logging", "Unable to create the folder '%s'.", folder);
83 folder);
84 return -1; 84 return -1;
85 } 85 }
86 86
@@ -88,10 +88,10 @@ static int construct_filename(char* filename, const char* folder,
88 * as filename, in order to only have one dump per rule, to migitate 88 * as filename, in order to only have one dump per rule, to migitate
89 * DoS attacks. */ 89 * DoS attacks. */
90 PHP_SHA256Init(&context); 90 PHP_SHA256Init(&context);
91 PHP_SHA256Update(&context, (const unsigned char *) textual, strlen(textual)); 91 PHP_SHA256Update(&context, (const unsigned char*)textual, strlen(textual));
92 PHP_SHA256Final(digest, &context); 92 PHP_SHA256Final(digest, &context);
93 make_digest_ex(strhash, digest, SHA256_SIZE); 93 make_digest_ex(strhash, digest, SHA256_SIZE);
94 snprintf(filename, MAX_FOLDER_LEN-1, "%s/sp_dump.%s", folder, strhash); 94 snprintf(filename, MAX_FOLDER_LEN - 1, "%s/sp_dump.%s", folder, strhash);
95 95
96 return 0; 96 return 0;
97} 97}
@@ -106,14 +106,14 @@ int sp_log_request(const char* folder, const char* text_repr) {
106 const int key; 106 const int key;
107 } zones[] = {{"GET", TRACK_VARS_GET}, {"POST", TRACK_VARS_POST}, 107 } zones[] = {{"GET", TRACK_VARS_GET}, {"POST", TRACK_VARS_POST},
108 {"COOKIE", TRACK_VARS_COOKIE}, {"SERVER", TRACK_VARS_SERVER}, 108 {"COOKIE", TRACK_VARS_COOKIE}, {"SERVER", TRACK_VARS_SERVER},
109 {"ENV", TRACK_VARS_ENV}, {NULL, 0}}; 109 {"ENV", TRACK_VARS_ENV}, {NULL, 0}};
110 110
111 if (0 != construct_filename(filename, folder, text_repr)) { 111 if (0 != construct_filename(filename, folder, text_repr)) {
112 return -1; 112 return -1;
113 } 113 }
114 if (NULL == (file = fopen(filename, "w+"))) { 114 if (NULL == (file = fopen(filename, "w+"))) {
115 sp_log_err("request_logging", "Unable to open %s: %s", filename, 115 sp_log_err("request_logging", "Unable to open %s: %s", filename,
116 strerror(errno)); 116 strerror(errno));
117 return -1; 117 return -1;
118 } 118 }
119 119
@@ -147,7 +147,7 @@ int sp_log_request(const char* folder, const char* text_repr) {
147 return 0; 147 return 0;
148} 148}
149 149
150static char *zv_str_to_char(zval *zv) { 150static char* zv_str_to_char(zval* zv) {
151 zval copy; 151 zval copy;
152 152
153 ZVAL_ZVAL(&copy, zv, 1, 0); 153 ZVAL_ZVAL(&copy, zv, 1, 0);
@@ -159,7 +159,6 @@ static char *zv_str_to_char(zval *zv) {
159 return estrdup(Z_STRVAL(copy)); 159 return estrdup(Z_STRVAL(copy));
160} 160}
161 161
162
163char* sp_convert_to_string(zval* zv) { 162char* sp_convert_to_string(zval* zv) {
164 switch (Z_TYPE_P(zv)) { 163 switch (Z_TYPE_P(zv)) {
165 case IS_FALSE: 164 case IS_FALSE:
@@ -169,18 +168,18 @@ char* sp_convert_to_string(zval* zv) {
169 case IS_NULL: 168 case IS_NULL:
170 return estrdup("NULL"); 169 return estrdup("NULL");
171 case IS_LONG: { 170 case IS_LONG: {
172 char *msg; 171 char* msg;
173 spprintf(&msg, 0, ZEND_LONG_FMT, Z_LVAL_P(zv)); 172 spprintf(&msg, 0, ZEND_LONG_FMT, Z_LVAL_P(zv));
174 return msg; 173 return msg;
175 } 174 }
176 case IS_DOUBLE: { 175 case IS_DOUBLE: {
177 char *msg; 176 char* msg;
178 spprintf(&msg, 0, "%f", Z_DVAL_P(zv)); 177 spprintf(&msg, 0, "%f", Z_DVAL_P(zv));
179 return msg; 178 return msg;
180 } 179 }
181 case IS_STRING:{ 180 case IS_STRING: {
182 return zv_str_to_char(zv); 181 return zv_str_to_char(zv);
183 } 182 }
184 case IS_OBJECT: 183 case IS_OBJECT:
185 return estrdup("OBJECT"); 184 return estrdup("OBJECT");
186 case IS_ARRAY: 185 case IS_ARRAY:
@@ -212,31 +211,32 @@ void sp_log_disable(const char* restrict path, const char* restrict arg_name,
212 const int sim = config_node->simulation; 211 const int sim = config_node->simulation;
213 if (arg_name) { 212 if (arg_name) {
214 if (alias) { 213 if (alias) {
215 sp_log_msg("disabled_function", sim?SP_LOG_SIMULATION:SP_LOG_DROP, 214 sp_log_msg(
215 "disabled_function", sim ? SP_LOG_SIMULATION : SP_LOG_DROP,
216 "The call to the function '%s' in %s:%d has been disabled, " 216 "The call to the function '%s' in %s:%d has been disabled, "
217 "because its argument '%s' content (%s) matched the rule '%s'.", 217 "because its argument '%s' content (%s) matched the rule '%s'.",
218 path, zend_get_executed_filename(TSRMLS_C), 218 path, zend_get_executed_filename(TSRMLS_C),
219 zend_get_executed_lineno(TSRMLS_C), arg_name, arg_value?arg_value:"?",
220 alias);
221 } else {
222 sp_log_msg("disabled_function", sim?SP_LOG_SIMULATION:SP_LOG_DROP,
223 "The call to the function '%s' in %s:%d has been disabled, "
224 "because its argument '%s' content (%s) matched a rule.",
225 path, zend_get_executed_filename(TSRMLS_C),
226 zend_get_executed_lineno(TSRMLS_C), arg_name, 219 zend_get_executed_lineno(TSRMLS_C), arg_name,
227 arg_value?arg_value:"?"); 220 arg_value ? arg_value : "?", alias);
221 } else {
222 sp_log_msg("disabled_function", sim ? SP_LOG_SIMULATION : SP_LOG_DROP,
223 "The call to the function '%s' in %s:%d has been disabled, "
224 "because its argument '%s' content (%s) matched a rule.",
225 path, zend_get_executed_filename(TSRMLS_C),
226 zend_get_executed_lineno(TSRMLS_C), arg_name,
227 arg_value ? arg_value : "?");
228 } 228 }
229 } else { 229 } else {
230 if (alias) { 230 if (alias) {
231 sp_log_msg("disabled_function", sim?SP_LOG_SIMULATION:SP_LOG_DROP, 231 sp_log_msg("disabled_function", sim ? SP_LOG_SIMULATION : SP_LOG_DROP,
232 "The call to the function '%s' in %s:%d has been disabled, " 232 "The call to the function '%s' in %s:%d has been disabled, "
233 "because of the the rule '%s'.",path, 233 "because of the the rule '%s'.",
234 zend_get_executed_filename(TSRMLS_C), 234 path, zend_get_executed_filename(TSRMLS_C),
235 zend_get_executed_lineno(TSRMLS_C), alias); 235 zend_get_executed_lineno(TSRMLS_C), alias);
236 } else { 236 } else {
237 sp_log_msg("disabled_function", sim?SP_LOG_SIMULATION:SP_LOG_DROP, 237 sp_log_msg("disabled_function", sim ? SP_LOG_SIMULATION : SP_LOG_DROP,
238 "The call to the function '%s' in %s:%d has been disabled.", 238 "The call to the function '%s' in %s:%d has been disabled.",
239 path, zend_get_executed_filename(TSRMLS_C), 239 path, zend_get_executed_filename(TSRMLS_C),
240 zend_get_executed_lineno(TSRMLS_C)); 240 zend_get_executed_lineno(TSRMLS_C));
241 } 241 }
242 } 242 }
@@ -252,17 +252,20 @@ void sp_log_disable_ret(const char* restrict path,
252 const char* alias = config_node->alias; 252 const char* alias = config_node->alias;
253 const int sim = config_node->simulation; 253 const int sim = config_node->simulation;
254 if (alias) { 254 if (alias) {
255 sp_log_msg("disabled_function", sim?SP_LOG_SIMULATION:SP_LOG_DROP, 255 sp_log_msg(
256 "disabled_function", sim ? SP_LOG_SIMULATION : SP_LOG_DROP,
256 "The execution has been aborted in %s:%d, " 257 "The execution has been aborted in %s:%d, "
257 "because the function '%s' returned '%s', which matched the rule '%s'.", 258 "because the function '%s' returned '%s', which matched the rule '%s'.",
258 zend_get_executed_filename(TSRMLS_C), 259 zend_get_executed_filename(TSRMLS_C),
259 zend_get_executed_lineno(TSRMLS_C), path, ret_value?ret_value:"?", alias); 260 zend_get_executed_lineno(TSRMLS_C), path, ret_value ? ret_value : "?",
261 alias);
260 } else { 262 } else {
261 sp_log_msg("disabled_function", sim?SP_LOG_SIMULATION:SP_LOG_DROP, 263 sp_log_msg(
264 "disabled_function", sim ? SP_LOG_SIMULATION : SP_LOG_DROP,
262 "The execution has been aborted in %s:%d, " 265 "The execution has been aborted in %s:%d, "
263 "because the return value (%s) of the function '%s' matched a rule.", 266 "because the return value (%s) of the function '%s' matched a rule.",
264 zend_get_executed_filename(TSRMLS_C), 267 zend_get_executed_filename(TSRMLS_C),
265 zend_get_executed_lineno(TSRMLS_C), ret_value?ret_value:"?", path); 268 zend_get_executed_lineno(TSRMLS_C), ret_value ? ret_value : "?", path);
266 } 269 }
267 if (dump) { 270 if (dump) {
268 sp_log_request(dump, config_node->textual_representation); 271 sp_log_request(dump, config_node->textual_representation);
@@ -276,17 +279,17 @@ bool sp_match_array_key(const zval* zv, const char* to_match, const pcre* rx) {
276 ZEND_HASH_FOREACH_KEY(Z_ARRVAL_P(zv), idx, key) { 279 ZEND_HASH_FOREACH_KEY(Z_ARRVAL_P(zv), idx, key) {
277 if (key) { 280 if (key) {
278 if (sp_match_value(ZSTR_VAL(key), to_match, rx)) { 281 if (sp_match_value(ZSTR_VAL(key), to_match, rx)) {
279 return true; 282 return true;
280 } 283 }
281 } else { 284 } else {
282 char *idx_str = NULL; 285 char* idx_str = NULL;
283 286
284 // Could use a log. 287 // Could use a log.
285 idx_str = emalloc(snprintf(NULL, 0, "%lu", idx)); 288 idx_str = emalloc(snprintf(NULL, 0, "%lu", idx));
286 sprintf(idx_str, "%lu", idx); 289 sprintf(idx_str, "%lu", idx);
287 if (sp_match_value(idx_str, to_match, rx)) { 290 if (sp_match_value(idx_str, to_match, rx)) {
288 efree(idx_str); 291 efree(idx_str);
289 return true; 292 return true;
290 } 293 }
291 efree(idx_str); 294 efree(idx_str);
292 } 295 }
@@ -295,17 +298,18 @@ bool sp_match_array_key(const zval* zv, const char* to_match, const pcre* rx) {
295 return false; 298 return false;
296} 299}
297 300
298bool sp_match_array_value(const zval* arr, const char* to_match, const pcre* rx) { 301bool sp_match_array_value(const zval* arr, const char* to_match,
302 const pcre* rx) {
299 zval* value; 303 zval* value;
300 304
301 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(arr), value) { 305 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(arr), value) {
302 if (Z_TYPE_P(value) != IS_ARRAY) { 306 if (Z_TYPE_P(value) != IS_ARRAY) {
303 char *value_str = sp_convert_to_string(value); 307 char* value_str = sp_convert_to_string(value);
304 if (sp_match_value(value_str, to_match, rx)) { 308 if (sp_match_value(value_str, to_match, rx)) {
305 efree(value_str); 309 efree(value_str);
306 return true; 310 return true;
307 } else { 311 } else {
308 efree (value_str); 312 efree(value_str);
309 } 313 }
310 } else if (sp_match_array_value(value, to_match, rx)) { 314 } else if (sp_match_array_value(value, to_match, rx)) {
311 return true; 315 return true;
@@ -315,18 +319,17 @@ bool sp_match_array_value(const zval* arr, const char* to_match, const pcre* rx)
315 return false; 319 return false;
316} 320}
317 321
318
319int hook_function(const char* original_name, HashTable* hook_table, 322int hook_function(const char* original_name, HashTable* hook_table,
320 void (*new_function)(INTERNAL_FUNCTION_PARAMETERS), 323 void (*new_function)(INTERNAL_FUNCTION_PARAMETERS),
321 bool hook_execution_table) { 324 bool hook_execution_table) {
322 zend_internal_function* func; 325 zend_internal_function* func;
323 HashTable *ht = hook_execution_table==true?EG(function_table):CG(function_table); 326 HashTable* ht =
327 hook_execution_table == true ? EG(function_table) : CG(function_table);
324 328
325 /* The `mb` module likes to hook functions, like strlen->mb_strlen, 329 /* The `mb` module likes to hook functions, like strlen->mb_strlen,
326 * so we have to hook both of them. */ 330 * so we have to hook both of them. */
327 331
328 if ((func = zend_hash_str_find_ptr(ht, 332 if ((func = zend_hash_str_find_ptr(ht, VAR_AND_LEN(original_name)))) {
329 VAR_AND_LEN(original_name)))) {
330 if (func->handler == new_function) { 333 if (func->handler == new_function) {
331 return SUCCESS; 334 return SUCCESS;
332 } 335 }
@@ -340,7 +343,7 @@ int hook_function(const char* original_name, HashTable* hook_table,
340 VAR_AND_LEN(original_name), 343 VAR_AND_LEN(original_name),
341 func->handler) == NULL) { 344 func->handler) == NULL) {
342 sp_log_err("function_pointer_saving", 345 sp_log_err("function_pointer_saving",
343 "Could not save function pointer for %s", original_name); 346 "Could not save function pointer for %s", original_name);
344 return FAILURE; 347 return FAILURE;
345 } else { 348 } else {
346 func->handler = new_function; 349 func->handler = new_function;
@@ -349,9 +352,9 @@ int hook_function(const char* original_name, HashTable* hook_table,
349 352
350 if (0 == strncmp(original_name, "mb_", 3)) { 353 if (0 == strncmp(original_name, "mb_", 3)) {
351 CG(compiler_options) |= ZEND_COMPILE_NO_BUILTIN_STRLEN; 354 CG(compiler_options) |= ZEND_COMPILE_NO_BUILTIN_STRLEN;
352 if (zend_hash_str_find(ht, 355 if (zend_hash_str_find(ht, VAR_AND_LEN(original_name + 3))) {
353 VAR_AND_LEN(original_name + 3))) { 356 hook_function(original_name + 3, hook_table, new_function,
354 hook_function(original_name + 3, hook_table, new_function, hook_execution_table); 357 hook_execution_table);
355 } 358 }
356 } else { // TODO this can be moved somewhere else to gain some marginal perfs 359 } else { // TODO this can be moved somewhere else to gain some marginal perfs
357 CG(compiler_options) |= ZEND_COMPILE_NO_BUILTIN_STRLEN; 360 CG(compiler_options) |= ZEND_COMPILE_NO_BUILTIN_STRLEN;
@@ -370,13 +373,14 @@ int hook_regexp(const pcre* regexp, HashTable* hook_table,
370 void (*new_function)(INTERNAL_FUNCTION_PARAMETERS), 373 void (*new_function)(INTERNAL_FUNCTION_PARAMETERS),
371 bool hook_execution_table) { 374 bool hook_execution_table) {
372 zend_string* key; 375 zend_string* key;
373 HashTable *ht = hook_execution_table==true?EG(function_table):CG(function_table); 376 HashTable* ht =
377 hook_execution_table == true ? EG(function_table) : CG(function_table);
374 378
375 ZEND_HASH_FOREACH_STR_KEY(ht, key) { 379 ZEND_HASH_FOREACH_STR_KEY(ht, key) {
376 if (key) { 380 if (key) {
377 int vec[30]; 381 int vec[30];
378 int ret = sp_pcre_exec(regexp, NULL, key->val, key->len, 0, 0, vec, 382 int ret = sp_pcre_exec(regexp, NULL, key->val, key->len, 0, 0, vec,
379 sizeof(vec)/sizeof(int)); 383 sizeof(vec) / sizeof(int));
380 if (ret < 0) { /* Error or no match*/ 384 if (ret < 0) { /* Error or no match*/
381 if (PCRE_ERROR_NOMATCH != ret) { 385 if (PCRE_ERROR_NOMATCH != ret) {
382 sp_log_err("pcre", "Runtime error with pcre, error code: %d", ret); 386 sp_log_err("pcre", "Runtime error with pcre, error code: %d", ret);
diff --git a/src/sp_utils.h b/src/sp_utils.h
index e54f307..e055e70 100644
--- a/src/sp_utils.h
+++ b/src/sp_utils.h
@@ -9,13 +9,13 @@
9#include "sp_list.h" 9#include "sp_list.h"
10 10
11#if defined(__GNUC__) 11#if defined(__GNUC__)
12# if __GNUC__ >= 3 12#if __GNUC__ >= 3
13# define sp_pure __attribute__((pure)) 13#define sp_pure __attribute__((pure))
14# define sp_const __attribute__((const)) 14#define sp_const __attribute__((const))
15# else 15#else
16# define sp_pure 16#define sp_pure
17# define sp_const 17#define sp_const
18# endif 18#endif
19#endif 19#endif
20/* The dump filename are of the form 20/* The dump filename are of the form
21 * `sp_dump_DATE_IPADDR.dump`, with: 21 * `sp_dump_DATE_IPADDR.dump`, with:
@@ -34,7 +34,8 @@
34#define SHA256_SIZE 32 34#define SHA256_SIZE 32
35 35
36#define HOOK_FUNCTION(original_name, hook_table, new_function, execution) \ 36#define HOOK_FUNCTION(original_name, hook_table, new_function, execution) \
37 hook_function(original_name, SNUFFLEUPAGUS_G(hook_table), new_function, execution) 37 hook_function(original_name, SNUFFLEUPAGUS_G(hook_table), new_function, \
38 execution)
38 39
39#define HOOK_FUNCTION_BY_REGEXP(regexp, hook_table, new_function, execution) \ 40#define HOOK_FUNCTION_BY_REGEXP(regexp, hook_table, new_function, execution) \
40 hook_regexp(regexp, SNUFFLEUPAGUS_G(hook_table), new_function, execution) 41 hook_regexp(regexp, SNUFFLEUPAGUS_G(hook_table), new_function, execution)
@@ -46,14 +47,14 @@
46 47
47#define sp_log_err(feature, ...) sp_log_msg(feature, SP_LOG_ERROR, __VA_ARGS__) 48#define sp_log_err(feature, ...) sp_log_msg(feature, SP_LOG_ERROR, __VA_ARGS__)
48#ifdef SP_DEBUG 49#ifdef SP_DEBUG
49 #define sp_log_debug(...) sp_log_msg("DEBUG", SP_LOG_DEBUG, __VA_ARGS__) 50#define sp_log_debug(...) sp_log_msg("DEBUG", SP_LOG_DEBUG, __VA_ARGS__)
50#else 51#else
51 #define sp_log_debug(...) 52#define sp_log_debug(...)
52#endif 53#endif
53 54
54#define GET_SUFFIX(x) (x==1)?"st":((x==2)?"nd":"th") 55#define GET_SUFFIX(x) (x == 1) ? "st" : ((x == 2) ? "nd" : "th")
55 56
56void sp_log_msg(char const *feature, char const *level, const char* fmt, ...); 57void sp_log_msg(char const *feature, char const *level, const char *fmt, ...);
57int compute_hash(const char *const filename, char *file_hash); 58int compute_hash(const char *const filename, char *file_hash);
58char *sp_convert_to_string(zval *); 59char *sp_convert_to_string(zval *);
59bool sp_match_value(const char *, const char *, const pcre *); 60bool sp_match_value(const char *, const char *, const pcre *);
diff --git a/src/sp_var_parser.c b/src/sp_var_parser.c
index 3f3dcdc..55cbfc2 100644
--- a/src/sp_var_parser.c
+++ b/src/sp_var_parser.c
@@ -1,7 +1,7 @@
1#include "php_snuffleupagus.h" 1#include "php_snuffleupagus.h"
2 2
3static int parse_str_tokens(const char *str, const sp_conf_token token, 3static int parse_str_tokens(const char *str, const sp_conf_token token,
4 sp_list_node *tokens_list) { 4 sp_list_node *tokens_list) {
5 const char *cur_str = str; 5 const char *cur_str = str;
6 6
7 while ((cur_str = strchr(cur_str, token.text_repr[0]))) { 7 while ((cur_str = strchr(cur_str, token.text_repr[0]))) {
@@ -30,23 +30,24 @@ static bool is_var_name_valid(const char *name) {
30 } 30 }
31 if (NULL == regexp_var || NULL == regexp_const) { 31 if (NULL == regexp_var || NULL == regexp_const) {
32 regexp_var = sp_pcre_compile(REGEXP_VAR, PCRE_CASELESS, &pcre_error, 32 regexp_var = sp_pcre_compile(REGEXP_VAR, PCRE_CASELESS, &pcre_error,
33 &pcre_error_offset, NULL); 33 &pcre_error_offset, NULL);
34 regexp_const = sp_pcre_compile(REGEXP_CONST, PCRE_CASELESS, &pcre_error, 34 regexp_const = sp_pcre_compile(REGEXP_CONST, PCRE_CASELESS, &pcre_error,
35 &pcre_error_offset, NULL); 35 &pcre_error_offset, NULL);
36 } 36 }
37 if (NULL == regexp_var || NULL == regexp_const) { 37 if (NULL == regexp_var || NULL == regexp_const) {
38 sp_log_err("config", "Could not compile regexp."); 38 sp_log_err("config", "Could not compile regexp.");
39 return false; 39 return false;
40 } 40 }
41 if (0 > sp_pcre_exec(regexp_var, NULL, name, strlen(name), 0, 0, NULL, 0) 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)) { 42 0 > sp_pcre_exec(regexp_const, NULL, name, strlen(name), 0, 0, NULL, 0)) {
43 return false; 43 return false;
44 } 44 }
45 return true; 45 return true;
46} 46}
47 47
48static int create_var(sp_tree *tree, const char *restrict value, 48static int create_var(sp_tree *tree, const char *restrict value,
49 size_t value_len, elem_type _type, const char *restrict idx) { 49 size_t value_len, elem_type _type,
50 const char *restrict idx) {
50 sp_tree *var_node = NULL; 51 sp_tree *var_node = NULL;
51 52
52 if (!tree) { 53 if (!tree) {
@@ -72,7 +73,8 @@ static int create_var(sp_tree *tree, const char *restrict value,
72 sp_log_err("config", "Can't allocate a strndup"); 73 sp_log_err("config", "Can't allocate a strndup");
73 return -1; 74 return -1;
74 } 75 }
75 if (var_node->type != INTERPRETED_STRING && !is_var_name_valid(var_node->value)) { 76 if (var_node->type != INTERPRETED_STRING &&
77 !is_var_name_valid(var_node->value)) {
76 sp_log_err("config", "Invalid var name: %s.", var_node->value); 78 sp_log_err("config", "Invalid var name: %s.", var_node->value);
77 return -1; 79 return -1;
78 } 80 }
@@ -88,22 +90,23 @@ static int create_var(sp_tree *tree, const char *restrict value,
88} 90}
89 91
90int cmp_tokens(sp_list_node *list1, sp_list_node *list2) { 92int cmp_tokens(sp_list_node *list1, sp_list_node *list2) {
91 return (((sp_conf_token *)list1->data)->pos 93 return (((sp_conf_token *)list1->data)->pos -
92 - ((sp_conf_token *)list2->data)->pos); 94 ((sp_conf_token *)list2->data)->pos);
93} 95}
94 96
95static int is_next_token_empty(sp_conf_token *token, sp_conf_token *token_next, 97static int is_next_token_empty(sp_conf_token *token, sp_conf_token *token_next,
96 const char * restrict str) { 98 const char *restrict str) {
97 if ((token_next && token_next->pos == token->pos + strlen(token->text_repr)) 99 if ((token_next &&
98 || (!token_next && token->pos == strlen(str) - strlen(token->text_repr))) { 100 token_next->pos == token->pos + strlen(token->text_repr)) ||
101 (!token_next && token->pos == strlen(str) - strlen(token->text_repr))) {
99 return -1; 102 return -1;
100 } 103 }
101 return 0; 104 return 0;
102} 105}
103 106
104static int is_token_valid(sp_list_node *tokens_list, elem_type quote, 107static int is_token_valid(sp_list_node *tokens_list, elem_type quote,
105 int array_count, const char * restrict str, 108 int array_count, const char *restrict str,
106 size_t pos) { 109 size_t pos) {
107 sp_conf_token *token = (sp_conf_token *)tokens_list->data; 110 sp_conf_token *token = (sp_conf_token *)tokens_list->data;
108 sp_conf_token *token_next = NULL; 111 sp_conf_token *token_next = NULL;
109 112
@@ -114,40 +117,40 @@ static int is_token_valid(sp_list_node *tokens_list, elem_type quote,
114 case LITERAL_STRING: 117 case LITERAL_STRING:
115 case INTERPRETED_STRING: 118 case INTERPRETED_STRING:
116 if (quote == token->type) { 119 if (quote == token->type) {
117 if (token_next) { 120 if (token_next) {
118 if (token_next->pos != token->pos + 1) { 121 if (token_next->pos != token->pos + 1) {
119 return -1; 122 return -1;
120 } 123 }
121 } else if (token->pos != strlen(str) - 1) { 124 } else if (token->pos != strlen(str) - 1) {
122 return -1; 125 return -1;
123 } 126 }
124 } 127 }
125 break; 128 break;
126 case ARRAY_END: 129 case ARRAY_END:
127 if (!quote) { 130 if (!quote) {
128 if (array_count < 1) { 131 if (array_count < 1) {
129 return -1; 132 return -1;
130 } else if (token_next) { 133 } else if (token_next) {
131 if (token_next->type == INTERPRETED_STRING 134 if (token_next->type == INTERPRETED_STRING ||
132 || token_next->type == LITERAL_STRING) { 135 token_next->type == LITERAL_STRING) {
133 return -1; 136 return -1;
134 } 137 }
135 } else if (token->pos != strlen(str) - strlen(token->text_repr)) { 138 } else if (token->pos != strlen(str) - strlen(token->text_repr)) {
136 return -1; 139 return -1;
137 } 140 }
138 } 141 }
139 break; 142 break;
140 case OBJECT: 143 case OBJECT:
141 if (!quote && -1 == is_next_token_empty(token, token_next, str)) { 144 if (!quote && -1 == is_next_token_empty(token, token_next, str)) {
142 return -1; 145 return -1;
143 } 146 }
144 if (pos == 0 && *str != VARIABLE_TOKEN) { 147 if (pos == 0 && *str != VARIABLE_TOKEN) {
145 return -1; 148 return -1;
146 } 149 }
147 break; 150 break;
148 case CLASS: 151 case CLASS:
149 if (!quote && -1 == is_next_token_empty(token, token_next, str)) { 152 if (!quote && -1 == is_next_token_empty(token, token_next, str)) {
150 return -1; 153 return -1;
151 } 154 }
152 break; 155 break;
153 default: 156 default:
@@ -156,8 +159,8 @@ static int is_token_valid(sp_list_node *tokens_list, elem_type quote,
156 return 0; 159 return 0;
157} 160}
158 161
159static sp_tree *parse_tokens(const char * restrict str, 162static sp_tree *parse_tokens(const char *restrict str,
160 sp_list_node *tokens_list) { 163 sp_list_node *tokens_list) {
161 size_t pos = 0; 164 size_t pos = 0;
162 int array_count = 0, pos_idx_start = -1; 165 int array_count = 0, pos_idx_start = -1;
163 elem_type quote = 0; 166 elem_type quote = 0;
@@ -179,7 +182,9 @@ static sp_tree *parse_tokens(const char * restrict str,
179 } 182 }
180 if (quote == 0) { 183 if (quote == 0) {
181 if (token->type == ARRAY) { 184 if (token->type == ARRAY) {
182 pos_idx_start = (array_count) ? pos_idx_start : (int)(token->pos + strlen(token->text_repr)); 185 pos_idx_start = (array_count)
186 ? pos_idx_start
187 : (int)(token->pos + strlen(token->text_repr));
183 array_count++; 188 array_count++;
184 } else if (token->type == ARRAY_END) { 189 } else if (token->type == ARRAY_END) {
185 array_count--; 190 array_count--;
@@ -210,12 +215,12 @@ static sp_tree *parse_tokens(const char * restrict str,
210 } 215 }
211 if (quote != 0) { 216 if (quote != 0) {
212 sp_log_err("config", "Missing a closing quote."); 217 sp_log_err("config", "Missing a closing quote.");
213error: 218 error:
214 sp_tree_free(tree); 219 sp_tree_free(tree);
215 return NULL; 220 return NULL;
216 } 221 }
217 if (pos != strlen(str) 222 if (pos != strlen(str) &&
218 && create_var(tree, &str[pos], strlen(str) - pos, CONSTANT, NULL)) { 223 create_var(tree, &str[pos], strlen(str) - pos, CONSTANT, NULL)) {
219 goto error; 224 goto error;
220 } 225 }
221 return tree; 226 return tree;
@@ -225,20 +230,19 @@ sp_tree *parse_var(const char *line) {
225 sp_list_node *tokens_list = NULL; 230 sp_list_node *tokens_list = NULL;
226 sp_tree *tree = NULL; 231 sp_tree *tree = NULL;
227 const sp_conf_token delimiter_list[] = { 232 const sp_conf_token delimiter_list[] = {
228 {.type=OBJECT, .text_repr=OBJECT_TOKEN}, 233 {.type = OBJECT, .text_repr = OBJECT_TOKEN},
229 {.type=ARRAY, .text_repr=ARRAY_TOKEN}, 234 {.type = ARRAY, .text_repr = ARRAY_TOKEN},
230 {.type=ARRAY_END, .text_repr=ARRAY_END_TOKEN}, 235 {.type = ARRAY_END, .text_repr = ARRAY_END_TOKEN},
231 {.type=INTERPRETED_STRING, .text_repr=STRING_TOKEN}, 236 {.type = INTERPRETED_STRING, .text_repr = STRING_TOKEN},
232 {.type=LITERAL_STRING, .text_repr=ESC_STRING_TOKEN}, 237 {.type = LITERAL_STRING, .text_repr = ESC_STRING_TOKEN},
233 {.type=CLASS, .text_repr=CLASS_TOKEN} 238 {.type = CLASS, .text_repr = CLASS_TOKEN}};
234 };
235
236 239
237 if (!line) { 240 if (!line) {
238 return NULL; 241 return NULL;
239 } 242 }
240 tokens_list = sp_list_new(); 243 tokens_list = sp_list_new();
241 for (unsigned int i = 0; i < sizeof(delimiter_list) / sizeof(sp_conf_token); i++) { 244 for (unsigned int i = 0; i < sizeof(delimiter_list) / sizeof(sp_conf_token);
245 i++) {
242 parse_str_tokens(line, delimiter_list[i], tokens_list); 246 parse_str_tokens(line, delimiter_list[i], tokens_list);
243 } 247 }
244 tokens_list = sp_list_sort(tokens_list, cmp_tokens); 248 tokens_list = sp_list_sort(tokens_list, cmp_tokens);
diff --git a/src/sp_var_value.c b/src/sp_var_value.c
index 7f74afa..9a23ad9 100644
--- a/src/sp_var_value.c
+++ b/src/sp_var_value.c
@@ -23,16 +23,16 @@ static zval *get_local_var(zend_execute_data *ed, const char *var_name) {
23 zval *value = NULL; 23 zval *value = NULL;
24 24
25 while (current) { 25 while (current) {
26 zend_string* key = NULL; 26 zend_string *key = NULL;
27 EG(current_execute_data) = current; 27 EG(current_execute_data) = current;
28 zend_array* symtable = zend_rebuild_symbol_table(); 28 zend_array *symtable = zend_rebuild_symbol_table();
29 ZEND_HASH_FOREACH_STR_KEY_VAL(symtable, key, value) { 29 ZEND_HASH_FOREACH_STR_KEY_VAL(symtable, key, value) {
30 if (0 == strcmp(var_name, key->val)) { 30 if (0 == strcmp(var_name, key->val)) {
31 if (Z_TYPE_P(value) == IS_INDIRECT) { 31 if (Z_TYPE_P(value) == IS_INDIRECT) {
32 value = Z_INDIRECT_P(value); 32 value = Z_INDIRECT_P(value);
33 } 33 }
34 EG(current_execute_data) = orig_execute_data; 34 EG(current_execute_data) = orig_execute_data;
35 return value; 35 return value;
36 } 36 }
37 } 37 }
38 ZEND_HASH_FOREACH_END(); 38 ZEND_HASH_FOREACH_END();
@@ -51,7 +51,7 @@ static zval *get_constant(const char *value) {
51} 51}
52 52
53static zval *get_var_value(zend_execute_data *ed, const char *var_name, 53static zval *get_var_value(zend_execute_data *ed, const char *var_name,
54 bool is_param) { 54 bool is_param) {
55 zval *zvalue = NULL; 55 zval *zvalue = NULL;
56 56
57 if (!var_name) { 57 if (!var_name) {
@@ -73,14 +73,14 @@ static zval *get_var_value(zend_execute_data *ed, const char *var_name,
73} 73}
74 74
75static void *get_entry_hashtable(const HashTable *ht, const char *entry, 75static void *get_entry_hashtable(const HashTable *ht, const char *entry,
76 size_t entry_len) { 76 size_t entry_len) {
77 zval *zvalue = zend_hash_str_find(ht, entry, entry_len); 77 zval *zvalue = zend_hash_str_find(ht, entry, entry_len);
78 78
79 if (!zvalue) { 79 if (!zvalue) {
80 zvalue = zend_hash_index_find(ht, atol(entry)); 80 zvalue = zend_hash_index_find(ht, atol(entry));
81 } 81 }
82 while (zvalue && (Z_TYPE_P(zvalue) == IS_INDIRECT 82 while (zvalue &&
83 || Z_TYPE_P(zvalue) == IS_PTR)) { 83 (Z_TYPE_P(zvalue) == IS_INDIRECT || Z_TYPE_P(zvalue) == IS_PTR)) {
84 if (Z_TYPE_P(zvalue) == IS_INDIRECT) { 84 if (Z_TYPE_P(zvalue) == IS_INDIRECT) {
85 zvalue = Z_INDIRECT_P(zvalue); 85 zvalue = Z_INDIRECT_P(zvalue);
86 } else { 86 } else {
@@ -91,7 +91,7 @@ static void *get_entry_hashtable(const HashTable *ht, const char *entry,
91} 91}
92 92
93static zval *get_array_value(zend_execute_data *ed, zval *zvalue, 93static zval *get_array_value(zend_execute_data *ed, zval *zvalue,
94 const sp_tree *tree) { 94 const sp_tree *tree) {
95 zval *idx_value, *ret = NULL; 95 zval *idx_value, *ret = NULL;
96 char *idx = NULL; 96 char *idx = NULL;
97 97
@@ -108,7 +108,7 @@ static zval *get_array_value(zend_execute_data *ed, zval *zvalue,
108} 108}
109 109
110static zval *get_object_property(zend_execute_data *ed, zval *object, 110static zval *get_object_property(zend_execute_data *ed, zval *object,
111 const char *property, bool is_param) { 111 const char *property, bool is_param) {
112 char *class_name = object->value.obj->ce->name->val; 112 char *class_name = object->value.obj->ce->name->val;
113 HashTable *array = Z_OBJPROP_P(object); 113 HashTable *array = Z_OBJPROP_P(object);
114 zval *zvalue = NULL; 114 zval *zvalue = NULL;
@@ -131,7 +131,8 @@ static zval *get_object_property(zend_execute_data *ed, zval *object,
131 } 131 }
132 if (!zvalue) { 132 if (!zvalue) {
133 char *private_property = emalloc(strlen(class_name) + 3 + strlen(property)); 133 char *private_property = emalloc(strlen(class_name) + 3 + strlen(property));
134 len = sprintf(private_property, PRIVATE_PROP_FMT, 0, class_name, 0, property); 134 len =
135 sprintf(private_property, PRIVATE_PROP_FMT, 0, class_name, 0, property);
135 zvalue = get_entry_hashtable(array, private_property, len); 136 zvalue = get_entry_hashtable(array, private_property, len);
136 efree(private_property); 137 efree(private_property);
137 } 138 }
@@ -149,8 +150,8 @@ static zend_class_entry *get_class(const char *value) {
149} 150}
150 151
151static zval *get_unknown_type(const char *restrict value, zval *zvalue, 152static zval *get_unknown_type(const char *restrict value, zval *zvalue,
152 zend_class_entry *ce, zend_execute_data *ed, 153 zend_class_entry *ce, zend_execute_data *ed,
153 const sp_tree *tree, bool is_param) { 154 const sp_tree *tree, bool is_param) {
154 if (ce) { 155 if (ce) {
155 zvalue = get_entry_hashtable(&ce->constants_table, value, strlen(value)); 156 zvalue = get_entry_hashtable(&ce->constants_table, value, strlen(value));
156 ce = NULL; 157 ce = NULL;
@@ -171,51 +172,50 @@ static zval *get_unknown_type(const char *restrict value, zval *zvalue,
171 return zvalue; 172 return zvalue;
172} 173}
173 174
174zval *get_value(zend_execute_data *ed, const sp_tree *tree, 175zval *get_value(zend_execute_data *ed, const sp_tree *tree, bool is_param) {
175 bool is_param) {
176 zval *zvalue = NULL; 176 zval *zvalue = NULL;
177 zend_class_entry *ce = NULL; 177 zend_class_entry *ce = NULL;
178 178
179 while (tree) { 179 while (tree) {
180 switch (tree->type) { 180 switch (tree->type) {
181 case ARRAY: 181 case ARRAY:
182 if (ce) { 182 if (ce) {
183 zvalue = get_entry_hashtable(&ce->constants_table, tree->value, 183 zvalue = get_entry_hashtable(&ce->constants_table, tree->value,
184 strlen(tree->value)); 184 strlen(tree->value));
185 ce = NULL; 185 ce = NULL;
186 } else if (!zvalue) { 186 } else if (!zvalue) {
187 zvalue = get_var_value(ed, tree->value, is_param); 187 zvalue = get_var_value(ed, tree->value, is_param);
188 } else if (Z_TYPE_P(zvalue) == IS_OBJECT) { 188 } else if (Z_TYPE_P(zvalue) == IS_OBJECT) {
189 zvalue = get_object_property(ed, zvalue, tree->value, is_param); 189 zvalue = get_object_property(ed, zvalue, tree->value, is_param);
190 } 190 }
191 zvalue = get_array_value(ed, zvalue, tree); 191 zvalue = get_array_value(ed, zvalue, tree);
192 break; 192 break;
193 case VAR: 193 case VAR:
194 if (zvalue && Z_TYPE_P(zvalue) == IS_OBJECT) { 194 if (zvalue && Z_TYPE_P(zvalue) == IS_OBJECT) {
195 zvalue = get_object_property(ed, zvalue, tree->value, is_param); 195 zvalue = get_object_property(ed, zvalue, tree->value, is_param);
196 } else { 196 } else {
197 zvalue = get_var_value(ed, tree->value, is_param); 197 zvalue = get_var_value(ed, tree->value, is_param);
198 } 198 }
199 break; 199 break;
200 case OBJECT: 200 case OBJECT:
201 if (!zvalue) { 201 if (!zvalue) {
202 zvalue = get_var_value(ed, tree->value, is_param); 202 zvalue = get_var_value(ed, tree->value, is_param);
203 } else if (Z_TYPE_P(zvalue) == IS_OBJECT) { 203 } else if (Z_TYPE_P(zvalue) == IS_OBJECT) {
204 if (0 != strlen(tree->value)) { 204 if (0 != strlen(tree->value)) {
205 zvalue = get_object_property(ed, zvalue, tree->value, is_param); 205 zvalue = get_object_property(ed, zvalue, tree->value, is_param);
206 } 206 }
207 } else { 207 } else {
208 return NULL; 208 return NULL;
209 } 209 }
210 break; 210 break;
211 case CLASS: 211 case CLASS:
212 ce = get_class(tree->value); 212 ce = get_class(tree->value);
213 zvalue = NULL; 213 zvalue = NULL;
214 break; 214 break;
215 default: 215 default:
216 zvalue = get_unknown_type(tree->value, zvalue, ce, ed, tree, is_param); 216 zvalue = get_unknown_type(tree->value, zvalue, ce, ed, tree, is_param);
217 ce = NULL; 217 ce = NULL;
218 break; 218 break;
219 } 219 }
220 if (!zvalue && !ce) { 220 if (!zvalue && !ce) {
221 return NULL; 221 return NULL;