diff options
-rw-r--r-- | src/libserver/protocol.c | 7 | ||||
-rw-r--r-- | src/libserver/task.c | 120 | ||||
-rw-r--r-- | src/libserver/task.h | 1 | ||||
-rw-r--r-- | src/libserver/url.h | 3 |
4 files changed, 97 insertions, 34 deletions
diff --git a/src/libserver/protocol.c b/src/libserver/protocol.c index 323838b6d..e6407d3a0 100644 --- a/src/libserver/protocol.c +++ b/src/libserver/protocol.c @@ -248,6 +248,13 @@ rspamd_protocol_handle_url (struct rspamd_task *task, break; } + if (u.field_set & (1 << UF_QUERY)) { + /* In case if we have a query, we need to store it somewhere */ + task->msg.start = msg->url->str + u.field_data[UF_QUERY].off; + task->msg.len = u.field_data[UF_QUERY].len; + task->flags |= RSPAMD_TASK_FLAG_FILE; + } + return TRUE; err: diff --git a/src/libserver/task.c b/src/libserver/task.c index 97ed76b5c..3cd4dc526 100644 --- a/src/libserver/task.c +++ b/src/libserver/task.c @@ -235,58 +235,110 @@ rspamd_task_free_soft (gpointer ud) rspamd_task_free (task, FALSE); } +static void +rspamd_task_unmapper (gpointer ud) +{ + struct rspamd_task *task = ud; + + munmap ((void *)task->msg.start, task->msg.len); +} + gboolean rspamd_task_load_message (struct rspamd_task *task, struct rspamd_http_message *msg, const gchar *start, gsize len) { - guint control_len; + guint control_len, r; struct ucl_parser *parser; ucl_object_t *control_obj; - - debug_task ("got input of length %z", task->msg.len); - task->msg.start = start; - task->msg.len = len; - - if (task->msg.len == 0) { - msg_warn ("message has invalid message length: %ud", - task->msg.len); - g_set_error (&task->err, rspamd_task_quark(), RSPAMD_PROTOCOL_ERROR, - "Invalid length"); - return FALSE; - } + gchar filepath[PATH_MAX]; + gint fd; + gpointer map; + struct stat st; if (msg) { rspamd_protocol_handle_headers (task, msg); } - if (task->flags & RSPAMD_TASK_FLAG_HAS_CONTROL) { - /* We have control chunk, so we need to process it separately */ - if (task->msg.len < task->message_len) { - msg_warn ("message has invalid message length: %ud and total len: %ud", - task->message_len, task->msg.len); + if (task->flags & RSPAMD_TASK_FLAG_FILE) { + g_assert (task->msg.len > 0); + + r = rspamd_strlcpy (filepath, task->msg.start, + MIN (sizeof (filepath), task->msg.len + 1)); + + rspamd_unescape_uri (filepath, filepath, r); + + if (access (filepath, R_OK) == -1 || stat (filepath, &st) == -1) { g_set_error (&task->err, rspamd_task_quark(), RSPAMD_PROTOCOL_ERROR, - "Invalid length"); + "Invalid file (%s): %s", filepath, strerror (errno)); return FALSE; } - control_len = task->msg.len - task->message_len; - if (control_len > 0) { - parser = ucl_parser_new (UCL_PARSER_KEY_LOWERCASE); + fd = open (filepath, O_RDONLY); - if (!ucl_parser_add_chunk (parser, task->msg.start, control_len)) { - msg_warn ("processing of control chunk failed: %s", - ucl_parser_get_error (parser)); - ucl_parser_free (parser); - } - else { - control_obj = ucl_parser_get_object (parser); - ucl_parser_free (parser); - rspamd_protocol_handle_control (task, control_obj); - ucl_object_unref (control_obj); + if (fd == -1) { + g_set_error (&task->err, rspamd_task_quark(), RSPAMD_PROTOCOL_ERROR, + "Cannot open file (%s): %s", filepath, strerror (errno)); + return FALSE; + } + + map = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); + + + if (map == MAP_FAILED) { + close (fd); + g_set_error (&task->err, rspamd_task_quark(), RSPAMD_PROTOCOL_ERROR, + "Cannot mmap file (%s): %s", filepath, strerror (errno)); + return FALSE; + } + + close (fd); + task->msg.start = map; + task->msg.len = st.st_size; + + rspamd_mempool_add_destructor (task->task_pool, rspamd_task_unmapper, task); + } + else { + debug_task ("got input of length %z", task->msg.len); + task->msg.start = start; + task->msg.len = len; + + if (task->msg.len == 0) { + msg_warn ("message has invalid message length: %ud", + task->msg.len); + g_set_error (&task->err, rspamd_task_quark(), RSPAMD_PROTOCOL_ERROR, + "Invalid length"); + return FALSE; + } + + if (task->flags & RSPAMD_TASK_FLAG_HAS_CONTROL) { + /* We have control chunk, so we need to process it separately */ + if (task->msg.len < task->message_len) { + msg_warn ("message has invalid message length: %ud and total len: %ud", + task->message_len, task->msg.len); + g_set_error (&task->err, rspamd_task_quark(), RSPAMD_PROTOCOL_ERROR, + "Invalid length"); + return FALSE; } + control_len = task->msg.len - task->message_len; + + if (control_len > 0) { + parser = ucl_parser_new (UCL_PARSER_KEY_LOWERCASE); - task->msg.start += control_len; - task->msg.len -= control_len; + if (!ucl_parser_add_chunk (parser, task->msg.start, control_len)) { + msg_warn ("processing of control chunk failed: %s", + ucl_parser_get_error (parser)); + ucl_parser_free (parser); + } + else { + control_obj = ucl_parser_get_object (parser); + ucl_parser_free (parser); + rspamd_protocol_handle_control (task, control_obj); + ucl_object_unref (control_obj); + } + + task->msg.start += control_len; + task->msg.len -= control_len; + } } } diff --git a/src/libserver/task.h b/src/libserver/task.h index 25694be9a..79aa19fb5 100644 --- a/src/libserver/task.h +++ b/src/libserver/task.h @@ -89,6 +89,7 @@ enum rspamd_task_stage { #define RSPAMD_TASK_FLAG_HAS_CONTROL (1 << 9) #define RSPAMD_TASK_FLAG_PROCESSING (1 << 10) #define RSPAMD_TASK_FLAG_GTUBE (1 << 11) +#define RSPAMD_TASK_FLAG_FILE (1 << 12) #define RSPAMD_TASK_IS_SKIPPED(task) (((task)->flags & RSPAMD_TASK_FLAG_SKIP)) #define RSPAMD_TASK_IS_JSON(task) (((task)->flags & RSPAMD_TASK_FLAG_JSON)) diff --git a/src/libserver/url.h b/src/libserver/url.h index 8666b8c9f..be9ca3b55 100644 --- a/src/libserver/url.h +++ b/src/libserver/url.h @@ -122,4 +122,7 @@ struct rspamd_url * rspamd_url_get_next (rspamd_mempool_t *pool, const gchar *start, gchar const **pos, gint *statep); +void +rspamd_unescape_uri (gchar *dst, const gchar *src, gsize size); + #endif |