summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjvoisin2025-10-24 23:50:18 +0200
committerjvoisin2025-10-24 23:55:13 +0200
commit6ea4278a512bc9f1f816844222e65a4ea670db8e (patch)
tree8c645390d3ad5202e3a894f9f6779f4cb590b02e
parenta167c4d23feb03e6c5b53f41724bbfcb813bf04b (diff)
feat(log): add the possibility to log to a filelog2file
-rw-r--r--doc/source/config.rst6
-rw-r--r--src/php_snuffleupagus.h2
-rw-r--r--src/snuffleupagus.c2
-rw-r--r--src/sp_config.h7
-rw-r--r--src/sp_config_keywords.c20
-rw-r--r--src/sp_utils.c16
-rw-r--r--src/tests/broken_configuration/broken_conf_invalid_log_media.phpt2
-rw-r--r--src/tests/syslog_simulation.phpt1
8 files changed, 43 insertions, 13 deletions
diff --git a/doc/source/config.rst b/doc/source/config.rst
index 64d3591..2053c2f 100644
--- a/doc/source/config.rst
+++ b/doc/source/config.rst
@@ -139,19 +139,21 @@ log_media
139^^^^^^^^^ 139^^^^^^^^^
140 140
141This configuration variable allows to specify how logs should be written, 141This configuration variable allows to specify how logs should be written,
142either via ``php`` or ``syslog``. 142either via ``php``, ``syslog``, or `file:`.
143 143
144:: 144::
145 145
146 sp.log_media("php"); 146 sp.log_media("php");
147 sp.log_media("syslog"); 147 sp.log_media("syslog");
148 sp.log_media("file:/var/log/snuffleupagus.log");
148 149
149The default value for ``sp.log_media`` is ``php``, to respect the `principle of 150The default value for ``sp.log_media`` is ``php``, to respect the `principle of
150least astonishment 151least astonishment
151<https://en.wikipedia.org/wiki/Principle_of_least_astonishment>`__. But since 152<https://en.wikipedia.org/wiki/Principle_of_least_astonishment>`__. But since
152it's `possible to modify php's logging system via php 153it's `possible to modify php's logging system via php
153<https://www.php.net/manual/en/errorfunc.configuration.php>`__, it's 154<https://www.php.net/manual/en/errorfunc.configuration.php>`__, it's
154heavily recommended to use the ``syslog`` option instead. 155heavily recommended to use the ``syslog`` option instead. The ``file:` option
156might be useful if you're using Snuffleupagus to fuzz or audit a codebase.
155 157
156log_max_len 158log_max_len
157^^^^^^^^^^^ 159^^^^^^^^^^^
diff --git a/src/php_snuffleupagus.h b/src/php_snuffleupagus.h
index be37cfa..adaa6c0 100644
--- a/src/php_snuffleupagus.h
+++ b/src/php_snuffleupagus.h
@@ -141,7 +141,7 @@ sp_config_eval config_eval;
141sp_config_wrapper config_wrapper; 141sp_config_wrapper config_wrapper;
142sp_config_session config_session; 142sp_config_session config_session;
143sp_config_ini config_ini; 143sp_config_ini config_ini;
144char config_log_media; 144sp_config_log config_log_media;
145int config_log_max_len; 145int config_log_max_len;
146u_long config_max_execution_depth; 146u_long config_max_execution_depth;
147bool config_server_encode; 147bool config_server_encode;
diff --git a/src/snuffleupagus.c b/src/snuffleupagus.c
index 6264d22..8b7f11d 100644
--- a/src/snuffleupagus.c
+++ b/src/snuffleupagus.c
@@ -356,7 +356,7 @@ static void dump_config(void) {
356 // global 356 // global
357 add_assoc_bool(&arr, SP_TOKEN_GLOBAL "." SP_TOKEN_ENCRYPTION_KEY, SPCFG(encryption_key) && ZSTR_LEN(SPCFG(encryption_key))); 357 add_assoc_bool(&arr, SP_TOKEN_GLOBAL "." SP_TOKEN_ENCRYPTION_KEY, SPCFG(encryption_key) && ZSTR_LEN(SPCFG(encryption_key)));
358 ADD_ASSOC_ZSTR(&arr, SP_TOKEN_GLOBAL "." SP_TOKEN_ENV_VAR, SPCFG(cookies_env_var)); 358 ADD_ASSOC_ZSTR(&arr, SP_TOKEN_GLOBAL "." SP_TOKEN_ENV_VAR, SPCFG(cookies_env_var));
359 add_assoc_long(&arr, SP_TOKEN_GLOBAL "." SP_TOKEN_LOG_MEDIA, SPCFG(log_media)); 359 //add_assoc_long(&arr, SP_TOKEN_GLOBAL "." SP_TOKEN_LOG_MEDIA, SPCFG(log_media));
360 add_assoc_long(&arr, SP_TOKEN_GLOBAL "." SP_TOKEN_LOG_MAX_LEN, SPCFG(log_max_len)); 360 add_assoc_long(&arr, SP_TOKEN_GLOBAL "." SP_TOKEN_LOG_MAX_LEN, SPCFG(log_max_len));
361 add_assoc_long(&arr, SP_TOKEN_GLOBAL "." SP_TOKEN_MAX_EXECUTION_DEPTH, SPCFG(max_execution_depth)); 361 add_assoc_long(&arr, SP_TOKEN_GLOBAL "." SP_TOKEN_MAX_EXECUTION_DEPTH, SPCFG(max_execution_depth));
362 add_assoc_bool(&arr, SP_TOKEN_GLOBAL "." SP_TOKEN_SERVER_ENCODE, SPCFG(server_encode)); 362 add_assoc_bool(&arr, SP_TOKEN_GLOBAL "." SP_TOKEN_SERVER_ENCODE, SPCFG(server_encode));
diff --git a/src/sp_config.h b/src/sp_config.h
index 6bfb009..8886bc6 100644
--- a/src/sp_config.h
+++ b/src/sp_config.h
@@ -19,10 +19,15 @@ typedef enum {
19 SP_PHP_TYPE_REFERENCE = IS_REFERENCE 19 SP_PHP_TYPE_REFERENCE = IS_REFERENCE
20} sp_php_type; 20} sp_php_type;
21 21
22typedef enum { SP_LOG_ZEND = 0, SP_LOG_SYSLOG = 1 } sp_log_media;
23 22
24typedef enum { SP_INI_UNSET = 0, SP_INI_READONLY = 1, SP_INI_READWRITE = -1 } sp_ini_permission; 23typedef enum { SP_INI_UNSET = 0, SP_INI_READONLY = 1, SP_INI_READWRITE = -1 } sp_ini_permission;
25 24
25typedef enum { SP_LOG_ZEND = 0, SP_LOG_SYSLOG = 1, SP_LOG_FILE = 2 } sp_log_media_type;
26typedef struct {
27 sp_log_media_type type;
28 char* path;
29} sp_config_log;
30
26typedef struct { 31typedef struct {
27 int ip_version; 32 int ip_version;
28 union { 33 union {
diff --git a/src/sp_config_keywords.c b/src/sp_config_keywords.c
index a5b4c5d..7f41e38 100644
--- a/src/sp_config_keywords.c
+++ b/src/sp_config_keywords.c
@@ -57,19 +57,27 @@ SP_PARSE_FN(parse_session) {
57} 57}
58 58
59SP_PARSEKW_FN(parse_log_media) { 59SP_PARSEKW_FN(parse_log_media) {
60 sp_config_log *cfg = (sp_config_log*)retval;
61 cfg->path = NULL;
62
60 SP_PARSE_ARG(value); 63 SP_PARSE_ARG(value);
61 64
62 if (!strcmp(ZSTR_VAL(value), "php")) { 65 if (!strcmp(ZSTR_VAL(value), "php")) {
63 *(char*)retval = SP_LOG_ZEND; 66 cfg->type = SP_LOG_ZEND;
64 zend_string_release_ex(value, 1); 67 zend_string_release_ex(value, 1);
65 return SP_PARSER_SUCCESS; 68 return SP_PARSER_STOP;
66 } else if (!strcmp(ZSTR_VAL(value), "syslog")) { 69 } else if (!strcmp(ZSTR_VAL(value), "syslog")) {
67 *(char*)retval = SP_LOG_SYSLOG; 70 cfg->type = SP_LOG_SYSLOG;
71 zend_string_release_ex(value, 1);
72 return SP_PARSER_STOP;
73 } else if (!strncmp(ZSTR_VAL(value), "file:", strlen("file:"))) {
74 cfg->type = SP_LOG_FILE;
75 cfg->path = strdup(ZSTR_VAL(value)+strlen("file:"));
68 zend_string_release_ex(value, 1); 76 zend_string_release_ex(value, 1);
69 return SP_PARSER_SUCCESS; 77 return SP_PARSER_STOP;
70 } 78 }
71 79
72 sp_log_err("config", "." SP_TOKEN_LOG_MEDIA "() only supports 'syslog' or 'php' on line %zu", kw->lineno); 80 sp_log_err("config", "." SP_TOKEN_LOG_MEDIA "() only supports 'syslog', 'file:' or 'php' on line %zu, got '%s' instead", kw->lineno, ZSTR_VAL(value));
73 81
74 return SP_PARSER_ERROR; 82 return SP_PARSER_ERROR;
75} 83}
diff --git a/src/sp_utils.c b/src/sp_utils.c
index 775ff95..41eb638 100644
--- a/src/sp_utils.c
+++ b/src/sp_utils.c
@@ -43,7 +43,7 @@ void sp_log_msgf(char const* const restrict feature, int level, int type,
43 break; 43 break;
44 } 44 }
45 45
46 switch (SPCFG(log_media)) { 46 switch (SPCFG(log_media).type) {
47 case SP_LOG_SYSLOG: { 47 case SP_LOG_SYSLOG: {
48 const char* error_filename = zend_get_executed_filename(); 48 const char* error_filename = zend_get_executed_filename();
49 int syslog_level = (level == E_ERROR) ? LOG_ERR : LOG_INFO; 49 int syslog_level = (level == E_ERROR) ? LOG_ERR : LOG_INFO;
@@ -54,6 +54,20 @@ void sp_log_msgf(char const* const restrict feature, int level, int type,
54 closelog(); 54 closelog();
55 break; 55 break;
56 } 56 }
57 case SP_LOG_FILE: {
58 FILE* logf = fopen(SPCFG(log_media).path, "a");
59 if (!logf) {
60 zend_error(level, "[snuffleupagus][%s][logging][log] unable to open %s to log", client_ip,
61 SPCFG(log_media).path);
62 } else {
63 int error_lineno = zend_get_executed_lineno(TSRMLS_C);
64 const char* error_filename = zend_get_executed_filename();
65 fprintf(logf, "[snuffleupagus][%s][%s][%s] %s in %s on line %d\n",
66 client_ip, feature, logtype, msg, error_filename, error_lineno);
67 fclose(logf);
68 }
69 break;
70 }
57 case SP_LOG_ZEND: 71 case SP_LOG_ZEND:
58 default: 72 default:
59 zend_error(level, "[snuffleupagus][%s][%s][%s] %s", client_ip, feature, 73 zend_error(level, "[snuffleupagus][%s][%s][%s] %s", client_ip, feature,
diff --git a/src/tests/broken_configuration/broken_conf_invalid_log_media.phpt b/src/tests/broken_configuration/broken_conf_invalid_log_media.phpt
index af0d61f..fef055c 100644
--- a/src/tests/broken_configuration/broken_conf_invalid_log_media.phpt
+++ b/src/tests/broken_configuration/broken_conf_invalid_log_media.phpt
@@ -7,7 +7,7 @@ sp.configuration_file={PWD}/config/broken_conf_invalid_log_media.ini
7error_log=/dev/null 7error_log=/dev/null
8--FILE-- 8--FILE--
9--EXPECTF-- 9--EXPECTF--
10Fatal error: [snuffleupagus][0.0.0.0][config][log] .log_media() only supports 'syslog' or 'php' on line 1 in Unknown on line 0 10Fatal error: [snuffleupagus][0.0.0.0][config][log] .log_media() only supports 'syslog', 'file:' or 'php' on line 1, got 'pouet' instead in Unknown on line 0
11 11
12Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 12Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0
13Could not startup. 13Could not startup.
diff --git a/src/tests/syslog_simulation.phpt b/src/tests/syslog_simulation.phpt
index 4b12f58..ff78928 100644
--- a/src/tests/syslog_simulation.phpt
+++ b/src/tests/syslog_simulation.phpt
@@ -9,3 +9,4 @@ sp.configuration_file={PWD}/config/syslog_simulation.ini
9var_dump(unserialize('s:1:"a";')); 9var_dump(unserialize('s:1:"a";'));
10?> 10?>
11--EXPECTF-- 11--EXPECTF--
12string(1) "a"