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