diff options
Diffstat (limited to 'src/sp_ini.c')
| -rw-r--r-- | src/sp_ini.c | 52 |
1 files changed, 35 insertions, 17 deletions
diff --git a/src/sp_ini.c b/src/sp_ini.c index 05d7d99..5777ca3 100644 --- a/src/sp_ini.c +++ b/src/sp_ini.c | |||
| @@ -3,6 +3,15 @@ | |||
| 3 | #define SP_INI_HAS_CHECKS_COND(entry) (entry->min || entry->max || entry->regexp) | 3 | #define SP_INI_HAS_CHECKS_COND(entry) (entry->min || entry->max || entry->regexp) |
| 4 | #define SP_INI_ACCESS_READONLY_COND(entry, cfg) (entry->access == SP_READONLY || (!entry->access && cfg->policy_readonly)) | 4 | #define SP_INI_ACCESS_READONLY_COND(entry, cfg) (entry->access == SP_READONLY || (!entry->access && cfg->policy_readonly)) |
| 5 | 5 | ||
| 6 | #define sp_log_auto2(feature, is_simulation, drop, ...) \ | ||
| 7 | sp_log_msgf(feature, ((is_simulation || !drop) ? SP_LOG_WARN : SP_LOG_ERROR), \ | ||
| 8 | (is_simulation ? SP_TYPE_SIMULATION : (drop ? SP_TYPE_DROP : SP_TYPE_LOG)), \ | ||
| 9 | __VA_ARGS__) | ||
| 10 | #define sp_log_ini_check_violation(...) if (simulation || cfg->policy_drop || (entry && entry->drop) || !cfg->policy_silent_fail) { \ | ||
| 11 | sp_log_auto2("ini_protection", simulation, (cfg->policy_drop || (entry && entry->drop)), __VA_ARGS__); \ | ||
| 12 | } | ||
| 13 | |||
| 14 | |||
| 6 | static bool /* success */ sp_ini_check(zend_string *varname, zend_string *new_value, sp_ini_entry **sp_entry_p) { | 15 | static bool /* success */ sp_ini_check(zend_string *varname, zend_string *new_value, sp_ini_entry **sp_entry_p) { |
| 7 | if (!varname || ZSTR_LEN(varname) == 0) { | 16 | if (!varname || ZSTR_LEN(varname) == 0) { |
| 8 | return false; | 17 | return false; |
| @@ -17,40 +26,49 @@ static bool /* success */ sp_ini_check(zend_string *varname, zend_string *new_va | |||
| 17 | 26 | ||
| 18 | if (!entry) { | 27 | if (!entry) { |
| 19 | if (cfg->policy_readonly) { | 28 | if (cfg->policy_readonly) { |
| 20 | sp_log_auto("ini_protection", simulation, "INI setting is read-only"); | 29 | if (!cfg->policy_silent_ro) { |
| 21 | if (simulation) { return true; } | 30 | sp_log_ini_check_violation("INI setting is read-only"); |
| 22 | return false; | 31 | } |
| 32 | return simulation; | ||
| 23 | } | 33 | } |
| 24 | return true; | 34 | return true; |
| 25 | } | 35 | } |
| 26 | 36 | ||
| 37 | // we have an entry. | ||
| 38 | |||
| 27 | if (SP_INI_ACCESS_READONLY_COND(entry, cfg)) { | 39 | if (SP_INI_ACCESS_READONLY_COND(entry, cfg)) { |
| 28 | sp_log_auto("ini_protection", simulation, "%s", (entry->msg ? ZSTR_VAL(entry->msg) : "INI setting is read-only")); | 40 | if (!cfg->policy_silent_ro) { |
| 29 | if (simulation) { return true; } | 41 | sp_log_ini_check_violation("%s", (entry->msg ? ZSTR_VAL(entry->msg) : "INI setting is read-only")); |
| 30 | return false; | 42 | } |
| 43 | return simulation; | ||
| 31 | } | 44 | } |
| 32 | 45 | ||
| 33 | if (!new_value && SP_INI_HAS_CHECKS_COND(entry)) { | 46 | if (!new_value || ZSTR_LEN(new_value) == 0) { |
| 34 | sp_log_auto("ini_protection", simulation, "new INI value must not be NULL"); | 47 | if (entry->allow_null) { |
| 35 | if (simulation) { return true; } | 48 | return true; // allow NULL value and skip other tests |
| 36 | return false; | 49 | } |
| 50 | if (SP_INI_HAS_CHECKS_COND(entry)) { | ||
| 51 | sp_log_ini_check_violation("new INI value must not be NULL or empty"); | ||
| 52 | return simulation; | ||
| 53 | } | ||
| 54 | return true; // no new_value, but no checks to perform | ||
| 37 | } | 55 | } |
| 38 | 56 | ||
| 57 | // we have a new_value. | ||
| 58 | |||
| 39 | if (entry->min || entry->max) { | 59 | if (entry->min || entry->max) { |
| 40 | zend_long lvalue = zend_atol(ZSTR_VAL(new_value), ZSTR_LEN(new_value)); | 60 | zend_long lvalue = zend_atol(ZSTR_VAL(new_value), ZSTR_LEN(new_value)); |
| 41 | if ((entry->min && zend_atol(ZSTR_VAL(entry->min), ZSTR_LEN(entry->min)) > lvalue) || | 61 | if ((entry->min && zend_atol(ZSTR_VAL(entry->min), ZSTR_LEN(entry->min)) > lvalue) || |
| 42 | (entry->max && zend_atol(ZSTR_VAL(entry->max), ZSTR_LEN(entry->max)) < lvalue)) { | 62 | (entry->max && zend_atol(ZSTR_VAL(entry->max), ZSTR_LEN(entry->max)) < lvalue)) { |
| 43 | sp_log_auto("ini_protection", simulation, "%s", (entry->msg ? ZSTR_VAL(entry->msg) : "INI value out of range")); | 63 | sp_log_ini_check_violation("%s", (entry->msg ? ZSTR_VAL(entry->msg) : "INI value out of range")); |
| 44 | if (simulation) { return true; } | 64 | return simulation; |
| 45 | return false; | ||
| 46 | } | 65 | } |
| 47 | } | 66 | } |
| 48 | 67 | ||
| 49 | if (entry->regexp) { | 68 | if (entry->regexp) { |
| 50 | if (!sp_is_regexp_matching_len(entry->regexp, ZSTR_VAL(new_value), ZSTR_LEN(new_value))) { | 69 | if (!sp_is_regexp_matching_len(entry->regexp, ZSTR_VAL(new_value), ZSTR_LEN(new_value))) { |
| 51 | sp_log_auto("ini_protection", simulation, "%s", (entry->msg ? ZSTR_VAL(entry->msg) : "INI value does not match regex")); | 70 | sp_log_ini_check_violation("%s", (entry->msg ? ZSTR_VAL(entry->msg) : "INI value does not match regex")); |
| 52 | if (simulation) { return true; } | 71 | return simulation; |
| 53 | return false; | ||
| 54 | } | 72 | } |
| 55 | } | 73 | } |
| 56 | 74 | ||
| @@ -83,7 +101,7 @@ void sp_hook_ini() { | |||
| 83 | sp_log_warn("ini_protection", "Cannot hook INI var `%s`. Maybe a typo or the PHP extension providing this var is not loaded yet.", ZSTR_VAL(sp_entry->key)); | 101 | sp_log_warn("ini_protection", "Cannot hook INI var `%s`. Maybe a typo or the PHP extension providing this var is not loaded yet.", ZSTR_VAL(sp_entry->key)); |
| 84 | continue; | 102 | continue; |
| 85 | } | 103 | } |
| 86 | if (SP_INI_ACCESS_READONLY_COND(sp_entry, cfg)) { | 104 | if (SP_INI_ACCESS_READONLY_COND(sp_entry, cfg) && (cfg->policy_silent_ro || cfg->policy_silent_fail) && !sp_entry->drop && !(sp_entry->simulation || cfg->simulation)) { |
| 87 | ini_entry->modifiable = ini_entry->orig_modifiable = 0; | 105 | ini_entry->modifiable = ini_entry->orig_modifiable = 0; |
| 88 | } | 106 | } |
| 89 | PHP_INI_MH((*orig_onmodify)) = ini_entry->on_modify; | 107 | PHP_INI_MH((*orig_onmodify)) = ini_entry->on_modify; |
