]> source.dussan.org Git - rspamd.git/commitdiff
Allow scanning local files in rspamd.
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Fri, 10 Jul 2015 16:24:18 +0000 (17:24 +0100)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Fri, 10 Jul 2015 16:24:18 +0000 (17:24 +0100)
src/libserver/protocol.c
src/libserver/task.c
src/libserver/task.h
src/libserver/url.h

index 323838b6d81953d5d94438da16a827776056456e..e6407d3a09df2d14aff45476af95892d981ce243 100644 (file)
@@ -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:
index 97ed76b5cd33c07261e273d9e2a2a0f88be3a10d..3cd4dc526ebfed4e6b0a2a1a6f1ef135e21caf05 100644 (file)
@@ -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;
+                       }
                }
        }
 
index 25694be9aad2f2e84c1fefbb32831e1dfc4fae4a..79aa19fb5a646ab9444d9de934c9f179c50099af 100644 (file)
@@ -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))
index 8666b8c9f5ba9a9e0d09cdd6890c5a48e0845556..be9ca3b55298f9008e3bc869efa9f9972f55f1b4 100644 (file)
@@ -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