1 #include "php_snuffleupagus.h"
2
3 int (*sp_rfc1867_orig_callback)(unsigned int event, void *event_data,
4 void **extra);
5 int sp_rfc1867_callback(unsigned int event, void *event_data, void **extra);
6
7 #define EFREE_3(env) \
8 for (size_t i = 0; i < 4; i++) { \
9 efree(env[i]); \
10 }
11
12 #ifdef PHP_WIN32
13
sp_rfc1867_callback_win(unsigned int event,void * event_data,void ** extra)14 int sp_rfc1867_callback_win(unsigned int event, void *event_data,
15 void **extra) {
16 sp_log_simulation(
17 "upload_validation",
18 "The upload validation doesn't work for now on Windows yet, "
19 "see https://github.com/jvoisin/snuffleupagus/issues/248 for "
20 "details.");
21 return SUCCESS;
22 }
23
24 #else
25
sp_rfc1867_callback(unsigned int event,void * event_data,void ** extra)26 int sp_rfc1867_callback(unsigned int event, void *event_data, void **extra) {
27 int retval = SUCCESS;
28
29 if (sp_rfc1867_orig_callback) {
30 retval = sp_rfc1867_orig_callback(event, event_data, extra);
31 }
32
33 if (event == MULTIPART_EVENT_END) {
34 zend_string *file_key __attribute__((unused)) = NULL;
35 const sp_config_upload_validation *config_upload =
36 SNUFFLEUPAGUS_G(config).config_upload_validation;
37 zval *file;
38 pid_t pid;
39
40 sp_log_debug(
41 "Got %d files",
42 zend_hash_num_elements(Z_ARRVAL(PG(http_globals)[TRACK_VARS_FILES])));
43
44 ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL(PG(http_globals)[TRACK_VARS_FILES]),
45 file_key, file) { // for each uploaded file
46
47 char *filename = Z_STRVAL_P(
48 zend_hash_str_find(Z_ARRVAL_P(file), "name", sizeof("name") - 1));
49 char *tmp_name = Z_STRVAL_P(zend_hash_str_find(
50 Z_ARRVAL_P(file), "tmp_name", sizeof("tmp_name") - 1));
51 size_t filesize = Z_LVAL_P(
52 zend_hash_str_find(Z_ARRVAL_P(file), "size", sizeof("size") - 1));
53 char *cmd[3] = {0};
54 char *env[5] = {0};
55
56 sp_log_debug("Filename: %s\nTmpname: %s\nSize: %d\nError: %d\nScript: %s",
57 filename, tmp_name, filesize,
58 Z_LVAL_P(zend_hash_str_find(Z_ARRVAL_P(file), "error", 5)),
59 ZSTR_VAL(config_upload->script));
60
61 cmd[0] = ZSTR_VAL(config_upload->script);
62 cmd[1] = tmp_name;
63 cmd[2] = NULL;
64
65 spprintf(&env[0], 0, "SP_FILENAME=%s", filename);
66 spprintf(&env[1], 0, "SP_REMOTE_ADDR=%s", getenv("REMOTE_ADDR"));
67 spprintf(&env[2], 0, "SP_CURRENT_FILE=%s",
68 zend_get_executed_filename(TSRMLS_C));
69 spprintf(&env[3], 0, "SP_FILESIZE=%zu", filesize);
70 env[4] = NULL;
71
72 if ((pid = fork()) == 0) {
73 if (execve(ZSTR_VAL(config_upload->script), cmd, env) == -1) {
74 sp_log_warn("upload_validation", "Could not call '%s' : %s",
75 ZSTR_VAL(config_upload->script), strerror(errno));
76 EFREE_3(env);
77 exit(1);
78 }
79 } else if (pid == -1) {
80 // LCOV_EXCL_START
81 sp_log_err("upload_validation", "Could not fork process : %s\n",
82 strerror(errno));
83 EFREE_3(env);
84 continue;
85 // LCOV_EXCL_STOP
86 }
87
88 EFREE_3(env);
89 int waitstatus;
90 wait(&waitstatus);
91 if (WEXITSTATUS(waitstatus) != 0) { // Nope
92 char *uri = getenv("REQUEST_URI");
93 int sim = config_upload->simulation;
94 sp_log_auto("upload_validation", sim,
95 "The upload of %s on %s was rejected.", filename,
96 uri ? uri : "?");
97 }
98 }
99 ZEND_HASH_FOREACH_END();
100 }
101 return retval;
102 }
103 #endif
104
hook_upload()105 void hook_upload() {
106 if (NULL == sp_rfc1867_orig_callback) {
107 sp_rfc1867_orig_callback = php_rfc1867_callback;
108 php_rfc1867_callback = sp_rfc1867_callback;
109 }
110 }
111