summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config.m42
-rw-r--r--config.w322
-rw-r--r--ex_imp.c412
-rw-r--r--execute.c39
-rw-r--r--header.c16
-rw-r--r--log.c13
-rw-r--r--php_suhosin.h121
-rw-r--r--post_handler.c11
-rw-r--r--rfc1867.c1397
-rw-r--r--rfc1867_new.c2
-rw-r--r--session.c61
-rw-r--r--sha256.c6
-rw-r--r--suhosin.c7
-rw-r--r--treat_data.c8
14 files changed, 8 insertions, 2089 deletions
diff --git a/config.m4 b/config.m4
index 9ddf5e9..c908de9 100644
--- a/config.m4
+++ b/config.m4
@@ -5,7 +5,7 @@ PHP_ARG_ENABLE(suhosin, whether to enable suhosin support,
5[ --enable-suhosin Enable suhosin support]) 5[ --enable-suhosin Enable suhosin support])
6 6
7if test "$PHP_SUHOSIN" != "no"; then 7if test "$PHP_SUHOSIN" != "no"; then
8 PHP_NEW_EXTENSION(suhosin, suhosin.c sha256.c memory_limit.c treat_data.c ifilter.c post_handler.c ufilter.c rfc1867.c rfc1867_new.c log.c header.c execute.c ex_imp.c session.c aes.c crypt.c, $ext_shared) 8 PHP_NEW_EXTENSION(suhosin, suhosin.c sha256.c memory_limit.c treat_data.c ifilter.c post_handler.c ufilter.c rfc1867_new.c log.c header.c execute.c ex_imp.c session.c aes.c crypt.c, $ext_shared)
9fi 9fi
10 10
11PHP_ARG_ENABLE(suhosin-experimental, whether to enable experimental suhosin features, 11PHP_ARG_ENABLE(suhosin-experimental, whether to enable experimental suhosin features,
diff --git a/config.w32 b/config.w32
index 6f0993f..ecfe832 100644
--- a/config.w32
+++ b/config.w32
@@ -4,7 +4,7 @@
4ARG_ENABLE("suhosin", "whether to enable suhosin support", "yes"); 4ARG_ENABLE("suhosin", "whether to enable suhosin support", "yes");
5 5
6if (PHP_SUHOSIN == "yes") { 6if (PHP_SUHOSIN == "yes") {
7 EXTENSION("suhosin", "suhosin.c sha256.c memory_limit.c treat_data.c ifilter.c post_handler.c ufilter.c rfc1867.c rfc1867_new.c log.c header.c execute.c ex_imp.c session.c aes.c crypt.c"); 7 EXTENSION("suhosin", "suhosin.c sha256.c memory_limit.c treat_data.c ifilter.c post_handler.c ufilter.c rfc1867_new.c log.c header.c execute.c ex_imp.c session.c aes.c crypt.c");
8 ARG_ENABLE("suhosin-experimental", "Enable experimental suhosin features", "no"); 8 ARG_ENABLE("suhosin-experimental", "Enable experimental suhosin features", "no");
9 9
10 if (PHP_SUHOSIN_EXPERIMENTAL != "no") { 10 if (PHP_SUHOSIN_EXPERIMENTAL != "no") {
diff --git a/ex_imp.c b/ex_imp.c
index 441314d..1c01191 100644
--- a/ex_imp.c
+++ b/ex_imp.c
@@ -86,7 +86,6 @@ static int php_valid_var_name(char *var_name, int len) /* {{{ */
86 Imports variables into symbol table from an array */ 86 Imports variables into symbol table from an array */
87PHP_FUNCTION(suhosin_extract) 87PHP_FUNCTION(suhosin_extract)
88{ 88{
89#if PHP_VERSION_ID >= 50300
90 zval *var_array, *prefix = NULL; 89 zval *var_array, *prefix = NULL;
91 long extract_type = EXTR_OVERWRITE; 90 long extract_type = EXTR_OVERWRITE;
92 zval **entry, *data; 91 zval **entry, *data;
@@ -240,430 +239,22 @@ PHP_FUNCTION(suhosin_extract)
240 } 239 }
241 240
242 RETURN_LONG(count); 241 RETURN_LONG(count);
243#else
244 zval **var_array, *orig_var_array, **z_extract_type, **prefix;
245 zval **entry, *data;
246 char *var_name;
247 smart_str final_name = {0};
248 ulong num_key;
249 uint var_name_len;
250 int var_exists, extract_type, key_type, count = 0;
251 int extract_refs = 0;
252 HashPosition pos;
253
254 switch (ZEND_NUM_ARGS()) {
255 case 1:
256 if (zend_get_parameters_ex(1, &var_array) == FAILURE) {
257 WRONG_PARAM_COUNT;
258 }
259 extract_type = EXTR_OVERWRITE;
260 break;
261
262 case 2:
263 if (zend_get_parameters_ex(2, &var_array, &z_extract_type) == FAILURE) {
264 WRONG_PARAM_COUNT;
265 }
266 convert_to_long_ex(z_extract_type);
267 extract_type = Z_LVAL_PP(z_extract_type);
268 extract_refs = (extract_type & EXTR_REFS);
269 extract_type &= 0xff;
270 if (extract_type > EXTR_SKIP && extract_type <= EXTR_PREFIX_IF_EXISTS) {
271 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Prefix expected to be specified");
272 return;
273 }
274 break;
275
276 case 3:
277 if (zend_get_parameters_ex(3, &var_array, &z_extract_type, &prefix) == FAILURE) {
278 WRONG_PARAM_COUNT;
279 }
280 convert_to_long_ex(z_extract_type);
281 extract_type = Z_LVAL_PP(z_extract_type);
282 extract_refs = (extract_type & EXTR_REFS);
283 extract_type &= 0xff;
284 convert_to_string_ex(prefix);
285 break;
286
287 default:
288 WRONG_PARAM_COUNT;
289 break;
290 }
291
292 if (extract_type < EXTR_OVERWRITE || extract_type > EXTR_IF_EXISTS) {
293 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown extract type");
294 return;
295 }
296
297 if (Z_TYPE_PP(var_array) != IS_ARRAY) {
298 php_error_docref(NULL TSRMLS_CC, E_WARNING, "First argument should be an array");
299 return;
300 }
301
302 /* var_array is passed by ref for the needs of EXTR_REFS (needs to
303 * work on the original array to create refs to its members)
304 * simulate pass_by_value if EXTR_REFS is not used */
305 if (!extract_refs) {
306 orig_var_array = *var_array;
307 SEPARATE_ARG_IF_REF((*var_array));
308 }
309
310 zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(var_array), &pos);
311 while (zend_hash_get_current_data_ex(Z_ARRVAL_PP(var_array), (void **)&entry, &pos) == SUCCESS) {
312 key_type = zend_hash_get_current_key_ex(Z_ARRVAL_PP(var_array), &var_name, &var_name_len, &num_key, 0, &pos);
313 var_exists = 0;
314
315 if (key_type == HASH_KEY_IS_STRING) {
316 var_name_len--;
317 var_exists = zend_hash_exists(EG(active_symbol_table), var_name, var_name_len + 1);
318 } else if (extract_type == EXTR_PREFIX_ALL || extract_type == EXTR_PREFIX_INVALID) {
319 smart_str_appendl(&final_name, Z_STRVAL_PP(prefix), Z_STRLEN_PP(prefix));
320 smart_str_appendc(&final_name, '_');
321 smart_str_append_long(&final_name, num_key);
322 } else {
323 zend_hash_move_forward_ex(Z_ARRVAL_PP(var_array), &pos);
324 continue;
325 }
326
327 switch (extract_type) {
328 case EXTR_IF_EXISTS:
329 if (!var_exists) break;
330 /* break omitted intentionally */
331
332 case EXTR_OVERWRITE:
333 /* GLOBALS protection */
334 if (var_exists && var_name_len == sizeof("GLOBALS") && !strcmp(var_name, "GLOBALS")) {
335 break;
336 }
337 if (var_exists && var_name_len == sizeof("this") && !strcmp(var_name, "this") && EG(scope) && EG(scope)->name_length != 0) {
338 break;
339 }
340 smart_str_appendl(&final_name, var_name, var_name_len);
341 break;
342
343 case EXTR_PREFIX_IF_EXISTS:
344 if (var_exists) {
345 smart_str_appendl(&final_name, Z_STRVAL_PP(prefix), Z_STRLEN_PP(prefix));
346 smart_str_appendc(&final_name, '_');
347 smart_str_appendl(&final_name, var_name, var_name_len);
348 }
349 break;
350
351 case EXTR_PREFIX_SAME:
352 if (!var_exists)
353 smart_str_appendl(&final_name, var_name, var_name_len);
354 /* break omitted intentionally */
355
356 case EXTR_PREFIX_ALL:
357 if (final_name.len == 0 && var_name_len != 0) {
358 smart_str_appendl(&final_name, Z_STRVAL_PP(prefix), Z_STRLEN_PP(prefix));
359 smart_str_appendc(&final_name, '_');
360 smart_str_appendl(&final_name, var_name, var_name_len);
361 }
362 break;
363
364 case EXTR_PREFIX_INVALID:
365 if (final_name.len == 0) {
366 if (!php_valid_var_name(var_name, var_name_len)) {
367 smart_str_appendl(&final_name, Z_STRVAL_PP(prefix), Z_STRLEN_PP(prefix));
368 smart_str_appendc(&final_name, '_');
369 smart_str_appendl(&final_name, var_name, var_name_len);
370 } else
371 smart_str_appendl(&final_name, var_name, var_name_len);
372 }
373 break;
374
375 default:
376 if (!var_exists)
377 smart_str_appendl(&final_name, var_name, var_name_len);
378 break;
379 }
380
381 if (final_name.len) {
382 smart_str_0(&final_name);
383 if (php_valid_var_name(final_name.c, final_name.len)) {
384 if (extract_refs) {
385 zval **orig_var;
386
387 SEPARATE_ZVAL_TO_MAKE_IS_REF(entry);
388 zval_add_ref(entry);
389
390 if (zend_hash_find(EG(active_symbol_table), final_name.c, final_name.len+1, (void **) &orig_var) == SUCCESS) {
391 zval_ptr_dtor(orig_var);
392 *orig_var = *entry;
393 } else {
394 zend_hash_update(EG(active_symbol_table), final_name.c, final_name.len+1, (void **) entry, sizeof(zval *), NULL);
395 }
396 } else {
397 MAKE_STD_ZVAL(data);
398 *data = **entry;
399 zval_copy_ctor(data);
400
401 ZEND_SET_SYMBOL_WITH_LENGTH(EG(active_symbol_table), final_name.c, final_name.len+1, data, 1, 0);
402 }
403
404 count++;
405 }
406 final_name.len = 0;
407 }
408
409 zend_hash_move_forward_ex(Z_ARRVAL_PP(var_array), &pos);
410 }
411
412 if (!extract_refs) {
413 zval_ptr_dtor(var_array);
414 *var_array = orig_var_array;
415 }
416 smart_str_free(&final_name);
417
418 RETURN_LONG(count);
419#endif
420} 242}
421/* }}} */ 243/* }}} */
422 244
423 245
424 246
425#if PHP_VERSION_ID < 50400
426/* import_request_variables() has been DEPRECATED as of PHP 5.3.0 and REMOVED as of PHP 5.4.0. */
427#define SUHOSIN_HAVE_IRV 1
428#endif
429
430#ifdef SUHOSIN_HAVE_IRV
431
432#if PHP_VERSION_ID >= 50300
433static int copy_request_variable(void *pDest TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
434{
435 zval *prefix, new_key;
436 int prefix_len;
437 zval **var = (zval **) pDest;
438
439 if (num_args != 1) {
440 return 0;
441 }
442
443 prefix = va_arg(args, zval *);
444 prefix_len = Z_STRLEN_P(prefix);
445
446 if (!prefix_len && !hash_key->nKeyLength) {
447 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Numeric key detected - possible security hazard");
448 return 0;
449 }
450
451 if (hash_key->nKeyLength) {
452 php_prefix_varname(&new_key, prefix, (char *)hash_key->arKey, hash_key->nKeyLength - 1, 0 TSRMLS_CC);
453 } else {
454 zval num;
455
456 ZVAL_LONG(&num, hash_key->h);
457 convert_to_string(&num);
458 php_prefix_varname(&new_key, prefix, Z_STRVAL(num), Z_STRLEN(num), 0 TSRMLS_CC);
459 zval_dtor(&num);
460 }
461
462 if (php_varname_check(Z_STRVAL(new_key), Z_STRLEN(new_key), 1 TSRMLS_CC) == FAILURE || suhosin_is_protected_varname(Z_STRVAL(new_key), Z_STRLEN(new_key))) {
463 zval_dtor(&new_key);
464 return 0;
465 }
466
467 zend_delete_global_variable(Z_STRVAL(new_key), Z_STRLEN(new_key) TSRMLS_CC);
468 ZEND_SET_SYMBOL_WITH_LENGTH(&EG(symbol_table), Z_STRVAL(new_key), Z_STRLEN(new_key) + 1, *var, Z_REFCOUNT_PP(var) + 1, 0);
469
470 zval_dtor(&new_key);
471 return 0;
472}
473#else
474static int copy_request_variable(void *pDest, int num_args, va_list args, zend_hash_key *hash_key)
475{
476 char *prefix, *new_key;
477 uint prefix_len, new_key_len;
478 zval **var = (zval **) pDest;
479 TSRMLS_FETCH();
480
481 if (num_args != 2) {
482 return 0;
483 }
484
485 prefix = va_arg(args, char *);
486 prefix_len = va_arg(args, uint);
487
488 if (!prefix_len) {
489 if (!hash_key->nKeyLength) {
490 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Numeric key detected - possible security hazard.");
491 return 0;
492 } else if (!strcmp(hash_key->arKey, "GLOBALS")) {
493 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attempted GLOBALS variable overwrite.");
494 return 0;
495 }
496 }
497
498 if (hash_key->nKeyLength) {
499 new_key_len = prefix_len + hash_key->nKeyLength;
500 new_key = (char *) emalloc(new_key_len);
501
502 memcpy(new_key, prefix, prefix_len);
503 memcpy(new_key+prefix_len, hash_key->arKey, hash_key->nKeyLength);
504 } else {
505 new_key_len = spprintf(&new_key, 0, "%s%ld", prefix, hash_key->h);
506 new_key_len++;
507 }
508
509 if (php_varname_check(new_key, new_key_len-1, 1 TSRMLS_CC) == FAILURE || suhosin_is_protected_varname(new_key, new_key_len-1)) {
510 efree(new_key);
511 return 0;
512 }
513
514#if PHP_MAJOR_VERSION > 5 || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 0)
515 zend_delete_global_variable(new_key, new_key_len-1 TSRMLS_CC);
516#else
517 zend_hash_del(&EG(symbol_table), new_key, new_key_len-1);
518#endif
519 ZEND_SET_SYMBOL_WITH_LENGTH(&EG(symbol_table), new_key, new_key_len, *var, Z_REFCOUNT_PP(var)+1, 0);
520
521 efree(new_key);
522 return 0;
523}
524#endif
525
526/* {{{ proto bool import_request_variables(string types [, string prefix])
527 Import GET/POST/Cookie variables into the global scope */
528PHP_FUNCTION(suhosin_import_request_variables)
529{
530#if PHP_VERSION_ID >= 50300
531 char *types;
532 int types_len;
533 zval *prefix = NULL;
534 char *p;
535 zend_bool ok = 0;
536
537 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z/", &types, &types_len, &prefix) == FAILURE) {
538 return;
539 }
540
541 if (ZEND_NUM_ARGS() > 1) {
542 convert_to_string(prefix);
543
544 if (Z_STRLEN_P(prefix) == 0) {
545 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "No prefix specified - possible security hazard");
546 }
547 } else {
548 MAKE_STD_ZVAL(prefix);
549 ZVAL_EMPTY_STRING(prefix);
550 }
551
552 for (p = types; p && *p; p++) {
553 switch (*p) {
554
555 case 'g':
556 case 'G':
557 zend_hash_apply_with_arguments(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_GET]) TSRMLS_CC, (apply_func_args_t) copy_request_variable, 1, prefix);
558 ok = 1;
559 break;
560
561 case 'p':
562 case 'P':
563 zend_hash_apply_with_arguments(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_POST]) TSRMLS_CC, (apply_func_args_t) copy_request_variable, 1, prefix);
564 zend_hash_apply_with_arguments(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_FILES]) TSRMLS_CC, (apply_func_args_t) copy_request_variable, 1, prefix);
565 ok = 1;
566 break;
567
568 case 'c':
569 case 'C':
570 zend_hash_apply_with_arguments(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_COOKIE]) TSRMLS_CC, (apply_func_args_t) copy_request_variable, 1, prefix);
571 ok = 1;
572 break;
573 }
574 }
575
576 if (ZEND_NUM_ARGS() < 2) {
577 zval_ptr_dtor(&prefix);
578 }
579 RETURN_BOOL(ok);
580#else
581 zval **z_types, **z_prefix;
582 char *types, *prefix;
583 uint prefix_len;
584 char *p;
585 zend_bool ok = 0;
586
587 switch (ZEND_NUM_ARGS()) {
588
589 case 1:
590 if (zend_get_parameters_ex(1, &z_types) == FAILURE) {
591 RETURN_FALSE;
592 }
593 prefix = "";
594 prefix_len = 0;
595 break;
596
597 case 2:
598 if (zend_get_parameters_ex(2, &z_types, &z_prefix) == FAILURE) {
599 RETURN_FALSE;
600 }
601 convert_to_string_ex(z_prefix);
602 prefix = Z_STRVAL_PP(z_prefix);
603 prefix_len = Z_STRLEN_PP(z_prefix);
604 break;
605
606 default:
607 ZEND_WRONG_PARAM_COUNT();
608 }
609
610 if (prefix_len == 0) {
611 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "No prefix specified - possible security hazard");
612 }
613
614 convert_to_string_ex(z_types);
615 types = Z_STRVAL_PP(z_types);
616
617 for (p = types; p && *p; p++) {
618 switch (*p) {
619
620 case 'g':
621 case 'G':
622 zend_hash_apply_with_arguments(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_GET]), (apply_func_args_t) copy_request_variable, 2, prefix, prefix_len);
623 ok = 1;
624 break;
625
626 case 'p':
627 case 'P':
628 zend_hash_apply_with_arguments(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_POST]), (apply_func_args_t) copy_request_variable, 2, prefix, prefix_len);
629 zend_hash_apply_with_arguments(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_FILES]), (apply_func_args_t) copy_request_variable, 2, prefix, prefix_len);
630 ok = 1;
631 break;
632
633 case 'c':
634 case 'C':
635 zend_hash_apply_with_arguments(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_COOKIE]), (apply_func_args_t) copy_request_variable, 2, prefix, prefix_len);
636 ok = 1;
637 break;
638 }
639 }
640 RETURN_BOOL(ok);
641#endif
642}
643/* }}} */
644
645#endif /* SUHOSIN_HAVE_IRV */
646
647ZEND_BEGIN_ARG_INFO_EX(suhosin_arginfo_extract, 0, 0, 1) 247ZEND_BEGIN_ARG_INFO_EX(suhosin_arginfo_extract, 0, 0, 1)
648 ZEND_ARG_INFO(ZEND_SEND_PREFER_REF, arg) /* ARRAY_INFO(0, arg, 0) */ 248 ZEND_ARG_INFO(ZEND_SEND_PREFER_REF, arg) /* ARRAY_INFO(0, arg, 0) */
649 ZEND_ARG_INFO(0, extract_type) 249 ZEND_ARG_INFO(0, extract_type)
650 ZEND_ARG_INFO(0, prefix) 250 ZEND_ARG_INFO(0, prefix)
651ZEND_END_ARG_INFO() 251ZEND_END_ARG_INFO()
652 252
653#ifdef SUHOSIN_HAVE_IRV
654ZEND_BEGIN_ARG_INFO_EX(suhosin_arginfo_import_request_variables, 0, 0, 1)
655 ZEND_ARG_INFO(0, types)
656 ZEND_ARG_INFO(0, prefix)
657ZEND_END_ARG_INFO()
658#endif
659 253
660/* {{{ suhosin_ex_imp_functions[] 254/* {{{ suhosin_ex_imp_functions[]
661 */ 255 */
662zend_function_entry suhosin_ex_imp_functions[] = { 256zend_function_entry suhosin_ex_imp_functions[] = {
663 PHP_NAMED_FE(extract, PHP_FN(suhosin_extract), suhosin_arginfo_extract) 257 PHP_NAMED_FE(extract, PHP_FN(suhosin_extract), suhosin_arginfo_extract)
664#ifdef SUHOSIN_HAVE_IRV
665 PHP_NAMED_FE(import_request_variables, PHP_FN(suhosin_import_request_variables), suhosin_arginfo_import_request_variables)
666#endif
667 {NULL, NULL, NULL} 258 {NULL, NULL, NULL}
668}; 259};
669/* }}} */ 260/* }}} */
@@ -672,9 +263,6 @@ void suhosin_hook_ex_imp(TSRMLS_D)
672{ 263{
673 /* replace the extract and import_request_variables functions */ 264 /* replace the extract and import_request_variables functions */
674 zend_hash_del(CG(function_table), "extract", sizeof("extract")); 265 zend_hash_del(CG(function_table), "extract", sizeof("extract"));
675#ifdef SUHOSIN_HAVE_IRV
676 zend_hash_del(CG(function_table), "import_request_variables", sizeof("import_request_variables"));
677#endif
678#ifndef ZEND_ENGINE_2 266#ifndef ZEND_ENGINE_2
679 zend_register_functions(suhosin_ex_imp_functions, NULL, MODULE_PERSISTENT TSRMLS_CC); 267 zend_register_functions(suhosin_ex_imp_functions, NULL, MODULE_PERSISTENT TSRMLS_CC);
680#else 268#else
diff --git a/execute.c b/execute.c
index aa37fb9..9c078f7 100644
--- a/execute.c
+++ b/execute.c
@@ -859,11 +859,7 @@ int ih_mail(IH_HANDLER_PARAMS)
859 859
860int ih_querycheck(IH_HANDLER_PARAMS) 860int ih_querycheck(IH_HANDLER_PARAMS)
861{ 861{
862#ifdef PHP_ATLEAST_5_3 862 void **p = zend_vm_stack_top(TSRMLS_C) - 1;
863 void **p = zend_vm_stack_top(TSRMLS_C) - 1;
864#else
865 void **p = EG(argument_stack).top_element-2;
866#endif
867 unsigned long arg_count; 863 unsigned long arg_count;
868 zval **arg; 864 zval **arg;
869 char *query, *s, *e; 865 char *query, *s, *e;
@@ -1020,11 +1016,7 @@ int ih_querycheck(IH_HANDLER_PARAMS)
1020 1016
1021int ih_fixusername(IH_HANDLER_PARAMS) 1017int ih_fixusername(IH_HANDLER_PARAMS)
1022{ 1018{
1023#ifdef PHP_ATLEAST_5_3 1019 void **p = zend_vm_stack_top(TSRMLS_C) - 1;
1024 void **p = zend_vm_stack_top(TSRMLS_C) - 1;
1025#else
1026 void **p = EG(argument_stack).top_element-2;
1027#endif
1028 unsigned long arg_count; 1020 unsigned long arg_count;
1029 zval **arg; 1021 zval **arg;
1030 char *prefix, *postfix, *user, *user_match, *cp; 1022 char *prefix, *postfix, *user, *user_match, *cp;
@@ -1115,15 +1107,12 @@ int ih_fixusername(IH_HANDLER_PARAMS)
1115 1107
1116static int ih_function_exists(IH_HANDLER_PARAMS) 1108static int ih_function_exists(IH_HANDLER_PARAMS)
1117{ 1109{
1118#ifndef PHP_ATLEAST_5_3
1119 zval **function_name; 1110 zval **function_name;
1120#endif
1121 zend_function *func; 1111 zend_function *func;
1122 char *lcname; 1112 char *lcname;
1123 zend_bool retval; 1113 zend_bool retval;
1124 int func_name_len; 1114 int func_name_len;
1125 1115
1126#ifndef PHP_ATLEAST_5_3
1127 if (ZEND_NUM_ARGS()!=1 || zend_get_parameters_ex(1, &function_name)==FAILURE) { 1116 if (ZEND_NUM_ARGS()!=1 || zend_get_parameters_ex(1, &function_name)==FAILURE) {
1128 ZEND_WRONG_PARAM_COUNT_WITH_RETVAL(1); 1117 ZEND_WRONG_PARAM_COUNT_WITH_RETVAL(1);
1129 } 1118 }
@@ -1131,18 +1120,6 @@ static int ih_function_exists(IH_HANDLER_PARAMS)
1131 func_name_len = Z_STRLEN_PP(function_name); 1120 func_name_len = Z_STRLEN_PP(function_name);
1132 lcname = estrndup(Z_STRVAL_PP(function_name), func_name_len); 1121 lcname = estrndup(Z_STRVAL_PP(function_name), func_name_len);
1133 zend_str_tolower(lcname, func_name_len); 1122 zend_str_tolower(lcname, func_name_len);
1134#else
1135 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &lcname, &func_name_len) == FAILURE) {
1136 return (1);
1137 }
1138
1139 /* Ignore leading "\" */
1140 if (func_name_len > 0 && lcname[0] == '\\') {
1141 lcname = &lcname[1];
1142 func_name_len--;
1143 }
1144 lcname = zend_str_tolower_dup(lcname, func_name_len);
1145#endif
1146 1123
1147 retval = (zend_hash_find(EG(function_table), lcname, func_name_len+1, (void **)&func) == SUCCESS); 1124 retval = (zend_hash_find(EG(function_table), lcname, func_name_len+1, (void **)&func) == SUCCESS);
1148 1125
@@ -1559,17 +1536,9 @@ static int ih_rand(IH_HANDLER_PARAMS)
1559 1536
1560static int ih_getrandmax(IH_HANDLER_PARAMS) 1537static int ih_getrandmax(IH_HANDLER_PARAMS)
1561{ 1538{
1562#ifdef PHP_ATLEAST_5_3
1563 if (zend_parse_parameters_none() == FAILURE) { 1539 if (zend_parse_parameters_none() == FAILURE) {
1564 return(0); 1540 return(0);
1565 } 1541 }
1566#else
1567 int argc = ZEND_NUM_ARGS();
1568
1569 if (argc != 0) {
1570 ZEND_WRONG_PARAM_COUNT_WITH_RETVAL(1);
1571 }
1572#endif
1573 RETVAL_LONG(PHP_MT_RAND_MAX); 1542 RETVAL_LONG(PHP_MT_RAND_MAX);
1574 return (1); 1543 return (1);
1575} 1544}
@@ -1737,11 +1706,7 @@ static void suhosin_execute_internal(zend_execute_data *execute_data_ptr, int re
1737 1706
1738#if PHP_VERSION_ID < 50500 1707#if PHP_VERSION_ID < 50500
1739#ifdef ZEND_ENGINE_2 1708#ifdef ZEND_ENGINE_2
1740# if PHP_VERSION_ID < 50400
1741 return_value = (*(temp_variable *)((char *) execute_data_ptr->Ts + execute_data_ptr->opline->result.u.var)).var.ptr;
1742# else
1743 return_value = (*(temp_variable *)((char *) execute_data_ptr->Ts + execute_data_ptr->opline->result.var)).var.ptr; 1709 return_value = (*(temp_variable *)((char *) execute_data_ptr->Ts + execute_data_ptr->opline->result.var)).var.ptr;
1744# endif
1745#else 1710#else
1746 return_value = execute_data_ptr->Ts[execute_data_ptr->opline->result.u.var].var.ptr; 1711 return_value = execute_data_ptr->Ts[execute_data_ptr->opline->result.u.var].var.ptr;
1747#endif 1712#endif
diff --git a/header.c b/header.c
index ddb1296..5229910 100644
--- a/header.c
+++ b/header.c
@@ -32,11 +32,7 @@
32#include "SAPI.h" 32#include "SAPI.h"
33#include "php_variables.h" 33#include "php_variables.h"
34 34
35#if PHP_VERSION_ID >= 50300
36static int (*orig_header_handler)(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers TSRMLS_DC) = NULL; 35static int (*orig_header_handler)(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers TSRMLS_DC) = NULL;
37#else
38static int (*orig_header_handler)(sapi_header_struct *sapi_header, sapi_headers_struct *sapi_headers TSRMLS_DC) = NULL;
39#endif
40 36
41char *suhosin_encrypt_single_cookie(char *name, int name_len, char *value, int value_len, char *key TSRMLS_DC) 37char *suhosin_encrypt_single_cookie(char *name, int name_len, char *value, int value_len, char *key TSRMLS_DC)
42{ 38{
@@ -190,20 +186,14 @@ char *suhosin_cookie_decryptor(TSRMLS_D)
190 186
191/* {{{ suhosin_header_handler 187/* {{{ suhosin_header_handler
192 */ 188 */
193#if PHP_VERSION_ID >= 50300
194int suhosin_header_handler(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers TSRMLS_DC) 189int suhosin_header_handler(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers TSRMLS_DC)
195#else
196int suhosin_header_handler(sapi_header_struct *sapi_header, sapi_headers_struct *sapi_headers TSRMLS_DC)
197#endif
198{ 190{
199 int retval = SAPI_HEADER_ADD, i; 191 int retval = SAPI_HEADER_ADD, i;
200 char *tmp; 192 char *tmp;
201 193
202#if PHP_VERSION_ID >= 50300
203 if (op != SAPI_HEADER_ADD && op != SAPI_HEADER_REPLACE) { 194 if (op != SAPI_HEADER_ADD && op != SAPI_HEADER_REPLACE) {
204 goto suhosin_skip_header_handling; 195 goto suhosin_skip_header_handling;
205 } 196 }
206#endif
207 197
208 if (sapi_header && sapi_header->header) { 198 if (sapi_header && sapi_header->header) {
209 199
@@ -294,11 +284,7 @@ int suhosin_header_handler(sapi_header_struct *sapi_header, sapi_headers_struct
294suhosin_skip_header_handling: 284suhosin_skip_header_handling:
295 /* If existing call the sapi header handler */ 285 /* If existing call the sapi header handler */
296 if (orig_header_handler) { 286 if (orig_header_handler) {
297#if PHP_VERSION_ID >= 50300
298 retval = orig_header_handler(sapi_header, op, sapi_headers TSRMLS_CC); 287 retval = orig_header_handler(sapi_header, op, sapi_headers TSRMLS_CC);
299#else
300 retval = orig_header_handler(sapi_header, sapi_headers TSRMLS_CC);
301#endif
302 } 288 }
303 289
304 return retval; 290 return retval;
diff --git a/log.c b/log.c
index 1a4c783..f76737c 100644
--- a/log.c
+++ b/log.c
@@ -287,11 +287,7 @@ log_sapi:
287 /* SAPI Logging activated? */ 287 /* SAPI Logging activated? */
288 SDEBUG("(suhosin_log) log_syslog: %ld - log_sapi: %ld - log_script: %ld - log_phpscript: %ld", SUHOSIN_G(log_syslog), SUHOSIN_G(log_sapi), SUHOSIN_G(log_script), SUHOSIN_G(log_phpscript)); 288 SDEBUG("(suhosin_log) log_syslog: %ld - log_sapi: %ld - log_script: %ld - log_phpscript: %ld", SUHOSIN_G(log_syslog), SUHOSIN_G(log_sapi), SUHOSIN_G(log_script), SUHOSIN_G(log_phpscript));
289 if (((SUHOSIN_G(log_sapi)|S_INTERNAL) & loglevel)!=0) { 289 if (((SUHOSIN_G(log_sapi)|S_INTERNAL) & loglevel)!=0) {
290#if PHP_VERSION_ID < 50400
291 sapi_module.log_message(buf);
292#else
293 sapi_module.log_message(buf TSRMLS_CC); 290 sapi_module.log_message(buf TSRMLS_CC);
294#endif
295 } 291 }
296 if ((SUHOSIN_G(log_stdout) & loglevel)!=0) { 292 if ((SUHOSIN_G(log_stdout) & loglevel)!=0) {
297 fprintf(stdout, "%s\n", buf); 293 fprintf(stdout, "%s\n", buf);
@@ -372,9 +368,6 @@ log_phpscript:
372 zval *result = NULL; 368 zval *result = NULL;
373 369
374 long orig_execution_depth = SUHOSIN_G(execution_depth); 370 long orig_execution_depth = SUHOSIN_G(execution_depth);
375#if PHP_VERSION_ID < 50400
376 zend_bool orig_safe_mode = PG(safe_mode);
377#endif
378 char *orig_basedir = PG(open_basedir); 371 char *orig_basedir = PG(open_basedir);
379 372
380 char *phpscript = SUHOSIN_G(log_phpscriptname); 373 char *phpscript = SUHOSIN_G(log_phpscriptname);
@@ -411,18 +404,12 @@ SDEBUG("scriptname %s", SUHOSIN_G(log_phpscriptname));
411 404
412 SUHOSIN_G(execution_depth) = 0; 405 SUHOSIN_G(execution_depth) = 0;
413 if (SUHOSIN_G(log_phpscript_is_safe)) { 406 if (SUHOSIN_G(log_phpscript_is_safe)) {
414#if PHP_VERSION_ID < 50400
415 PG(safe_mode) = 0;
416#endif
417 PG(open_basedir) = NULL; 407 PG(open_basedir) = NULL;
418 } 408 }
419 409
420 zend_execute(new_op_array TSRMLS_CC); 410 zend_execute(new_op_array TSRMLS_CC);
421 411
422 SUHOSIN_G(execution_depth) = orig_execution_depth; 412 SUHOSIN_G(execution_depth) = orig_execution_depth;
423#if PHP_VERSION_ID < 50400
424 PG(safe_mode) = orig_safe_mode;
425#endif
426 PG(open_basedir) = orig_basedir; 413 PG(open_basedir) = orig_basedir;
427 414
428#ifdef ZEND_ENGINE_2 415#ifdef ZEND_ENGINE_2
diff --git a/php_suhosin.h b/php_suhosin.h
index 88890fb..d5a20ab 100644
--- a/php_suhosin.h
+++ b/php_suhosin.h
@@ -120,51 +120,6 @@ protected_varname:
120} 120}
121 121
122 122
123#if PHP_VERSION_ID < 50203
124static inline int php_varname_check(char *name, int name_len, zend_bool silent TSRMLS_DC) /* {{{ */
125{
126 if (name_len == sizeof("GLOBALS") - 1 && !memcmp(name, "GLOBALS", sizeof("GLOBALS") - 1)) {
127 if (!silent) {
128 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attempted GLOBALS variable overwrite");
129 }
130 return FAILURE;
131 } else if (name[0] == '_' &&
132 (
133 (name_len == sizeof("_GET") - 1 && !memcmp(name, "_GET", sizeof("_GET") - 1)) ||
134 (name_len == sizeof("_POST") - 1 && !memcmp(name, "_POST", sizeof("_POST") - 1)) ||
135 (name_len == sizeof("_COOKIE") - 1 && !memcmp(name, "_COOKIE", sizeof("_COOKIE") - 1)) ||
136 (name_len == sizeof("_ENV") - 1 && !memcmp(name, "_ENV", sizeof("_ENV") - 1)) ||
137 (name_len == sizeof("_SERVER") - 1 && !memcmp(name, "_SERVER", sizeof("_SERVER") - 1)) ||
138 (name_len == sizeof("_SESSION") - 1 && !memcmp(name, "_SESSION", sizeof("_SESSION") - 1)) ||
139 (name_len == sizeof("_FILES") - 1 && !memcmp(name, "_FILES", sizeof("_FILES") - 1)) ||
140 (name_len == sizeof("_REQUEST") -1 && !memcmp(name, "_REQUEST", sizeof("_REQUEST") - 1))
141 )
142 ) {
143 if (!silent) {
144 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attempted super-global (%s) variable overwrite", name);
145 }
146 return FAILURE;
147 } else if (name[0] == 'H' &&
148 (
149 (name_len == sizeof("HTTP_POST_VARS") - 1 && !memcmp(name, "HTTP_POST_VARS", sizeof("HTTP_POST_VARS") - 1)) ||
150 (name_len == sizeof("HTTP_GET_VARS") - 1 && !memcmp(name, "HTTP_GET_VARS", sizeof("HTTP_GET_VARS") - 1)) ||
151 (name_len == sizeof("HTTP_COOKIE_VARS") - 1 && !memcmp(name, "HTTP_COOKIE_VARS", sizeof("HTTP_COOKIE_VARS") - 1)) ||
152 (name_len == sizeof("HTTP_ENV_VARS") - 1 && !memcmp(name, "HTTP_ENV_VARS", sizeof("HTTP_ENV_VARS") - 1)) ||
153 (name_len == sizeof("HTTP_SERVER_VARS") - 1 && !memcmp(name, "HTTP_SERVER_VARS", sizeof("HTTP_SERVER_VARS") - 1)) ||
154 (name_len == sizeof("HTTP_SESSION_VARS") - 1 && !memcmp(name, "HTTP_SESSION_VARS", sizeof("HTTP_SESSION_VARS") - 1)) ||
155 (name_len == sizeof("HTTP_RAW_POST_DATA") - 1 && !memcmp(name, "HTTP_RAW_POST_DATA", sizeof("HTTP_RAW_POST_DATA") - 1)) ||
156 (name_len == sizeof("HTTP_POST_FILES") - 1 && !memcmp(name, "HTTP_POST_FILES", sizeof("HTTP_POST_FILES") - 1))
157 )
158 ) {
159 if (!silent) {
160 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attempted long input array (%s) overwrite", name);
161 }
162 return FAILURE;
163 }
164 return SUCCESS;
165}
166#endif
167
168ZEND_BEGIN_MODULE_GLOBALS(suhosin) 123ZEND_BEGIN_MODULE_GLOBALS(suhosin)
169 zend_uint in_code_type; 124 zend_uint in_code_type;
170 long execution_depth; 125 long execution_depth;
@@ -452,82 +407,6 @@ void suhosin_bailout(TSRMLS_D);
452size_t suhosin_strnspn(const char *input, size_t n, const char *accept); 407size_t suhosin_strnspn(const char *input, size_t n, const char *accept);
453size_t suhosin_strncspn(const char *input, size_t n, const char *reject); 408size_t suhosin_strncspn(const char *input, size_t n, const char *reject);
454 409
455/* Add pseudo refcount macros for PHP version < 5.3 */
456#ifndef Z_REFCOUNT_PP
457
458#define Z_REFCOUNT_PP(ppz) Z_REFCOUNT_P(*(ppz))
459#define Z_SET_REFCOUNT_PP(ppz, rc) Z_SET_REFCOUNT_P(*(ppz), rc)
460#define Z_ADDREF_PP(ppz) Z_ADDREF_P(*(ppz))
461#define Z_DELREF_PP(ppz) Z_DELREF_P(*(ppz))
462#define Z_ISREF_PP(ppz) Z_ISREF_P(*(ppz))
463#define Z_SET_ISREF_PP(ppz) Z_SET_ISREF_P(*(ppz))
464#define Z_UNSET_ISREF_PP(ppz) Z_UNSET_ISREF_P(*(ppz))
465#define Z_SET_ISREF_TO_PP(ppz, isref) Z_SET_ISREF_TO_P(*(ppz), isref)
466
467#define Z_REFCOUNT_P(pz) zval_refcount_p(pz)
468#define Z_SET_REFCOUNT_P(pz, rc) zval_set_refcount_p(pz, rc)
469#define Z_ADDREF_P(pz) zval_addref_p(pz)
470#define Z_DELREF_P(pz) zval_delref_p(pz)
471#define Z_ISREF_P(pz) zval_isref_p(pz)
472#define Z_SET_ISREF_P(pz) zval_set_isref_p(pz)
473#define Z_UNSET_ISREF_P(pz) zval_unset_isref_p(pz)
474#define Z_SET_ISREF_TO_P(pz, isref) zval_set_isref_to_p(pz, isref)
475
476#define Z_REFCOUNT(z) Z_REFCOUNT_P(&(z))
477#define Z_SET_REFCOUNT(z, rc) Z_SET_REFCOUNT_P(&(z), rc)
478#define Z_ADDREF(z) Z_ADDREF_P(&(z))
479#define Z_DELREF(z) Z_DELREF_P(&(z))
480#define Z_ISREF(z) Z_ISREF_P(&(z))
481#define Z_SET_ISREF(z) Z_SET_ISREF_P(&(z))
482#define Z_UNSET_ISREF(z) Z_UNSET_ISREF_P(&(z))
483#define Z_SET_ISREF_TO(z, isref) Z_SET_ISREF_TO_P(&(z), isref)
484
485#if defined(__GNUC__)
486#define zend_always_inline inline __attribute__((always_inline))
487#elif defined(_MSC_VER)
488#define zend_always_inline __forceinline
489#else
490#define zend_always_inline inline
491#endif
492
493static zend_always_inline zend_uint zval_refcount_p(zval* pz) {
494 return pz->refcount;
495}
496
497static zend_always_inline zend_uint zval_set_refcount_p(zval* pz, zend_uint rc) {
498 return pz->refcount = rc;
499}
500
501static zend_always_inline zend_uint zval_addref_p(zval* pz) {
502 return ++pz->refcount;
503}
504
505static zend_always_inline zend_uint zval_delref_p(zval* pz) {
506 return --pz->refcount;
507}
508
509static zend_always_inline zend_bool zval_isref_p(zval* pz) {
510 return pz->is_ref;
511}
512
513static zend_always_inline zend_bool zval_set_isref_p(zval* pz) {
514 return pz->is_ref = 1;
515}
516
517static zend_always_inline zend_bool zval_unset_isref_p(zval* pz) {
518 return pz->is_ref = 0;
519}
520
521static zend_always_inline zend_bool zval_set_isref_to_p(zval* pz, zend_bool isref) {
522 return pz->is_ref = isref;
523}
524
525#else
526
527#define PHP_ATLEAST_5_3 true
528
529#endif
530
531 410
532#endif /* PHP_SUHOSIN_H */ 411#endif /* PHP_SUHOSIN_H */
533 412
diff --git a/post_handler.c b/post_handler.c
index 737f33f..ec40387 100644
--- a/post_handler.c
+++ b/post_handler.c
@@ -46,9 +46,8 @@ SAPI_POST_HANDLER_FUNC(suhosin_std_post_handler)
46{ 46{
47 char *var, *val, *e, *s, *p; 47 char *var, *val, *e, *s, *p;
48 zval *array_ptr = (zval *) arg; 48 zval *array_ptr = (zval *) arg;
49#if PHP_VERSION_ID >= 50311
50 long count = 0; 49 long count = 0;
51#endif 50
52 if (SG(request_info).post_data == NULL) { 51 if (SG(request_info).post_data == NULL) {
53 return; 52 return;
54 } 53 }
@@ -61,12 +60,10 @@ last_value:
61 if ((val = memchr(s, '=', (p - s)))) { /* have a value */ 60 if ((val = memchr(s, '=', (p - s)))) { /* have a value */
62 unsigned int val_len, new_val_len; 61 unsigned int val_len, new_val_len;
63 62
64#if PHP_VERSION_ID >= 50311
65 if (++count > PG(max_input_vars)) { 63 if (++count > PG(max_input_vars)) {
66 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Input variables exceeded %ld. To increase the limit change max_input_vars in php.ini.", PG(max_input_vars)); 64 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Input variables exceeded %ld. To increase the limit change max_input_vars in php.ini.", PG(max_input_vars));
67 return; 65 return;
68 } 66 }
69#endif
70 var = s; 67 var = s;
71 68
72 php_url_decode(var, (val - s)); 69 php_url_decode(var, (val - s));
@@ -266,15 +263,9 @@ void suhosin_hook_post_handlers(TSRMLS_D)
266 HashTable tempht; 263 HashTable tempht;
267 zend_ini_entry *ini_entry; 264 zend_ini_entry *ini_entry;
268 265
269#if PHP_MAJOR_VERSION > 5 || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 0)
270 sapi_unregister_post_entry(&suhosin_post_entries[0] TSRMLS_CC); 266 sapi_unregister_post_entry(&suhosin_post_entries[0] TSRMLS_CC);
271 sapi_unregister_post_entry(&suhosin_post_entries[1] TSRMLS_CC); 267 sapi_unregister_post_entry(&suhosin_post_entries[1] TSRMLS_CC);
272 sapi_register_post_entries(suhosin_post_entries TSRMLS_CC); 268 sapi_register_post_entries(suhosin_post_entries TSRMLS_CC);
273#else
274 sapi_unregister_post_entry(&suhosin_post_entries[0]);
275 sapi_unregister_post_entry(&suhosin_post_entries[1]);
276 sapi_register_post_entries(suhosin_post_entries);
277#endif
278 269
279 /* we want to get notified if another extension deregisters the suhosin post handlers */ 270 /* we want to get notified if another extension deregisters the suhosin post handlers */
280 271
diff --git a/rfc1867.c b/rfc1867.c
deleted file mode 100644
index e19c677..0000000
--- a/rfc1867.c
+++ /dev/null
@@ -1,1397 +0,0 @@
1/*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2006 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Authors: Rasmus Lerdorf <rasmus@php.net> |
16 | Jani Taskinen <sniper@php.net> |
17 +----------------------------------------------------------------------+
18 */
19
20/* $Id: rfc1867.c,v 1.1.1.1 2007-11-28 01:15:35 sesser Exp $ */
21
22/*
23 * This product includes software developed by the Apache Group
24 * for use in the Apache HTTP server project (http://www.apache.org/).
25 *
26 */
27
28#include <stdio.h>
29#include "php.h"
30#include "php_open_temporary_file.h"
31#include "zend_globals.h"
32#include "php_globals.h"
33#include "php_variables.h"
34#include "php_suhosin.h"
35#include "suhosin_rfc1867.h"
36#include "php_ini.h"
37#include "ext/standard/php_string.h"
38
39#if PHP_VERSION_ID < 50400
40
41#define DEBUG_FILE_UPLOAD ZEND_DEBUG
42
43#if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
44#include "ext/mbstring/mbstring.h"
45
46static void safe_php_register_variable(char *var, char *strval, zval *track_vars_array, zend_bool override_protection TSRMLS_DC);
47
48#define SAFE_RETURN { \
49 php_mb_flush_gpc_variables(num_vars, val_list, len_list, array_ptr TSRMLS_CC); \
50 if (lbuf) efree(lbuf); \
51 if (abuf) efree(abuf); \
52 if (array_index) efree(array_index); \
53 zend_hash_destroy(&PG(rfc1867_protected_variables)); \
54 zend_llist_destroy(&header); \
55 if (mbuff->boundary_next) efree(mbuff->boundary_next); \
56 if (mbuff->boundary) efree(mbuff->boundary); \
57 if (mbuff->buffer) efree(mbuff->buffer); \
58 if (mbuff) efree(mbuff); \
59 return; }
60
61static void php_mb_flush_gpc_variables(int num_vars, char **val_list, int *len_list, zval *array_ptr TSRMLS_DC)
62{
63 int i;
64 if (php_mb_encoding_translation(TSRMLS_C)) {
65 if (num_vars > 0 &&
66 php_mb_gpc_encoding_detector(val_list, len_list, num_vars, NULL TSRMLS_CC) == SUCCESS) {
67 php_mb_gpc_encoding_converter(val_list, len_list, num_vars, NULL, NULL TSRMLS_CC);
68 }
69 for (i=0; i<num_vars; i+=2){
70 safe_php_register_variable(val_list[i], val_list[i+1], array_ptr, 0 TSRMLS_CC);
71 efree(val_list[i]);
72 efree(val_list[i+1]);
73 }
74 efree(val_list);
75 efree(len_list);
76 }
77}
78
79static void php_mb_gpc_realloc_buffer(char ***pval_list, int **plen_list, int *num_vars_max, int inc TSRMLS_DC)
80{
81 /* allow only even increments */
82 if (inc & 1) {
83 inc++;
84 }
85 (*num_vars_max) += inc;
86 *pval_list = (char **)erealloc(*pval_list, (*num_vars_max+2)*sizeof(char *));
87 *plen_list = (int *)erealloc(*plen_list, (*num_vars_max+2)*sizeof(int));
88}
89
90static void php_mb_gpc_stack_variable(char *param, char *value, char ***pval_list, int **plen_list, int *num_vars, int *num_vars_max TSRMLS_DC)
91{
92 char **val_list=*pval_list;
93 int *len_list=*plen_list;
94
95 if (*num_vars>=*num_vars_max){
96 php_mb_gpc_realloc_buffer(pval_list, plen_list, num_vars_max,
97 16 TSRMLS_CC);
98 /* in case realloc relocated the buffer */
99 val_list = *pval_list;
100 len_list = *plen_list;
101 }
102
103 val_list[*num_vars] = (char *)estrdup(param);
104 len_list[*num_vars] = strlen(param);
105 (*num_vars)++;
106 val_list[*num_vars] = (char *)estrdup(value);
107 len_list[*num_vars] = strlen(value);
108 (*num_vars)++;
109}
110
111#else
112
113#define SAFE_RETURN { \
114 if (lbuf) efree(lbuf); \
115 if (abuf) efree(abuf); \
116 if (array_index) efree(array_index); \
117 zend_hash_destroy(&PG(rfc1867_protected_variables)); \
118 zend_llist_destroy(&header); \
119 if (mbuff->boundary_next) efree(mbuff->boundary_next); \
120 if (mbuff->boundary) efree(mbuff->boundary); \
121 if (mbuff->buffer) efree(mbuff->buffer); \
122 if (mbuff) efree(mbuff); \
123 return; }
124#endif
125
126/* The longest property name we use in an uploaded file array */
127#define MAX_SIZE_OF_INDEX sizeof("[tmp_name]")
128
129/* The longest anonymous name */
130#define MAX_SIZE_ANONNAME 33
131
132/* Errors */
133#define UPLOAD_ERROR_OK 0 /* File upload succesful */
134#define UPLOAD_ERROR_A 1 /* Uploaded file exceeded upload_max_filesize */
135#define UPLOAD_ERROR_B 2 /* Uploaded file exceeded MAX_FILE_SIZE */
136#define UPLOAD_ERROR_C 3 /* Partially uploaded */
137#define UPLOAD_ERROR_D 4 /* No file uploaded */
138#define UPLOAD_ERROR_E 6 /* Missing /tmp or similar directory */
139#define UPLOAD_ERROR_F 7 /* Failed to write file to disk */
140#define UPLOAD_ERROR_X 8 /* File upload stopped by extension */
141
142/*
143void php_rfc1867_register_constants(TSRMLS_D)
144{
145 REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_OK", UPLOAD_ERROR_OK, CONST_CS | CONST_PERSISTENT);
146 REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_INI_SIZE", UPLOAD_ERROR_A, CONST_CS | CONST_PERSISTENT);
147 REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_FORM_SIZE", UPLOAD_ERROR_B, CONST_CS | CONST_PERSISTENT);
148 REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_PARTIAL", UPLOAD_ERROR_C, CONST_CS | CONST_PERSISTENT);
149 REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_NO_FILE", UPLOAD_ERROR_D, CONST_CS | CONST_PERSISTENT);
150 REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_NO_TMP_DIR", UPLOAD_ERROR_E, CONST_CS | CONST_PERSISTENT);
151 REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_CANT_WRITE", UPLOAD_ERROR_F, CONST_CS | CONST_PERSISTENT);
152 REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_EXTENSION", UPLOAD_ERROR_X, CONST_CS | CONST_PERSISTENT);
153}
154*/
155
156static void normalize_protected_variable(char *varname TSRMLS_DC)
157{
158 char *s=varname, *index=NULL, *indexend=NULL, *p;
159
160 /* overjump leading space */
161 while (*s == ' ') {
162 s++;
163 }
164
165 /* and remove it */
166 if (s != varname) {
167 memmove(varname, s, strlen(s)+1);
168 }
169
170 for (p=varname; *p && *p != '['; p++) {
171 switch(*p) {
172 case ' ':
173 case '.':
174 *p='_';
175 break;
176 }
177 }
178
179 /* find index */
180 index = strchr(varname, '[');
181 if (index) {
182 index++;
183 s=index;
184 } else {
185 return;
186 }
187
188 /* done? */
189 while (index) {
190
191 while (*index == ' ' || *index == '\r' || *index == '\n' || *index=='\t') {
192 index++;
193 }
194 indexend = strchr(index, ']');
195 indexend = indexend ? indexend + 1 : index + strlen(index);
196
197 if (s != index) {
198 memmove(s, index, strlen(index)+1);
199 s += indexend-index;
200 } else {
201 s = indexend;
202 }
203
204 if (*s == '[') {
205 s++;
206 index = s;
207 } else {
208 index = NULL;
209 }
210 }
211 *s++='\0';
212}
213
214
215static void add_protected_variable(char *varname TSRMLS_DC)
216{
217 int dummy=1;
218
219 normalize_protected_variable(varname TSRMLS_CC);
220 zend_hash_add(&PG(rfc1867_protected_variables), varname, strlen(varname)+1, &dummy, sizeof(int), NULL);
221}
222
223
224static zend_bool is_protected_variable(char *varname TSRMLS_DC)
225{
226 normalize_protected_variable(varname TSRMLS_CC);
227 return zend_hash_exists(&PG(rfc1867_protected_variables), varname, strlen(varname)+1);
228}
229
230
231static void safe_php_register_variable(char *var, char *strval, zval *track_vars_array, zend_bool override_protection TSRMLS_DC)
232{
233 if (override_protection || !is_protected_variable(var TSRMLS_CC)) {
234 php_register_variable(var, strval, track_vars_array TSRMLS_CC);
235 }
236}
237
238
239static void safe_php_register_variable_ex(char *var, zval *val, zval *track_vars_array, zend_bool override_protection TSRMLS_DC)
240{
241 if (override_protection || !is_protected_variable(var TSRMLS_CC)) {
242 php_register_variable_ex(var, val, track_vars_array TSRMLS_CC);
243 }
244}
245
246
247static void register_http_post_files_variable(char *strvar, char *val, zval *http_post_files, zend_bool override_protection TSRMLS_DC)
248{
249#if PHP_VERSION_ID < 50400
250 int register_globals = PG(register_globals);
251
252 PG(register_globals) = 0;
253#endif
254 safe_php_register_variable(strvar, val, http_post_files, override_protection TSRMLS_CC);
255#if PHP_VERSION_ID < 50400
256 PG(register_globals) = register_globals;
257#endif
258}
259
260
261static void register_http_post_files_variable_ex(char *var, zval *val, zval *http_post_files, zend_bool override_protection TSRMLS_DC)
262{
263#if PHP_VERSION_ID < 50400
264 int register_globals = PG(register_globals);
265
266 PG(register_globals) = 0;
267#endif
268 safe_php_register_variable_ex(var, val, http_post_files, override_protection TSRMLS_CC);
269#if PHP_VERSION_ID < 50400
270 PG(register_globals) = register_globals;
271#endif
272}
273
274/*
275 * Following code is based on apache_multipart_buffer.c from libapreq-0.33 package.
276 *
277 */
278
279#define FILLUNIT (1024 * 5)
280
281typedef struct {
282
283 /* read buffer */
284 char *buffer;
285 char *buf_begin;
286 int bufsize;
287 int bytes_in_buffer;
288
289 /* boundary info */
290 char *boundary;
291 char *boundary_next;
292 int boundary_next_len;
293
294} multipart_buffer;
295
296
297typedef struct {
298 char *key;
299 char *value;
300} mime_header_entry;
301
302
303/*
304 fill up the buffer with client data.
305 returns number of bytes added to buffer.
306*/
307static int fill_buffer(multipart_buffer *self TSRMLS_DC)
308{
309 int bytes_to_read, total_read = 0, actual_read = 0;
310
311 /* shift the existing data if necessary */
312 if (self->bytes_in_buffer > 0 && self->buf_begin != self->buffer) {
313 memmove(self->buffer, self->buf_begin, self->bytes_in_buffer);
314 }
315
316 self->buf_begin = self->buffer;
317
318 /* calculate the free space in the buffer */
319 bytes_to_read = self->bufsize - self->bytes_in_buffer;
320
321 /* read the required number of bytes */
322 while (bytes_to_read > 0) {
323
324 char *buf = self->buffer + self->bytes_in_buffer;
325
326 actual_read = sapi_module.read_post(buf, bytes_to_read TSRMLS_CC);
327
328 /* update the buffer length */
329 if (actual_read > 0) {
330 self->bytes_in_buffer += actual_read;
331 SG(read_post_bytes) += actual_read;
332 total_read += actual_read;
333 bytes_to_read -= actual_read;
334 } else {
335 break;
336 }
337 }
338
339 return total_read;
340}
341
342
343/* eof if we are out of bytes, or if we hit the final boundary */
344static int multipart_buffer_eof(multipart_buffer *self TSRMLS_DC)
345{
346 if ( (self->bytes_in_buffer == 0 && fill_buffer(self TSRMLS_CC) < 1) ) {
347 return 1;
348 } else {
349 return 0;
350 }
351}
352
353
354/* create new multipart_buffer structure */
355static multipart_buffer *multipart_buffer_new(char *boundary, int boundary_len)
356{
357 multipart_buffer *self = (multipart_buffer *) ecalloc(1, sizeof(multipart_buffer));
358
359 int minsize = boundary_len + 6;
360 if (minsize < FILLUNIT) minsize = FILLUNIT;
361
362 self->buffer = (char *) ecalloc(1, minsize + 1);
363 self->bufsize = minsize;
364
365 self->boundary = (char *) ecalloc(1, boundary_len + 3);
366 sprintf(self->boundary, "--%s", boundary);
367
368 self->boundary_next = (char *) ecalloc(1, boundary_len + 4);
369 sprintf(self->boundary_next, "\n--%s", boundary);
370 self->boundary_next_len = boundary_len + 3;
371
372 self->buf_begin = self->buffer;
373 self->bytes_in_buffer = 0;
374
375 return self;
376}
377
378
379/*
380 gets the next CRLF terminated line from the input buffer.
381 if it doesn't find a CRLF, and the buffer isn't completely full, returns
382 NULL; otherwise, returns the beginning of the null-terminated line,
383 minus the CRLF.
384
385 note that we really just look for LF terminated lines. this works
386 around a bug in internet explorer for the macintosh which sends mime
387 boundaries that are only LF terminated when you use an image submit
388 button in a multipart/form-data form.
389 */
390static char *next_line(multipart_buffer *self)
391{
392 /* look for LF in the data */
393 char* line = self->buf_begin;
394 char* ptr = memchr(self->buf_begin, '\n', self->bytes_in_buffer);
395
396 if (ptr) { /* LF found */
397
398 /* terminate the string, remove CRLF */
399 if ((ptr - line) > 0 && *(ptr-1) == '\r') {
400 *(ptr-1) = 0;
401 } else {
402 *ptr = 0;
403 }
404
405 /* bump the pointer */
406 self->buf_begin = ptr + 1;
407 self->bytes_in_buffer -= (self->buf_begin - line);
408
409 } else { /* no LF found */
410
411 /* buffer isn't completely full, fail */
412 if (self->bytes_in_buffer < self->bufsize) {
413 return NULL;
414 }
415 /* return entire buffer as a partial line */
416 line[self->bufsize] = 0;
417 self->buf_begin = ptr;
418 self->bytes_in_buffer = 0;
419 }
420
421 return line;
422}
423
424
425/* returns the next CRLF terminated line from the client */
426static char *get_line(multipart_buffer *self TSRMLS_DC)
427{
428 char* ptr = next_line(self);
429
430 if (!ptr) {
431 fill_buffer(self TSRMLS_CC);
432 ptr = next_line(self);
433 }
434
435 return ptr;
436}
437
438
439/* Free header entry */
440static void php_free_hdr_entry(mime_header_entry *h)
441{
442 if (h->key) {
443 efree(h->key);
444 }
445 if (h->value) {
446 efree(h->value);
447 }
448}
449
450
451/* finds a boundary */
452static int find_boundary(multipart_buffer *self, char *boundary TSRMLS_DC)
453{
454 char *line;
455
456 /* loop thru lines */
457 while( (line = get_line(self TSRMLS_CC)) )
458 {
459 /* finished if we found the boundary */
460 if (!strcmp(line, boundary)) {
461 return 1;
462 }
463 }
464
465 /* didn't find the boundary */
466 return 0;
467}
468
469
470/* parse headers */
471static int multipart_buffer_headers(multipart_buffer *self, zend_llist *header TSRMLS_DC)
472{
473 char *line;
474 mime_header_entry prev_entry, entry;
475 int prev_len, cur_len;
476
477 /* didn't find boundary, abort */
478 if (!find_boundary(self, self->boundary TSRMLS_CC)) {
479 return 0;
480 }
481
482 /* get lines of text, or CRLF_CRLF */
483
484 while( (line = get_line(self TSRMLS_CC)) && strlen(line) > 0 )
485 {
486 /* add header to table */
487
488 char *key = line;
489 char *value = NULL;
490
491 /* space in the beginning means same header */
492 if (!isspace(line[0])) {
493 value = strchr(line, ':');
494 }
495
496 if (value) {
497 *value = 0;
498 do { value++; } while(isspace(*value));
499
500 entry.value = estrdup(value);
501 entry.key = estrdup(key);
502
503 } else if (zend_llist_count(header)) { /* If no ':' on the line, add to previous line */
504
505 prev_len = strlen(prev_entry.value);
506 cur_len = strlen(line);
507
508 entry.value = emalloc(prev_len + cur_len + 1);
509 memcpy(entry.value, prev_entry.value, prev_len);
510 memcpy(entry.value + prev_len, line, cur_len);
511 entry.value[cur_len + prev_len] = '\0';
512
513 entry.key = estrdup(prev_entry.key);
514
515 zend_llist_remove_tail(header);
516 } else {
517 continue;
518 }
519
520 zend_llist_add_element(header, &entry);
521 prev_entry = entry;
522 }
523
524 return 1;
525}
526
527
528static char *php_mime_get_hdr_value(zend_llist header, char *key)
529{
530 mime_header_entry *entry;
531
532 if (key == NULL) {
533 return NULL;
534 }
535
536 entry = zend_llist_get_first(&header);
537 while (entry) {
538 if (!strcasecmp(entry->key, key)) {
539 return entry->value;
540 }
541 entry = zend_llist_get_next(&header);
542 }
543
544 return NULL;
545}
546
547
548static char *php_ap_getword(char **line, char stop)
549{
550 char *pos = *line, quote;
551 char *res;
552
553 while (*pos && *pos != stop) {
554
555 if ((quote = *pos) == '"' || quote == '\'') {
556 ++pos;
557 while (*pos && *pos != quote) {
558 if (*pos == '\\' && pos[1] && pos[1] == quote) {
559 pos += 2;
560 } else {
561 ++pos;
562 }
563 }
564 if (*pos) {
565 ++pos;
566 }
567 } else ++pos;
568
569 }
570 if (*pos == '\0') {
571 res = estrdup(*line);
572 *line += strlen(*line);
573 return res;
574 }
575
576 res = estrndup(*line, pos - *line);
577
578 while (*pos == stop) {
579 ++pos;
580 }
581
582 *line = pos;
583 return res;
584}
585
586
587static char *substring_conf(char *start, int len, char quote TSRMLS_DC)
588{
589 char *result = emalloc(len + 2);
590 char *resp = result;
591 int i;
592
593 for (i = 0; i < len; ++i) {
594 if (start[i] == '\\' && (start[i + 1] == '\\' || (quote && start[i + 1] == quote))) {
595 *resp++ = start[++i];
596 } else {
597#if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
598 if (php_mb_encoding_translation(TSRMLS_C)) {
599 size_t j = php_mb_gpc_mbchar_bytes(start+i TSRMLS_CC);
600 while (j-- > 0 && i < len) {
601 *resp++ = start[i++];
602 }
603 --i;
604 } else {
605 *resp++ = start[i];
606 }
607#else
608 *resp++ = start[i];
609#endif
610 }
611 }
612
613 *resp++ = '\0';
614 return result;
615}
616
617
618static char *php_ap_getword_conf(char **line TSRMLS_DC)
619{
620 char *str = *line, *strend, *res, quote;
621
622#if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
623 if (php_mb_encoding_translation(TSRMLS_C)) {
624 int len=strlen(str);
625 php_mb_gpc_encoding_detector(&str, &len, 1, NULL TSRMLS_CC);
626 }
627#endif
628
629 while (*str && isspace(*str)) {
630 ++str;
631 }
632
633 if (!*str) {
634 *line = str;
635 return estrdup("");
636 }
637
638 if ((quote = *str) == '"' || quote == '\'') {
639 strend = str + 1;
640look_for_quote:
641 while (*strend && *strend != quote) {
642 if (*strend == '\\' && strend[1] && strend[1] == quote) {
643 strend += 2;
644 } else {
645 ++strend;
646 }
647 }
648 if (*strend && *strend == quote) {
649 char p = *(strend + 1);
650 if (p != '\r' && p != '\n' && p != '\0') {
651 strend++;
652 goto look_for_quote;
653 }
654 }
655
656 res = substring_conf(str + 1, strend - str - 1, quote TSRMLS_CC);
657
658 if (*strend == quote) {
659 ++strend;
660 }
661
662 } else {
663
664 strend = str;
665 while (*strend && !isspace(*strend)) {
666 ++strend;
667 }
668 res = substring_conf(str, strend - str, 0 TSRMLS_CC);
669 }
670
671 while (*strend && isspace(*strend)) {
672 ++strend;
673 }
674
675 *line = strend;
676 return res;
677}
678
679
680/*
681 search for a string in a fixed-length byte string.
682 if partial is true, partial matches are allowed at the end of the buffer.
683 returns NULL if not found, or a pointer to the start of the first match.
684*/
685static void *php_ap_memstr(char *haystack, int haystacklen, char *needle, int needlen, int partial)
686{
687 int len = haystacklen;
688 char *ptr = haystack;
689
690 /* iterate through first character matches */
691 while( (ptr = memchr(ptr, needle[0], len)) ) {
692
693 /* calculate length after match */
694 len = haystacklen - (ptr - (char *)haystack);
695
696 /* done if matches up to capacity of buffer */
697 if (memcmp(needle, ptr, needlen < len ? needlen : len) == 0 && (partial || len >= needlen)) {
698 break;
699 }
700
701 /* next character */
702 ptr++; len--;
703 }
704
705 return ptr;
706}
707
708
709/* read until a boundary condition */
710static int multipart_buffer_read(multipart_buffer *self, char *buf, int bytes, int *end TSRMLS_DC)
711{
712 int len, max;
713 char *bound;
714
715 /* fill buffer if needed */
716 if (bytes > self->bytes_in_buffer) {
717 fill_buffer(self TSRMLS_CC);
718 }
719
720 /* look for a potential boundary match, only read data up to that point */
721 if ((bound = php_ap_memstr(self->buf_begin, self->bytes_in_buffer, self->boundary_next, self->boundary_next_len, 1))) {
722 max = bound - self->buf_begin;
723 if (end && php_ap_memstr(self->buf_begin, self->bytes_in_buffer, self->boundary_next, self->boundary_next_len, 0)) {
724 *end = 1;
725 }
726 } else {
727 max = self->bytes_in_buffer;
728 }
729
730 /* maximum number of bytes we are reading */
731 len = max < bytes-1 ? max : bytes-1;
732
733 /* if we read any data... */
734 if (len > 0) {
735
736 /* copy the data */
737 memcpy(buf, self->buf_begin, len);
738 buf[len] = 0;
739
740 if (bound && len > 0 && buf[len-1] == '\r') {
741 buf[--len] = 0;
742 }
743
744 /* update the buffer */
745 self->bytes_in_buffer -= len;
746 self->buf_begin += len;
747 }
748
749 return len;
750}
751
752
753/*
754 XXX: this is horrible memory-usage-wise, but we only expect
755 to do this on small pieces of form data.
756*/
757static char *multipart_buffer_read_body(multipart_buffer *self, unsigned int *len TSRMLS_DC)
758{
759 char buf[FILLUNIT], *out=NULL;
760 int total_bytes=0, read_bytes=0;
761
762 while((read_bytes = multipart_buffer_read(self, buf, sizeof(buf), NULL TSRMLS_CC))) {
763 out = erealloc(out, total_bytes + read_bytes + 1);
764 memcpy(out + total_bytes, buf, read_bytes);
765 total_bytes += read_bytes;
766 }
767
768 if (out) out[total_bytes] = '\0';
769 *len = total_bytes;
770
771 return out;
772}
773
774
775/*
776 * The combined READER/HANDLER
777 *
778 */
779
780SAPI_POST_HANDLER_FUNC(suhosin_rfc1867_post_handler)
781{
782 char *boundary, *s=NULL, *boundary_end = NULL, *start_arr=NULL, *array_index=NULL;
783 char *temp_filename=NULL, *lbuf=NULL, *abuf=NULL;
784 int boundary_len=0, total_bytes=0, cancel_upload=0, is_arr_upload=0, array_len=0;
785 int max_file_size=0, skip_upload=0, anonindex=0, is_anonymous;
786 zval *http_post_files=NULL; HashTable *uploaded_files=NULL;
787#if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
788 int str_len = 0, num_vars = 0, num_vars_max = 2*10, *len_list = NULL;
789 char **val_list = NULL;
790#endif
791 multipart_buffer *mbuff;
792 zval *array_ptr = (zval *) arg;
793 int fd=-1;
794 zend_llist header;
795 void *event_extra_data = NULL;
796#if PHP_VERSION_ID >= 50302 || (PHP_VERSION_ID >= 50212 && PHP_VERSION_ID < 50300)
797 int upload_cnt = INI_INT("max_file_uploads");
798#endif
799
800 SDEBUG("suhosin_rfc1867_handler");
801
802 if (SG(request_info).content_length > SG(post_max_size)) {
803 sapi_module.sapi_error(E_WARNING, "POST Content-Length of %ld bytes exceeds the limit of %ld bytes", SG(request_info).content_length, SG(post_max_size));
804 return;
805 }
806
807 /* Get the boundary */
808 boundary = strstr(content_type_dup, "boundary");
809 if (!boundary) {
810 int content_type_len = strlen(content_type_dup);
811 char *content_type_lcase = estrndup(content_type_dup, content_type_len);
812
813 php_strtolower(content_type_lcase, content_type_len);
814 boundary = strstr(content_type_lcase, "boundary");
815 if (boundary) {
816 boundary = content_type_dup + (boundary - content_type_lcase);
817 }
818 efree(content_type_lcase);
819 }
820
821 if (!boundary || !(boundary=strchr(boundary, '='))) {
822 sapi_module.sapi_error(E_WARNING, "Missing boundary in multipart/form-data POST data");
823 return;
824 }
825
826 boundary++;
827 boundary_len = strlen(boundary);
828
829 if (boundary[0] == '"') {
830 boundary++;
831 boundary_end = strchr(boundary, '"');
832 if (!boundary_end) {
833 sapi_module.sapi_error(E_WARNING, "Invalid boundary in multipart/form-data POST data");
834 return;
835 }
836 } else {
837 /* search for the end of the boundary */
838 boundary_end = strchr(boundary, ',');
839 }
840 if (boundary_end) {
841 boundary_end[0] = '\0';
842 boundary_len = boundary_end-boundary;
843 }
844
845 /* Initialize the buffer */
846 if (!(mbuff = multipart_buffer_new(boundary, boundary_len))) {
847 sapi_module.sapi_error(E_WARNING, "Unable to initialize the input buffer");
848 return;
849 }
850
851 /* Initialize $_FILES[] */
852 zend_hash_init(&PG(rfc1867_protected_variables), 5, NULL, NULL, 0);
853
854 ALLOC_HASHTABLE(uploaded_files);
855 zend_hash_init(uploaded_files, 5, NULL, (dtor_func_t) free_estring, 0);
856 SG(rfc1867_uploaded_files) = uploaded_files;
857
858 ALLOC_ZVAL(http_post_files);
859 array_init(http_post_files);
860 INIT_PZVAL(http_post_files);
861 PG(http_globals)[TRACK_VARS_FILES] = http_post_files;
862
863#if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
864 if (php_mb_encoding_translation(TSRMLS_C)) {
865 val_list = (char **)ecalloc(num_vars_max+2, sizeof(char *));
866 len_list = (int *)ecalloc(num_vars_max+2, sizeof(int));
867 }
868#endif
869 zend_llist_init(&header, sizeof(mime_header_entry), (llist_dtor_func_t) php_free_hdr_entry, 0);
870
871
872 {
873 multipart_event_start event_start;
874
875 event_start.content_length = SG(request_info).content_length;
876 if (suhosin_rfc1867_filter(MULTIPART_EVENT_START, &event_start, &event_extra_data TSRMLS_CC) == FAILURE) {
877 goto fileupload_done;
878 }
879 }
880
881 while (!multipart_buffer_eof(mbuff TSRMLS_CC))
882 {
883 char buff[FILLUNIT];
884 char *cd=NULL,*param=NULL,*filename=NULL, *tmp=NULL;
885 size_t blen=0, wlen=0;
886 off_t offset;
887
888 zend_llist_clean(&header);
889
890 if (!multipart_buffer_headers(mbuff, &header TSRMLS_CC)) {
891 goto fileupload_done;
892 }
893
894 if ((cd = php_mime_get_hdr_value(header, "Content-Disposition"))) {
895 char *pair=NULL;
896 int end=0;
897
898 while (isspace(*cd)) {
899 ++cd;
900 }
901
902 while (*cd && (pair = php_ap_getword(&cd, ';')))
903 {
904 char *key=NULL, *word = pair;
905
906 while (isspace(*cd)) {
907 ++cd;
908 }
909
910 if (strchr(pair, '=')) {
911 key = php_ap_getword(&pair, '=');
912
913 if (!strcasecmp(key, "name")) {
914 if (param) {
915 efree(param);
916 }
917 param = php_ap_getword_conf(&pair TSRMLS_CC);
918 } else if (!strcasecmp(key, "filename")) {
919 if (filename) {
920 efree(filename);
921 }
922 filename = php_ap_getword_conf(&pair TSRMLS_CC);
923 }
924 }
925 if (key) {
926 efree(key);
927 }
928 efree(word);
929 }
930
931 /* Normal form variable, safe to read all data into memory */
932 if (!filename && param) {
933
934 unsigned int value_len;
935 char *value = multipart_buffer_read_body(mbuff, &value_len TSRMLS_CC);
936 unsigned int new_val_len; /* Dummy variable */
937
938 if (!value) {
939 value = estrdup("");
940 }
941SDEBUG("calling inputfilter");
942 if (suhosin_input_filter(PARSE_POST, param, &value, value_len, &new_val_len TSRMLS_CC) == 0) {
943 SUHOSIN_G(abort_request)=1;
944 efree(param);
945 efree(value);
946 continue;
947 }
948
949#ifdef ZEND_ENGINE_2
950 if (sapi_module.input_filter(PARSE_POST, param, &value, new_val_len, &new_val_len TSRMLS_CC)) {
951#endif
952 {
953 multipart_event_formdata event_formdata;
954 size_t newlength = 0;
955
956 event_formdata.post_bytes_processed = SG(read_post_bytes);
957 event_formdata.name = param;
958 event_formdata.value = &value;
959 event_formdata.length = new_val_len;
960 event_formdata.newlength = &newlength;
961 if (suhosin_rfc1867_filter(MULTIPART_EVENT_FORMDATA, &event_formdata, &event_extra_data TSRMLS_CC) == FAILURE) {
962 efree(param);
963 efree(value);
964 continue;
965 }
966 new_val_len = newlength;
967 }
968
969#if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
970 if (php_mb_encoding_translation(TSRMLS_C)) {
971 php_mb_gpc_stack_variable(param, value, &val_list, &len_list,
972 &num_vars, &num_vars_max TSRMLS_CC);
973 } else {
974 safe_php_register_variable(param, value, array_ptr, 0 TSRMLS_CC);
975 }
976#else
977 safe_php_register_variable(param, value, array_ptr, 0 TSRMLS_CC);
978#endif
979#ifdef ZEND_ENGINE_2
980 } else {
981 multipart_event_formdata event_formdata;
982
983 event_formdata.post_bytes_processed = SG(read_post_bytes);
984 event_formdata.name = param;
985 event_formdata.value = &value;
986 event_formdata.length = value_len;
987 event_formdata.newlength = NULL;
988 suhosin_rfc1867_filter(MULTIPART_EVENT_FORMDATA, &event_formdata, &event_extra_data TSRMLS_CC);
989 }
990#endif
991 if (!strcasecmp(param, "MAX_FILE_SIZE")) {
992 max_file_size = atol(value);
993 }
994
995 efree(param);
996 efree(value);
997 continue;
998 }
999
1000 /* If file_uploads=off, skip the file part */
1001 if (!PG(file_uploads)) {
1002 skip_upload = 1;
1003 }
1004#if PHP_VERSION_ID >= 50302 || (PHP_VERSION_ID >= 50212 && PHP_VERSION_ID < 50300)
1005 else if (upload_cnt <= 0) {
1006 skip_upload = 1;
1007 sapi_module.sapi_error(E_WARNING, "Maximum number of allowable file uploads has been exceeded");
1008 }
1009#endif
1010
1011 /* Return with an error if the posted data is garbled */
1012 if (!param && !filename) {
1013 sapi_module.sapi_error(E_WARNING, "File Upload Mime headers garbled");
1014 goto fileupload_done;
1015 }
1016
1017 if (!param) {
1018 is_anonymous = 1;
1019 param = emalloc(MAX_SIZE_ANONNAME);
1020 snprintf(param, MAX_SIZE_ANONNAME, "%u", anonindex++);
1021 } else {
1022 is_anonymous = 0;
1023 }
1024
1025 /* New Rule: never repair potential malicious user input */
1026 if (!skip_upload) {
1027 char *tmp = param;
1028 long c = 0;
1029
1030 while (*tmp) {
1031 if (*tmp == '[') {
1032 c++;
1033 } else if (*tmp == ']') {
1034 c--;
1035 if (tmp[1] && tmp[1] != '[') {
1036 skip_upload = 1;
1037 break;
1038 }
1039 }
1040 if (c < 0) {
1041 skip_upload = 1;
1042 break;
1043 }
1044 tmp++;
1045 }
1046 }
1047
1048 total_bytes = cancel_upload = 0;
1049
1050 if (!skip_upload) {
1051 multipart_event_file_start event_file_start;
1052
1053 /* Handle file */
1054 fd = php_open_temporary_fd(PG(upload_tmp_dir), "php", &temp_filename TSRMLS_CC);
1055#if PHP_VERSION_ID >= 50302 || (PHP_VERSION_ID >= 50212 && PHP_VERSION_ID < 50300)
1056 upload_cnt--;
1057#endif
1058 if (fd==-1) {
1059 sapi_module.sapi_error(E_WARNING, "File upload error - unable to create a temporary file");
1060 cancel_upload = UPLOAD_ERROR_E;
1061 }
1062
1063 event_file_start.post_bytes_processed = SG(read_post_bytes);
1064 event_file_start.name = param;
1065 event_file_start.filename = &filename;
1066 if (suhosin_rfc1867_filter(MULTIPART_EVENT_FILE_START, &event_file_start, &event_extra_data TSRMLS_CC) == FAILURE) {
1067 if (temp_filename) {
1068 if (cancel_upload != UPLOAD_ERROR_E) { /* file creation failed */
1069 close(fd);
1070 unlink(temp_filename);
1071 }
1072 efree(temp_filename);
1073 }
1074 temp_filename = NULL;
1075 efree(param);
1076 efree(filename);
1077 continue;
1078 }
1079 }
1080
1081
1082 if (skip_upload) {
1083 efree(param);
1084 efree(filename);
1085 continue;
1086 }
1087
1088 if(strlen(filename) == 0) {
1089#if DEBUG_FILE_UPLOAD
1090 sapi_module.sapi_error(E_NOTICE, "No file uploaded");
1091#endif
1092 cancel_upload = UPLOAD_ERROR_D;
1093 }
1094
1095 offset = 0;
1096 end = 0;
1097 while (!cancel_upload && (blen = multipart_buffer_read(mbuff, buff, sizeof(buff), &end TSRMLS_CC)))
1098 {
1099 {
1100 multipart_event_file_data event_file_data;
1101
1102 event_file_data.post_bytes_processed = SG(read_post_bytes);
1103 event_file_data.offset = offset;
1104 event_file_data.data = buff;
1105 event_file_data.length = blen;
1106 event_file_data.newlength = &blen;
1107 if (suhosin_rfc1867_filter(MULTIPART_EVENT_FILE_DATA, &event_file_data, &event_extra_data TSRMLS_CC) == FAILURE) {
1108 cancel_upload = UPLOAD_ERROR_X;
1109 continue;
1110 }
1111 }
1112
1113
1114 if (PG(upload_max_filesize) > 0 && total_bytes+blen > PG(upload_max_filesize)) {
1115#if DEBUG_FILE_UPLOAD
1116 sapi_module.sapi_error(E_NOTICE, "upload_max_filesize of %ld bytes exceeded - file [%s=%s] not saved", PG(upload_max_filesize), param, filename);
1117#endif
1118 cancel_upload = UPLOAD_ERROR_A;
1119 } else if (max_file_size && (total_bytes+blen > max_file_size)) {
1120#if DEBUG_FILE_UPLOAD
1121 sapi_module.sapi_error(E_NOTICE, "MAX_FILE_SIZE of %ld bytes exceeded - file [%s=%s] not saved", max_file_size, param, filename);
1122#endif
1123 cancel_upload = UPLOAD_ERROR_B;
1124 } else if (blen > 0) {
1125
1126 wlen = write(fd, buff, blen);
1127
1128 if (wlen < blen) {
1129#if DEBUG_FILE_UPLOAD
1130 sapi_module.sapi_error(E_NOTICE, "Only %d bytes were written, expected to write %d", wlen, blen);
1131#endif
1132 cancel_upload = UPLOAD_ERROR_F;
1133 } else {
1134 total_bytes += wlen;
1135 }
1136
1137 offset += wlen;
1138 }
1139 }
1140 if (fd!=-1) { /* may not be initialized if file could not be created */
1141 close(fd);
1142 }
1143 if (!cancel_upload && !end) {
1144#if DEBUG_FILE_UPLOAD
1145 sapi_module.sapi_error(E_NOTICE, "Missing mime boundary at the end of the data for file %s", strlen(filename) > 0 ? filename : "");
1146#endif
1147 cancel_upload = UPLOAD_ERROR_C;
1148 }
1149#if DEBUG_FILE_UPLOAD
1150 if(strlen(filename) > 0 && total_bytes == 0 && !cancel_upload) {
1151 sapi_module.sapi_error(E_WARNING, "Uploaded file size 0 - file [%s=%s] not saved", param, filename);
1152 cancel_upload = 5;
1153 }
1154#endif
1155
1156 {
1157 multipart_event_file_end event_file_end;
1158
1159 event_file_end.post_bytes_processed = SG(read_post_bytes);
1160 event_file_end.temp_filename = temp_filename;
1161 event_file_end.cancel_upload = cancel_upload;
1162 if (suhosin_rfc1867_filter(MULTIPART_EVENT_FILE_END, &event_file_end, &event_extra_data TSRMLS_CC) == FAILURE) {
1163 cancel_upload = UPLOAD_ERROR_X;
1164 }
1165 }
1166
1167 if (cancel_upload) {
1168 if (temp_filename) {
1169 if (cancel_upload != UPLOAD_ERROR_E) { /* file creation failed */
1170 unlink(temp_filename);
1171 }
1172 efree(temp_filename);
1173 }
1174 temp_filename="";
1175 } else {
1176 zend_hash_add(SG(rfc1867_uploaded_files), temp_filename, strlen(temp_filename) + 1, &temp_filename, sizeof(char *), NULL);
1177 }
1178
1179 /* is_arr_upload is true when name of file upload field
1180 * ends in [.*]
1181 * start_arr is set to point to 1st [
1182 */
1183 is_arr_upload = (start_arr = strchr(param,'[')) && (param[strlen(param)-1] == ']');
1184
1185 if (is_arr_upload) {
1186 array_len = strlen(start_arr);
1187 if (array_index) {
1188 efree(array_index);
1189 }
1190 array_index = estrndup(start_arr+1, array_len-2);
1191 }
1192
1193 /* Add $foo_name */
1194 if (lbuf) {
1195 efree(lbuf);
1196 }
1197 lbuf = (char *) emalloc(strlen(param) + MAX_SIZE_OF_INDEX + 1);
1198
1199 if (is_arr_upload) {
1200 if (abuf) efree(abuf);
1201 abuf = estrndup(param, strlen(param)-array_len);
1202 sprintf(lbuf, "%s_name[%s]", abuf, array_index);
1203 } else {
1204 sprintf(lbuf, "%s_name", param);
1205 }
1206
1207#if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
1208 if (php_mb_encoding_translation(TSRMLS_C)) {
1209 if (num_vars>=num_vars_max){
1210 php_mb_gpc_realloc_buffer(&val_list, &len_list, &num_vars_max,
1211 1 TSRMLS_CC);
1212 }
1213 val_list[num_vars] = filename;
1214 len_list[num_vars] = strlen(filename);
1215 num_vars++;
1216 if(php_mb_gpc_encoding_detector(val_list, len_list, num_vars, NULL TSRMLS_CC) == SUCCESS) {
1217 str_len = strlen(filename);
1218 php_mb_gpc_encoding_converter(&filename, &str_len, 1, NULL, NULL TSRMLS_CC);
1219 }
1220 s = php_mb_strrchr(filename, '\\' TSRMLS_CC);
1221 if ((tmp = php_mb_strrchr(filename, '/' TSRMLS_CC)) > s) {
1222 s = tmp;
1223 }
1224 num_vars--;
1225 goto filedone;
1226 }
1227#endif
1228 /* The \ check should technically be needed for win32 systems only where
1229 * it is a valid path separator. However, IE in all it's wisdom always sends
1230 * the full path of the file on the user's filesystem, which means that unless
1231 * the user does basename() they get a bogus file name. Until IE's user base drops
1232 * to nill or problem is fixed this code must remain enabled for all systems.
1233 */
1234 s = strrchr(filename, '\\');
1235 if ((tmp = strrchr(filename, '/')) > s) {
1236 s = tmp;
1237 }
1238#ifdef PHP_WIN32
1239 if (PG(magic_quotes_gpc)) {
1240 s = s ? s : filename;
1241 tmp = strrchr(s, '\'');
1242 s = tmp > s ? tmp : s;
1243 tmp = strrchr(s, '"');
1244 s = tmp > s ? tmp : s;
1245 }
1246#endif
1247
1248#if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
1249filedone:
1250#endif
1251
1252 if (!is_anonymous) {
1253 if (s && s > filename) {
1254 safe_php_register_variable(lbuf, s+1, NULL, 0 TSRMLS_CC);
1255 } else {
1256 safe_php_register_variable(lbuf, filename, NULL, 0 TSRMLS_CC);
1257 }
1258 }
1259
1260 /* Add $foo[name] */
1261 if (is_arr_upload) {
1262 sprintf(lbuf, "%s[name][%s]", abuf, array_index);
1263 } else {
1264 sprintf(lbuf, "%s[name]", param);
1265 }
1266 if (s && s > filename) {
1267 register_http_post_files_variable(lbuf, s+1, http_post_files, 0 TSRMLS_CC);
1268 } else {
1269 register_http_post_files_variable(lbuf, filename, http_post_files, 0 TSRMLS_CC);
1270 }
1271 efree(filename);
1272 s = NULL;
1273
1274 /* Possible Content-Type: */
1275 if (cancel_upload || !(cd = php_mime_get_hdr_value(header, "Content-Type"))) {
1276 cd = "";
1277 } else {
1278 /* fix for Opera 6.01 */
1279 s = strchr(cd, ';');
1280 if (s != NULL) {
1281 *s = '\0';
1282 }
1283 }
1284
1285 /* Add $foo_type */
1286 if (is_arr_upload) {
1287 sprintf(lbuf, "%s_type[%s]", abuf, array_index);
1288 } else {
1289 sprintf(lbuf, "%s_type", param);
1290 }
1291 if (!is_anonymous) {
1292 safe_php_register_variable(lbuf, cd, NULL, 0 TSRMLS_CC);
1293 }
1294
1295 /* Add $foo[type] */
1296 if (is_arr_upload) {
1297 sprintf(lbuf, "%s[type][%s]", abuf, array_index);
1298 } else {
1299 sprintf(lbuf, "%s[type]", param);
1300 }
1301 register_http_post_files_variable(lbuf, cd, http_post_files, 0 TSRMLS_CC);
1302
1303 /* Restore Content-Type Header */
1304 if (s != NULL) {
1305 *s = ';';
1306 }
1307 s = "";
1308
1309 {
1310 /* store temp_filename as-is (without magic_quotes_gpc-ing it, in case upload_tmp_dir
1311 * contains escapeable characters. escape only the variable name.) */
1312 zval zfilename;
1313
1314 /* Initialize variables */
1315 add_protected_variable(param TSRMLS_CC);
1316
1317 /* if param is of form xxx[.*] this will cut it to xxx */
1318 if (!is_anonymous) {
1319 ZVAL_STRING(&zfilename, temp_filename, 1);
1320 safe_php_register_variable_ex(param, &zfilename, NULL, 1 TSRMLS_CC);
1321 }
1322
1323 /* Add $foo[tmp_name] */
1324 if (is_arr_upload) {
1325 sprintf(lbuf, "%s[tmp_name][%s]", abuf, array_index);
1326 } else {
1327 sprintf(lbuf, "%s[tmp_name]", param);
1328 }
1329 add_protected_variable(lbuf TSRMLS_CC);
1330 ZVAL_STRING(&zfilename, temp_filename, 1);
1331 register_http_post_files_variable_ex(lbuf, &zfilename, http_post_files, 1 TSRMLS_CC);
1332 }
1333
1334 {
1335 zval file_size, error_type;
1336
1337 error_type.value.lval = cancel_upload;
1338 error_type.type = IS_LONG;
1339
1340 /* Add $foo[error] */
1341 if (cancel_upload) {
1342 file_size.value.lval = 0;
1343 file_size.type = IS_LONG;
1344 } else {
1345 file_size.value.lval = total_bytes;
1346 file_size.type = IS_LONG;
1347 }
1348
1349 if (is_arr_upload) {
1350 sprintf(lbuf, "%s[error][%s]", abuf, array_index);
1351 } else {
1352 sprintf(lbuf, "%s[error]", param);
1353 }
1354 register_http_post_files_variable_ex(lbuf, &error_type, http_post_files, 0 TSRMLS_CC);
1355
1356 /* Add $foo_size */
1357 if (is_arr_upload) {
1358 sprintf(lbuf, "%s_size[%s]", abuf, array_index);
1359 } else {
1360 sprintf(lbuf, "%s_size", param);
1361 }
1362 if (!is_anonymous) {
1363 safe_php_register_variable_ex(lbuf, &file_size, NULL, 0 TSRMLS_CC);
1364 }
1365
1366 /* Add $foo[size] */
1367 if (is_arr_upload) {
1368 sprintf(lbuf, "%s[size][%s]", abuf, array_index);
1369 } else {
1370 sprintf(lbuf, "%s[size]", param);
1371 }
1372 register_http_post_files_variable_ex(lbuf, &file_size, http_post_files, 0 TSRMLS_CC);
1373 }
1374 efree(param);
1375 }
1376 }
1377fileupload_done:
1378 {
1379 multipart_event_end event_end;
1380
1381 event_end.post_bytes_processed = SG(read_post_bytes);
1382 suhosin_rfc1867_filter(MULTIPART_EVENT_END, &event_end, &event_extra_data TSRMLS_CC);
1383 }
1384
1385 SAFE_RETURN;
1386}
1387
1388#endif
1389
1390/*
1391 * Local variables:
1392 * tab-width: 4
1393 * c-basic-offset: 4
1394 * End:
1395 * vim600: sw=4 ts=4 fdm=marker
1396 * vim<600: sw=4 ts=4
1397 */
diff --git a/rfc1867_new.c b/rfc1867_new.c
index 720e3ff..2a8b3ab 100644
--- a/rfc1867_new.c
+++ b/rfc1867_new.c
@@ -35,7 +35,6 @@
35#include "suhosin_rfc1867.h" 35#include "suhosin_rfc1867.h"
36#include "ext/standard/php_string.h" 36#include "ext/standard/php_string.h"
37 37
38#if PHP_VERSION_ID >= 50400
39 38
40#define DEBUG_FILE_UPLOAD ZEND_DEBUG 39#define DEBUG_FILE_UPLOAD ZEND_DEBUG
41 40
@@ -1267,7 +1266,6 @@ fileupload_done:
1267} 1266}
1268/* }}} */ 1267/* }}} */
1269 1268
1270#endif
1271 1269
1272/* 1270/*
1273 * Local variables: 1271 * Local variables:
diff --git a/session.c b/session.c
index 548786f..0e16ce4 100644
--- a/session.c
+++ b/session.c
@@ -58,22 +58,6 @@ static int suhosin_get_session_var(char *name, size_t namelen, zval ***state_var
58 58
59 if (SESSION_G(http_session_vars) && SESSION_G(http_session_vars)->type == IS_ARRAY) { 59 if (SESSION_G(http_session_vars) && SESSION_G(http_session_vars)->type == IS_ARRAY) {
60 ret = zend_hash_find(Z_ARRVAL_P(SESSION_G(http_session_vars)), name, namelen + 1, (void **) state_var); 60 ret = zend_hash_find(Z_ARRVAL_P(SESSION_G(http_session_vars)), name, namelen + 1, (void **) state_var);
61
62#if PHP_VERSION_ID < 50400
63 /* If register_globals is enabled, and
64 * if there is an entry for the slot in $_SESSION, and
65 * if that entry is still set to NULL, and
66 * if the global var exists, then
67 * we prefer the same key in the global sym table. */
68
69 if (PG(register_globals) && ret == SUCCESS && Z_TYPE_PP(*state_var) == IS_NULL) {
70 zval **tmp;
71
72 if (zend_hash_find(&EG(symbol_table), name, namelen + 1, (void **) &tmp) == SUCCESS) {
73 *state_var = tmp;
74 }
75 }
76#endif
77 } 61 }
78 return ret; 62 return ret;
79} 63}
@@ -123,7 +107,6 @@ static void suhosin_send_cookie(TSRMLS_D)
123 107
124 /* The following is requires to be 100% compatible to PHP 108 /* The following is requires to be 100% compatible to PHP
125 versions where the hash extension is not available by default */ 109 versions where the hash extension is not available by default */
126#if (PHP_MAJOR_VERSION >= 5 && PHP_MINOR_VERSION >= 3)
127 if (zend_hash_find(EG(ini_directives), "session.hash_bits_per_character", sizeof("session.hash_bits_per_character"), (void **) &ini_entry) == SUCCESS) { 110 if (zend_hash_find(EG(ini_directives), "session.hash_bits_per_character", sizeof("session.hash_bits_per_character"), (void **) &ini_entry) == SUCCESS) {
128#ifndef ZTS 111#ifndef ZTS
129 base = (char *) ini_entry->mh_arg2; 112 base = (char *) ini_entry->mh_arg2;
@@ -132,7 +115,6 @@ static void suhosin_send_cookie(TSRMLS_D)
132#endif 115#endif
133 session_send_cookie = (int *) (base+(size_t) ini_entry->mh_arg1+sizeof(long)); 116 session_send_cookie = (int *) (base+(size_t) ini_entry->mh_arg1+sizeof(long));
134 } 117 }
135#endif
136 *session_send_cookie = 1; 118 *session_send_cookie = 1;
137} 119}
138 120
@@ -155,9 +137,7 @@ static int suhosin_hook_s_read(void **mod_data, const char *key, char **val, int
155 /* protect dumb session handlers */ 137 /* protect dumb session handlers */
156 if (key == NULL || !key[0] || 138 if (key == NULL || !key[0] ||
157 (*mod_data == NULL 139 (*mod_data == NULL
158#if PHP_VERSION_ID >= 50400
159 && !SESSION_G(mod_user_implemented) 140 && !SESSION_G(mod_user_implemented)
160#endif
161 )) { 141 )) {
162regenerate: 142regenerate:
163 SDEBUG("regenerating key is %s", key); 143 SDEBUG("regenerating key is %s", key);
@@ -169,14 +149,6 @@ regenerate:
169 goto regenerate; 149 goto regenerate;
170 } 150 }
171 } 151 }
172#if (PHP_MAJOR_VERSION < 5) || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 2)
173 else if (strpbrk(KEY, "\r\n\t <>'\"\\")) {
174 suhosin_log(S_SESSION, "session id ('%s') contains invalid chars - regenerating", KEY);
175 if (!SUHOSIN_G(simulation)) {
176 goto regenerate;
177 }
178 }
179#endif
180 152
181 r = SUHOSIN_G(old_s_read)(mod_data, KEY, val, vallen TSRMLS_CC); 153 r = SUHOSIN_G(old_s_read)(mod_data, KEY, val, vallen TSRMLS_CC);
182 154
@@ -209,9 +181,7 @@ static int suhosin_hook_s_write(void **mod_data, const char *key, const char *va
209 /* protect dumb session handlers */ 181 /* protect dumb session handlers */
210 if (key == NULL || !key[0] || val == NULL || strlen(key) > SUHOSIN_G(session_max_id_length) || 182 if (key == NULL || !key[0] || val == NULL || strlen(key) > SUHOSIN_G(session_max_id_length) ||
211 (*mod_data == NULL 183 (*mod_data == NULL
212#if PHP_VERSION_ID >= 50400
213 && !SESSION_G(mod_user_implemented) 184 && !SESSION_G(mod_user_implemented)
214#endif
215 )) { 185 )) {
216 r = FAILURE; 186 r = FAILURE;
217 goto return_write; 187 goto return_write;
@@ -257,9 +227,7 @@ static int suhosin_hook_s_destroy(void **mod_data, const char *key TSRMLS_DC)
257 /* protect dumb session handlers */ 227 /* protect dumb session handlers */
258 if (key == NULL || !key[0] || strlen(key) > SUHOSIN_G(session_max_id_length) || 228 if (key == NULL || !key[0] || strlen(key) > SUHOSIN_G(session_max_id_length) ||
259 (*mod_data == NULL 229 (*mod_data == NULL
260#if PHP_VERSION_ID >= 50400
261 && !SESSION_G(mod_user_implemented) 230 && !SESSION_G(mod_user_implemented)
262#endif
263 )) { 231 )) {
264 return FAILURE; 232 return FAILURE;
265 } 233 }
@@ -343,7 +311,6 @@ void suhosin_hook_session(TSRMLS_D)
343 return; 311 return;
344 } 312 }
345 /* retrieve globals from module entry struct if possible */ 313 /* retrieve globals from module entry struct if possible */
346#if PHP_VERSION_ID >= 50200
347#ifdef ZTS 314#ifdef ZTS
348 if (session_globals_id == 0) { 315 if (session_globals_id == 0) {
349 session_globals_id = *module->globals_id_ptr; 316 session_globals_id = *module->globals_id_ptr;
@@ -353,32 +320,6 @@ void suhosin_hook_session(TSRMLS_D)
353 session_globals = module->globals_ptr; 320 session_globals = module->globals_ptr;
354 } 321 }
355#endif 322#endif
356#else
357 /* retrieve globals from symbols if PHP version is old */
358#ifdef ZTS
359 if (session_globals_id == 0) {
360 ps_globals_id_ptr = DL_FETCH_SYMBOL(module->handle, "ps_globals_id");
361 if (ps_globals_id_ptr == NULL) {
362 ps_globals_id_ptr = DL_FETCH_SYMBOL(module->handle, "_ps_globals_id");
363 }
364 if (ps_globals_id_ptr == NULL) {
365 return;
366 }
367
368 session_globals_id = *ps_globals_id_ptr;
369 }
370#else
371 if (session_globals == NULL) {
372 session_globals = DL_FETCH_SYMBOL(module->handle, "ps_globals");
373 if (session_globals == NULL) {
374 session_globals = DL_FETCH_SYMBOL(module->handle, "_ps_globals");
375 }
376 if (session_globals == NULL) {
377 return;
378 }
379 }
380#endif
381#endif
382 323
383 if (old_OnUpdateSaveHandler != NULL) { 324 if (old_OnUpdateSaveHandler != NULL) {
384 return; 325 return;
@@ -401,12 +342,10 @@ void suhosin_hook_session(TSRMLS_D)
401 suhosin_hook_session_module(TSRMLS_C); 342 suhosin_hook_session_module(TSRMLS_C);
402 343
403 /* Protect the PHP serializer from ! attacks */ 344 /* Protect the PHP serializer from ! attacks */
404# if PHP_MAJOR_VERSION > 5 || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 2)
405 serializer = (ps_serializer *) SESSION_G(serializer); 345 serializer = (ps_serializer *) SESSION_G(serializer);
406 if (serializer != NULL && strcmp(serializer->name, "php")==0) { 346 if (serializer != NULL && strcmp(serializer->name, "php")==0) {
407 serializer->encode = suhosin_session_encode; 347 serializer->encode = suhosin_session_encode;
408 } 348 }
409#endif
410 349
411 /* increase session identifier entropy */ 350 /* increase session identifier entropy */
412 if (SESSION_G(entropy_length) == 0 || SESSION_G(entropy_file) == NULL) { 351 if (SESSION_G(entropy_length) == 0 || SESSION_G(entropy_file) == NULL) {
diff --git a/sha256.c b/sha256.c
index 275dccd..64ee25f 100644
--- a/sha256.c
+++ b/sha256.c
@@ -86,12 +86,6 @@ static PHP_FUNCTION(suhosin_sha256_file)
86 return; 86 return;
87 } 87 }
88 88
89#if PHP_VERSION_ID < 50400
90 if (PG(safe_mode) && (!php_checkuid(arg, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
91 RETURN_FALSE;
92 }
93#endif
94
95 if (php_check_open_basedir(arg TSRMLS_CC)) { 89 if (php_check_open_basedir(arg TSRMLS_CC)) {
96 RETURN_FALSE; 90 RETURN_FALSE;
97 } 91 }
diff --git a/suhosin.c b/suhosin.c
index 5b24789..76cdac1 100644
--- a/suhosin.c
+++ b/suhosin.c
@@ -1058,11 +1058,8 @@ PHP_MINIT_FUNCTION(suhosin)
1058 php_register_info_logo(SUHOSIN_LOGO_GUID, "image/jpeg", suhosin_logo, sizeof(suhosin_logo)); 1058 php_register_info_logo(SUHOSIN_LOGO_GUID, "image/jpeg", suhosin_logo, sizeof(suhosin_logo));
1059#endif 1059#endif
1060 1060
1061#if PHP_MAJOR_VERSION < 5 1061#if PHP_VERSION_ID < 50400
1062#error Suhosin Extension is not designed to run with PHP 4 and below. 1062#error Suhosin Extension is not designed to run with PHP versions lower than 5.4.
1063#endif
1064#if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION <= 2 && !SUHOSIN_DEBUG
1065 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Suhosin Extension does not officially support PHP 5.2 and below anymore, because it is discontinued. Use it at your own risk.");
1066#endif 1063#endif
1067 1064
1068#if !defined(HAVE_PHP_SESSION) && !defined(SUHOSIN_NO_SESSION_WARNING) 1065#if !defined(HAVE_PHP_SESSION) && !defined(SUHOSIN_NO_SESSION_WARNING)
diff --git a/treat_data.c b/treat_data.c
index 15e721d..10e8166 100644
--- a/treat_data.c
+++ b/treat_data.c
@@ -39,9 +39,7 @@ SAPI_TREAT_DATA_FUNC(suhosin_treat_data)
39 int free_buffer = 0; 39 int free_buffer = 0;
40 char *strtok_buf = NULL; 40 char *strtok_buf = NULL;
41 41
42#if PHP_VERSION_ID >= 50311
43 long count = 0; 42 long count = 0;
44#endif
45 43
46 /* Mark that we were not yet called */ 44 /* Mark that we were not yet called */
47 SUHOSIN_G(already_scanned) = 0; 45 SUHOSIN_G(already_scanned) = 0;
@@ -148,12 +146,10 @@ SAPI_TREAT_DATA_FUNC(suhosin_treat_data)
148 } 146 }
149 val = strchr(var, '='); 147 val = strchr(var, '=');
150 148
151#if PHP_VERSION_ID >= 50311
152 if (++count > PG(max_input_vars)) { 149 if (++count > PG(max_input_vars)) {
153 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Input variables exceeded %ld. To increase the limit change max_input_vars in php.ini.", PG(max_input_vars)); 150 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Input variables exceeded %ld. To increase the limit change max_input_vars in php.ini.", PG(max_input_vars));
154 break; 151 break;
155 } 152 }
156#endif
157 153
158 if (val) { /* have a value */ 154 if (val) { /* have a value */
159 int val_len; 155 int val_len;
@@ -210,13 +206,9 @@ SAPI_TREAT_DATA_FUNC(suhosin_treat_data)
210 206
211void suhosin_hook_treat_data() 207void suhosin_hook_treat_data()
212{ 208{
213#if PHP_VERSION_ID < 50400
214 sapi_register_treat_data(suhosin_treat_data);
215#else
216 TSRMLS_FETCH(); 209 TSRMLS_FETCH();
217 210
218 sapi_register_treat_data(suhosin_treat_data TSRMLS_CC); 211 sapi_register_treat_data(suhosin_treat_data TSRMLS_CC);
219#endif
220#ifdef ZEND_ENGINE_2 212#ifdef ZEND_ENGINE_2
221 if (old_input_filter == NULL) { 213 if (old_input_filter == NULL) {
222 old_input_filter = sapi_module.input_filter; 214 old_input_filter = sapi_module.input_filter;