summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/sp_config_keywords.c202
1 files changed, 111 insertions, 91 deletions
diff --git a/src/sp_config_keywords.c b/src/sp_config_keywords.c
index 0e52846..9bb8021 100644
--- a/src/sp_config_keywords.c
+++ b/src/sp_config_keywords.c
@@ -2,47 +2,31 @@
2 2
3ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus) 3ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus)
4 4
5static const struct {
6 unsigned int type;
7 char *keys[5]; // Update this value if necessary
8} CONSTRUCTS_TYPES[] = {
9 {.type = ZEND_INCLUDE_OR_EVAL,
10 .keys = {"include", "include_once", "require", "require_once", NULL}},
11 {.type = ZEND_ECHO, .keys = {"echo", NULL}},
12 {.type = ZEND_NEW, .keys = {"new", NULL}},
13 {.type = ZEND_EXIT, .keys = {"exit", NULL}},
14 {.type = ZEND_STRLEN, .keys = {"strlen", NULL}},
15 {.type = ZEND_EVAL_CODE, .keys = {"eval", NULL}},
16 {.type = 0, .keys = {NULL}}};
5 17
6static int get_construct_type(sp_disabled_function const *const df) { 18static int get_construct_type(sp_disabled_function const *const df) {
7 const struct { 19 for (size_t i = 0; 0 != CONSTRUCTS_TYPES[i].type; i++) {
8 unsigned int type; 20 for (size_t j = 0; NULL != CONSTRUCTS_TYPES[i].keys[j]; j++) {
9 char *keys[5]; 21 assert(df->function || df->r_function);
10 } mapping[] = {
11 {
12 .type = ZEND_INCLUDE_OR_EVAL,
13 .keys = {"include", "include_once", "require", "require_once", NULL}
14 },{
15 .type = ZEND_ECHO,
16 .keys = {"echo", NULL}
17 },{
18 .type = ZEND_NEW,
19 .keys = {"new", NULL}
20 },{
21 .type = ZEND_EXIT,
22 .keys = {"exit", NULL}
23 },{
24 .type = ZEND_STRLEN,
25 .keys = {"strlen", NULL}
26 },{
27 .type = ZEND_EVAL_CODE,
28 .keys = {"eval", NULL}
29 },{
30 .type = 0,
31 .keys = {NULL}
32 }
33 };
34
35 // FIXME: This can be optimized
36 // FIXME the ->function and r_fonction tests are _wrong_
37 for (size_t i=0; 0 != mapping[i].type; i++) {
38 for (size_t j=0; NULL != mapping[i].keys[j]; j++) {
39 if (df->function) { 22 if (df->function) {
40 if (0 == strcmp(df->function, mapping[i].keys[j])) { 23 if (0 == strcmp(df->function, CONSTRUCTS_TYPES[i].keys[j])) {
41 return mapping[i].type; 24 return CONSTRUCTS_TYPES[i].type;
42 } 25 }
43 } else if (df->r_function) { 26 } else {
44 if (true == is_regexp_matching(df->r_function, mapping[i].keys[j])) { 27 if (true ==
45 return mapping[i].type; 28 is_regexp_matching(df->r_function, CONSTRUCTS_TYPES[i].keys[j])) {
29 return CONSTRUCTS_TYPES[i].type;
46 } 30 }
47 } 31 }
48 } 32 }
@@ -50,13 +34,14 @@ static int get_construct_type(sp_disabled_function const *const df) {
50 return -1; 34 return -1;
51} 35}
52 36
53static int parse_enable(char *line, bool * restrict retval, bool * restrict simulation) { 37static int parse_enable(char *line, bool *restrict retval,
38 bool *restrict simulation) {
54 bool enable = false, disable = false; 39 bool enable = false, disable = false;
55 sp_config_functions sp_config_funcs[] = { 40 sp_config_functions sp_config_funcs[] = {
56 {parse_empty, SP_TOKEN_ENABLE, &(enable)}, 41 {parse_empty, SP_TOKEN_ENABLE, &(enable)},
57 {parse_empty, SP_TOKEN_DISABLE, &(disable)}, 42 {parse_empty, SP_TOKEN_DISABLE, &(disable)},
58 {parse_empty, SP_TOKEN_SIMULATION, simulation}, 43 {parse_empty, SP_TOKEN_SIMULATION, simulation},
59 {0}}; 44 {0}};
60 45
61 int ret = parse_keywords(sp_config_funcs, line); 46 int ret = parse_keywords(sp_config_funcs, line);
62 47
@@ -65,7 +50,8 @@ static int parse_enable(char *line, bool * restrict retval, bool * restrict simu
65 } 50 }
66 51
67 if (!(enable ^ disable)) { 52 if (!(enable ^ disable)) {
68 sp_log_err("config", "A rule can't be enabled and disabled on line %zu.", sp_line_no); 53 sp_log_err("config", "A rule can't be enabled and disabled on line %zu.",
54 sp_line_no);
69 return -1; 55 return -1;
70 } 56 }
71 57
@@ -75,27 +61,35 @@ static int parse_enable(char *line, bool * restrict retval, bool * restrict simu
75} 61}
76 62
77int parse_random(char *line) { 63int parse_random(char *line) {
78 return parse_enable(line, &(SNUFFLEUPAGUS_G(config).config_random->enable), NULL); 64 return parse_enable(line, &(SNUFFLEUPAGUS_G(config).config_random->enable),
65 NULL);
79} 66}
80 67
81int parse_disable_xxe(char *line) { 68int parse_disable_xxe(char *line) {
82 return parse_enable(line, &(SNUFFLEUPAGUS_G(config).config_disable_xxe->enable), NULL); 69 return parse_enable(
70 line, &(SNUFFLEUPAGUS_G(config).config_disable_xxe->enable), NULL);
83} 71}
84 72
85int parse_auto_cookie_secure(char *line) { 73int parse_auto_cookie_secure(char *line) {
86 return parse_enable(line, &(SNUFFLEUPAGUS_G(config).config_auto_cookie_secure->enable), NULL); 74 return parse_enable(
75 line, &(SNUFFLEUPAGUS_G(config).config_auto_cookie_secure->enable), NULL);
87} 76}
88 77
89int parse_global_strict(char *line) { 78int parse_global_strict(char *line) {
90 return parse_enable(line, &(SNUFFLEUPAGUS_G(config).config_global_strict->enable), NULL); 79 return parse_enable(
80 line, &(SNUFFLEUPAGUS_G(config).config_global_strict->enable), NULL);
91} 81}
92 82
93int parse_unserialize(char *line) { 83int parse_unserialize(char *line) {
94 return parse_enable(line, &(SNUFFLEUPAGUS_G(config).config_unserialize->enable), &(SNUFFLEUPAGUS_G(config).config_unserialize->simulation)); 84 return parse_enable(
85 line, &(SNUFFLEUPAGUS_G(config).config_unserialize->enable),
86 &(SNUFFLEUPAGUS_G(config).config_unserialize->simulation));
95} 87}
96 88
97int parse_readonly_exec(char *line) { 89int parse_readonly_exec(char *line) {
98 return parse_enable(line, &(SNUFFLEUPAGUS_G(config).config_readonly_exec->enable), &(SNUFFLEUPAGUS_G(config).config_readonly_exec->simulation)); 90 return parse_enable(
91 line, &(SNUFFLEUPAGUS_G(config).config_readonly_exec->enable),
92 &(SNUFFLEUPAGUS_G(config).config_readonly_exec->simulation));
99} 93}
100 94
101int parse_global(char *line) { 95int parse_global(char *line) {
@@ -127,24 +121,35 @@ int parse_cookie(char *line) {
127 121
128 if (cookie->encrypt) { 122 if (cookie->encrypt) {
129 if (0 == (SNUFFLEUPAGUS_G(config).config_snuffleupagus->cookies_env_var)) { 123 if (0 == (SNUFFLEUPAGUS_G(config).config_snuffleupagus->cookies_env_var)) {
130 sp_log_err("config", "You're trying to use the cookie encryption feature" 124 sp_log_err(
131 "on line %zu without having set the `.cookie_env_var` option in" 125 "config",
132 "`sp.global`: please set it first.", sp_line_no); 126 "You're trying to use the cookie encryption feature"
127 "on line %zu without having set the `.cookie_env_var` option in"
128 "`sp.global`: please set it first.",
129 sp_line_no);
133 return -1; 130 return -1;
134 } else if (0 == (SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key)) { 131 } else if (0 ==
135 sp_log_err("config", "You're trying to use the cookie encryption feature" 132 (SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key)) {
136 "on line %zu without having set the `.encryption_key` option in" 133 sp_log_err(
137 "`sp.global`: please set it first.", sp_line_no); 134 "config",
135 "You're trying to use the cookie encryption feature"
136 "on line %zu without having set the `.encryption_key` option in"
137 "`sp.global`: please set it first.",
138 sp_line_no);
138 return -1; 139 return -1;
139 } 140 }
140 } else if (!samesite) { 141 } else if (!samesite) {
141 sp_log_err("config", "You must specify a at least one action to a cookie on line " 142 sp_log_err("config",
142 "%zu.", sp_line_no); 143 "You must specify a at least one action to a cookie on line "
144 "%zu.",
145 sp_line_no);
143 return -1; 146 return -1;
144 } 147 }
145 if (0 == strlen(name)) { 148 if (0 == strlen(name)) {
146 sp_log_err("config", "You must specify a cookie name on line " 149 sp_log_err("config",
147 "%zu.", sp_line_no); 150 "You must specify a cookie name on line "
151 "%zu.",
152 sp_line_no);
148 return -1; 153 return -1;
149 } 154 }
150 if (samesite) { 155 if (samesite) {
@@ -153,14 +158,19 @@ int parse_cookie(char *line) {
153 } else if (0 == strcasecmp(samesite, SP_TOKEN_SAMESITE_STRICT)) { 158 } else if (0 == strcasecmp(samesite, SP_TOKEN_SAMESITE_STRICT)) {
154 cookie->samesite = strict; 159 cookie->samesite = strict;
155 } else { 160 } else {
156 sp_log_err("config", "%s is an invalid value to samesite (expected %s or %s) on line " 161 sp_log_err(
157 "%zu.", samesite, SP_TOKEN_SAMESITE_LAX, SP_TOKEN_SAMESITE_STRICT, sp_line_no); 162 "config",
163 "%s is an invalid value to samesite (expected %s or %s) on line "
164 "%zu.",
165 samesite, SP_TOKEN_SAMESITE_LAX, SP_TOKEN_SAMESITE_STRICT,
166 sp_line_no);
158 return -1; 167 return -1;
159 } 168 }
160 } 169 }
161 170
162 zend_name = zend_string_init(name, strlen(name), 1); 171 zend_name = zend_string_init(name, strlen(name), 1);
163 zend_hash_add_ptr(SNUFFLEUPAGUS_G(config).config_cookie->cookies, zend_name, cookie); 172 zend_hash_add_ptr(SNUFFLEUPAGUS_G(config).config_cookie->cookies, zend_name,
173 cookie);
164 174
165 return SUCCESS; 175 return SUCCESS;
166} 176}
@@ -206,13 +216,13 @@ int parse_disabled_functions(char *line) {
206 return ret; 216 return ret;
207 } 217 }
208 218
209#define MUTUALLY_EXCLUSIVE(X, Y, STR1, STR2) \ 219#define MUTUALLY_EXCLUSIVE(X, Y, STR1, STR2) \
210 if (X && Y) { \ 220 if (X && Y) { \
211 sp_log_err("config", \ 221 sp_log_err("config", \
212 "Invalid configuration line: 'sp.disabled_functions%s': " \ 222 "Invalid configuration line: 'sp.disabled_functions%s': " \
213 "'.%s' and '.%s' are mutually exclusive on line %zu.", \ 223 "'.%s' and '.%s' are mutually exclusive on line %zu.", \
214 line, STR1, STR2, sp_line_no); \ 224 line, STR1, STR2, sp_line_no); \
215 return 1;\ 225 return 1; \
216 } 226 }
217 227
218 MUTUALLY_EXCLUSIVE(df->value, df->value_r, "value", "regexp"); 228 MUTUALLY_EXCLUSIVE(df->value, df->value_r, "value", "regexp");
@@ -221,11 +231,13 @@ int parse_disabled_functions(char *line) {
221 MUTUALLY_EXCLUSIVE(df->ret, df->r_ret, "r_ret", "ret"); 231 MUTUALLY_EXCLUSIVE(df->ret, df->r_ret, "r_ret", "ret");
222#undef MUTUALLY_EXCLUSIVE 232#undef MUTUALLY_EXCLUSIVE
223 233
224 if (1 < ((df->r_param?1:0) + (df->param?1:0) + ((-1 != df->pos)?1:0))) { 234 if (1 < ((df->r_param ? 1 : 0) + (df->param ? 1 : 0) +
225 sp_log_err("config", 235 ((-1 != df->pos) ? 1 : 0))) {
226 "Invalid configuration line: 'sp.disabled_functions%s':" 236 sp_log_err(
227 "'.r_param', '.param' and '.pos' are mutually exclusive on line %zu.", 237 "config",
228 line, sp_line_no); 238 "Invalid configuration line: 'sp.disabled_functions%s':"
239 "'.r_param', '.param' and '.pos' are mutually exclusive on line %zu.",
240 line, sp_line_no);
229 return -1; 241 return -1;
230 } else if ((df->r_ret || df->ret) && (df->r_param || df->param)) { 242 } else if ((df->r_ret || df->ret) && (df->r_param || df->param)) {
231 sp_log_err("config", 243 sp_log_err("config",
@@ -240,11 +252,11 @@ int parse_disabled_functions(char *line) {
240 line, sp_line_no); 252 line, sp_line_no);
241 return -1; 253 return -1;
242 } else if (df->filename && *df->filename != '/') { 254 } else if (df->filename && *df->filename != '/') {
243 sp_log_err("config", 255 sp_log_err("config",
244 "Invalid configuration line: 'sp.disabled_functions%s':" 256 "Invalid configuration line: 'sp.disabled_functions%s':"
245 "'.filename' must be an absolute path on line %zu.", 257 "'.filename' must be an absolute path on line %zu.",
246 line, sp_line_no); 258 line, sp_line_no);
247 return -1; 259 return -1;
248 } else if (!(allow ^ drop)) { 260 } else if (!(allow ^ drop)) {
249 sp_log_err("config", 261 sp_log_err("config",
250 "Invalid configuration line: 'sp.disabled_functions%s': The " 262 "Invalid configuration line: 'sp.disabled_functions%s': The "
@@ -259,7 +271,7 @@ int parse_disabled_functions(char *line) {
259 df->pos = (int)strtol(pos, &endptr, 10); 271 df->pos = (int)strtol(pos, &endptr, 10);
260 if (errno != 0 || endptr == pos) { 272 if (errno != 0 || endptr == pos) {
261 sp_log_err("config", "Failed to parse arg '%s' of `pos` on line %zu.", 273 sp_log_err("config", "Failed to parse arg '%s' of `pos` on line %zu.",
262 pos, sp_line_no); 274 pos, sp_line_no);
263 return -1; 275 return -1;
264 } 276 }
265 } 277 }
@@ -270,7 +282,7 @@ int parse_disabled_functions(char *line) {
270 df->line = (unsigned int)strtoul(line_number, &endptr, 10); 282 df->line = (unsigned int)strtoul(line_number, &endptr, 10);
271 if (errno != 0 || endptr == line_number) { 283 if (errno != 0 || endptr == line_number) {
272 sp_log_err("config", "Failed to parse arg '%s' of `line` on line %zu.", 284 sp_log_err("config", "Failed to parse arg '%s' of `line` on line %zu.",
273 line_number, sp_line_no); 285 line_number, sp_line_no);
274 return -1; 286 return -1;
275 } 287 }
276 } 288 }
@@ -300,10 +312,14 @@ int parse_disabled_functions(char *line) {
300 312
301 switch (get_construct_type(df)) { 313 switch (get_construct_type(df)) {
302 case ZEND_INCLUDE_OR_EVAL: 314 case ZEND_INCLUDE_OR_EVAL:
303 sp_list_insert(SNUFFLEUPAGUS_G(config).config_disabled_constructs->construct_include, df); 315 sp_list_insert(
316 SNUFFLEUPAGUS_G(config).config_disabled_constructs->construct_include,
317 df);
304 return ret; 318 return ret;
305 case ZEND_EVAL_CODE: 319 case ZEND_EVAL_CODE:
306 sp_list_insert(SNUFFLEUPAGUS_G(config).config_disabled_constructs->construct_eval, df); 320 sp_list_insert(
321 SNUFFLEUPAGUS_G(config).config_disabled_constructs->construct_eval,
322 df);
307 return ret; 323 return ret;
308 case ZEND_ECHO: 324 case ZEND_ECHO:
309 default: 325 default:
@@ -315,9 +331,9 @@ int parse_disabled_functions(char *line) {
315 } 331 }
316 332
317 if (df->ret || df->r_ret || df->ret_type) { 333 if (df->ret || df->r_ret || df->ret_type) {
318 sp_list_insert( 334 sp_list_insert(SNUFFLEUPAGUS_G(config)
319 SNUFFLEUPAGUS_G(config).config_disabled_functions_ret->disabled_functions, 335 .config_disabled_functions_ret->disabled_functions,
320 df); 336 df);
321 } else { 337 } else {
322 sp_list_insert( 338 sp_list_insert(
323 SNUFFLEUPAGUS_G(config).config_disabled_functions->disabled_functions, 339 SNUFFLEUPAGUS_G(config).config_disabled_functions->disabled_functions,
@@ -344,7 +360,8 @@ int parse_upload_validation(char *line) {
344 } 360 }
345 361
346 if (!(enable ^ disable)) { 362 if (!(enable ^ disable)) {
347 sp_log_err("config", "A rule can't be enabled and disabled on line %zu.", sp_line_no); 363 sp_log_err("config", "A rule can't be enabled and disabled on line %zu.",
364 sp_line_no);
348 return -1; 365 return -1;
349 } 366 }
350 SNUFFLEUPAGUS_G(config).config_upload_validation->enable = enable; 367 SNUFFLEUPAGUS_G(config).config_upload_validation->enable = enable;
@@ -352,14 +369,17 @@ int parse_upload_validation(char *line) {
352 char const *script = SNUFFLEUPAGUS_G(config).config_upload_validation->script; 369 char const *script = SNUFFLEUPAGUS_G(config).config_upload_validation->script;
353 370
354 if (!script) { 371 if (!script) {
355 sp_log_err("config", "The `script` directive is mandatory in '%s' on line %zu.", 372 sp_log_err("config",
356 line, sp_line_no); 373 "The `script` directive is mandatory in '%s' on line %zu.", line,
374 sp_line_no);
357 return -1; 375 return -1;
358 } else if (-1 == access(script, F_OK)) { 376 } else if (-1 == access(script, F_OK)) {
359 sp_log_err("config", "The `script` (%s) doesn't exist on line %zu.", script, sp_line_no); 377 sp_log_err("config", "The `script` (%s) doesn't exist on line %zu.", script,
378 sp_line_no);
360 return -1; 379 return -1;
361 } else if (-1 == access(script, X_OK)) { 380 } else if (-1 == access(script, X_OK)) {
362 sp_log_err("config", "The `script` (%s) isn't executable on line %zu.", script, sp_line_no); 381 sp_log_err("config", "The `script` (%s) isn't executable on line %zu.",
382 script, sp_line_no);
363 return -1; 383 return -1;
364 } 384 }
365 385