diff options
Diffstat (limited to 'src/sp_ini.c')
| -rw-r--r-- | src/sp_ini.c | 60 |
1 files changed, 55 insertions, 5 deletions
diff --git a/src/sp_ini.c b/src/sp_ini.c index 7b22012..8860a92 100644 --- a/src/sp_ini.c +++ b/src/sp_ini.c | |||
| @@ -11,6 +11,29 @@ | |||
| 11 | sp_log_auto2("ini_protection", simulation, (cfg->policy_drop || (entry && entry->drop)), __VA_ARGS__); \ | 11 | sp_log_auto2("ini_protection", simulation, (cfg->policy_drop || (entry && entry->drop)), __VA_ARGS__); \ |
| 12 | } | 12 | } |
| 13 | 13 | ||
| 14 | static const char* check_safe_key(const char* string) { | ||
| 15 | for (const char* p = string; *p != '\0'; p++) { | ||
| 16 | if (!isalnum((unsigned char)*p) && *p != '_' && *p != '.') { | ||
| 17 | return NULL; | ||
| 18 | } | ||
| 19 | } | ||
| 20 | |||
| 21 | return string; | ||
| 22 | } | ||
| 23 | |||
| 24 | static const char* check_safe_value(const char* string) { | ||
| 25 | for (const char* p = string; *p != '\0'; p++) { | ||
| 26 | if (*p == '\'' || *p == '"') { | ||
| 27 | return NULL; | ||
| 28 | } | ||
| 29 | |||
| 30 | if (!isgraph((unsigned char)*p)) { | ||
| 31 | return NULL; | ||
| 32 | } | ||
| 33 | } | ||
| 34 | |||
| 35 | return string; | ||
| 36 | } | ||
| 14 | 37 | ||
| 15 | static bool /* success */ sp_ini_check(zend_string *const restrict varname, zend_string const *const restrict new_value, sp_ini_entry **sp_entry_p) { | 38 | static bool /* success */ sp_ini_check(zend_string *const restrict varname, zend_string const *const restrict new_value, sp_ini_entry **sp_entry_p) { |
| 16 | if (!varname || ZSTR_LEN(varname) == 0) { | 39 | if (!varname || ZSTR_LEN(varname) == 0) { |
| @@ -27,7 +50,8 @@ static bool /* success */ sp_ini_check(zend_string *const restrict varname, zend | |||
| 27 | if (!entry) { | 50 | if (!entry) { |
| 28 | if (cfg->policy_readonly) { | 51 | if (cfg->policy_readonly) { |
| 29 | if (!cfg->policy_silent_ro) { | 52 | if (!cfg->policy_silent_ro) { |
| 30 | sp_log_ini_check_violation("INI setting is read-only"); | 53 | sp_log_ini_check_violation("INI setting `%s` is read-only", |
| 54 | check_safe_key(ZSTR_VAL(varname)) ? ZSTR_VAL(varname) : "<invalid>"); | ||
| 31 | } | 55 | } |
| 32 | return simulation; | 56 | return simulation; |
| 33 | } | 57 | } |
| @@ -38,7 +62,11 @@ static bool /* success */ sp_ini_check(zend_string *const restrict varname, zend | |||
| 38 | 62 | ||
| 39 | if (SP_INI_ACCESS_READONLY_COND(entry, cfg)) { | 63 | if (SP_INI_ACCESS_READONLY_COND(entry, cfg)) { |
| 40 | if (!cfg->policy_silent_ro) { | 64 | if (!cfg->policy_silent_ro) { |
| 41 | sp_log_ini_check_violation("%s", (entry->msg ? ZSTR_VAL(entry->msg) : "INI setting is read-only")); | 65 | if (entry->msg) { |
| 66 | sp_log_ini_check_violation("%s", ZSTR_VAL(entry->msg)); | ||
| 67 | } else { | ||
| 68 | sp_log_ini_check_violation("INI setting `%s` is read-only", ZSTR_VAL(entry->key)); | ||
| 69 | } | ||
| 42 | } | 70 | } |
| 43 | return simulation; | 71 | return simulation; |
| 44 | } | 72 | } |
| @@ -48,7 +76,7 @@ static bool /* success */ sp_ini_check(zend_string *const restrict varname, zend | |||
| 48 | return true; // allow NULL value and skip other tests | 76 | return true; // allow NULL value and skip other tests |
| 49 | } | 77 | } |
| 50 | if (SP_INI_HAS_CHECKS_COND(entry)) { | 78 | if (SP_INI_HAS_CHECKS_COND(entry)) { |
| 51 | sp_log_ini_check_violation("new INI value must not be NULL or empty"); | 79 | sp_log_ini_check_violation("new INI value for `%s` must not be NULL or empty", ZSTR_VAL(entry->key)); |
| 52 | return simulation; | 80 | return simulation; |
| 53 | } | 81 | } |
| 54 | return true; // no new_value, but no checks to perform | 82 | return true; // no new_value, but no checks to perform |
| @@ -66,14 +94,36 @@ static bool /* success */ sp_ini_check(zend_string *const restrict varname, zend | |||
| 66 | if ((entry->min && zend_atol(ZSTR_VAL(entry->min), ZSTR_LEN(entry->min)) > lvalue) || | 94 | if ((entry->min && zend_atol(ZSTR_VAL(entry->min), ZSTR_LEN(entry->min)) > lvalue) || |
| 67 | (entry->max && zend_atol(ZSTR_VAL(entry->max), ZSTR_LEN(entry->max)) < lvalue)) { | 95 | (entry->max && zend_atol(ZSTR_VAL(entry->max), ZSTR_LEN(entry->max)) < lvalue)) { |
| 68 | #endif | 96 | #endif |
| 69 | sp_log_ini_check_violation("%s", (entry->msg ? ZSTR_VAL(entry->msg) : "INI value out of range")); | 97 | if (entry->msg) { |
| 98 | sp_log_ini_check_violation("%s", ZSTR_VAL(entry->msg)); | ||
| 99 | } else { | ||
| 100 | sp_log_ini_check_violation("INI value %lld for `%s` out of range", lvalue, ZSTR_VAL(entry->key)); | ||
| 101 | } | ||
| 70 | return simulation; | 102 | return simulation; |
| 71 | } | 103 | } |
| 72 | } | 104 | } |
| 73 | 105 | ||
| 74 | if (entry->regexp) { | 106 | if (entry->regexp) { |
| 75 | if (!sp_is_regexp_matching_zstr(entry->regexp, new_value)) { | 107 | if (!sp_is_regexp_matching_zstr(entry->regexp, new_value)) { |
| 76 | sp_log_ini_check_violation("%s", (entry->msg ? ZSTR_VAL(entry->msg) : "INI value does not match regex")); | 108 | if (entry->msg) { |
| 109 | sp_log_ini_check_violation("%s", ZSTR_VAL(entry->msg)); | ||
| 110 | } else { | ||
| 111 | zend_string *base64_new_val = NULL; | ||
| 112 | const char *safe_new_val = check_safe_value(ZSTR_VAL(new_value)); | ||
| 113 | if (!safe_new_val) { | ||
| 114 | base64_new_val = php_base64_encode((const unsigned char*)(ZSTR_VAL(new_value)), ZSTR_LEN(new_value)); | ||
| 115 | safe_new_val = base64_new_val ? ZSTR_VAL(base64_new_val) : "<invalid>"; | ||
| 116 | } | ||
| 117 | |||
| 118 | sp_log_ini_check_violation("INI value `%s`%s for `%s` does not match regex", | ||
| 119 | safe_new_val, | ||
| 120 | base64_new_val ? "(base64)" : "", | ||
| 121 | ZSTR_VAL(entry->key)); | ||
| 122 | |||
| 123 | if (base64_new_val) { | ||
| 124 | zend_string_release(base64_new_val); | ||
| 125 | } | ||
| 126 | } | ||
| 77 | return simulation; | 127 | return simulation; |
| 78 | } | 128 | } |
| 79 | } | 129 | } |
