123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354 |
- /*-
- * Copyright 2016 Vsevolod Stakhov
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #include "config.h"
- #include "rspamd.h"
- #include "smtp.h"
- #include "unix-std.h"
-
- void
- free_smtp_session (gpointer arg)
- {
- struct smtp_session *session = arg;
-
- if (session) {
- if (session->task) {
- if (session->task->msg.begin) {
- munmap ((gpointer)session->task->msg.begin,
- session->task->msg.len);
- }
- rspamd_task_free (session->task);
- }
- if (session->rcpt) {
- g_list_free (session->rcpt);
- }
- if (session->dispatcher) {
- rspamd_remove_dispatcher (session->dispatcher);
- }
- close (session->sock);
- if (session->temp_name != NULL) {
- unlink (session->temp_name);
- }
- if (session->temp_fd != -1) {
- close (session->temp_fd);
- }
- rspamd_mempool_delete (session->pool);
- g_free (session);
- }
- }
-
- gboolean
- create_smtp_upstream_connection (struct smtp_session *session)
- {
- struct upstream *selected;
-
- /* Try to select upstream */
- selected = rspamd_upstream_get (session->ctx->upstreams,
- RSPAMD_UPSTREAM_ROUND_ROBIN, NULL, 0);
- if (selected == NULL) {
- msg_err ("no upstreams suitable found");
- return FALSE;
- }
-
- session->upstream = selected;
-
- /* Now try to create socket */
- session->upstream_sock = rspamd_inet_address_connect (
- rspamd_upstream_addr (selected), SOCK_STREAM, TRUE);
- if (session->upstream_sock == -1) {
- msg_err ("cannot make a connection to %s", rspamd_upstream_name (selected));
- rspamd_upstream_fail (selected);
- return FALSE;
- }
- /* Create a dispatcher for upstream connection */
- session->upstream_dispatcher = rspamd_create_dispatcher (session->ev_base,
- session->upstream_sock,
- BUFFER_LINE,
- smtp_upstream_read_socket,
- smtp_upstream_write_socket,
- smtp_upstream_err_socket,
- &session->ctx->smtp_timeout,
- session);
- session->state = SMTP_STATE_WAIT_UPSTREAM;
- session->upstream_state = SMTP_STATE_GREETING;
- rspamd_session_add_event (session->s,
- (event_finalizer_t)smtp_upstream_finalize_connection,
- session,
- g_quark_from_static_string ("smtp proxy"));
- return TRUE;
- }
-
- gboolean
- smtp_send_upstream_message (struct smtp_session *session)
- {
- rspamd_dispatcher_pause (session->dispatcher);
- rspamd_dispatcher_restore (session->upstream_dispatcher);
-
- session->upstream_state = SMTP_STATE_IN_SENDFILE;
- session->state = SMTP_STATE_WAIT_UPSTREAM;
- if (!rspamd_dispatcher_sendfile (session->upstream_dispatcher,
- session->temp_fd, session->temp_size)) {
- msg_err ("sendfile failed: %s", strerror (errno));
- goto err;
- }
- return TRUE;
-
- err:
- session->error = SMTP_ERROR_FILE;
- session->state = SMTP_STATE_CRITICAL_ERROR;
- if (!rspamd_dispatcher_write (session->dispatcher, session->error, 0, FALSE,
- TRUE)) {
- return FALSE;
- }
- rspamd_session_destroy (session->s);
- return FALSE;
- }
-
- struct smtp_metric_callback_data {
- struct smtp_session *session;
- enum rspamd_metric_action action;
- struct metric_result *res;
- gchar *log_buf;
- gint log_offset;
- gint log_size;
- gboolean alive;
- };
-
- static void
- smtp_metric_symbols_callback (gpointer key, gpointer value, void *user_data)
- {
- struct smtp_metric_callback_data *cd = user_data;
-
- cd->log_offset += rspamd_snprintf (cd->log_buf + cd->log_offset,
- cd->log_size - cd->log_offset,
- "%s,",
- (gchar *)key);
- }
-
- static void
- smtp_metric_callback (gpointer key, gpointer value, gpointer ud)
- {
- struct smtp_metric_callback_data *cd = ud;
- struct metric_result *metric_res = value;
- enum rspamd_metric_action action = METRIC_ACTION_NOACTION;
- double ms = 0, rs = 0;
- gboolean is_spam = FALSE;
- struct rspamd_task *task;
-
- task = cd->session->task;
-
- /* XXX rewrite */
- ms = metric_res->metric->actions[METRIC_ACTION_REJECT].score;
- rs = metric_res->metric->actions[METRIC_ACTION_REJECT].score;
- #if 0
- if (!check_metric_settings (metric_res, &ms, &rs)) {
- ms = metric_res->metric->actions[METRIC_ACTION_REJECT].score;
- rs = metric_res->metric->actions[METRIC_ACTION_REJECT].score;
- }
- if (!check_metric_action_settings (task, metric_res, metric_res->score,
- &action)) {
- action =
- check_metric_action (metric_res->score, ms, metric_res->metric);
- }
- #endif
- if (metric_res->score >= ms) {
- is_spam = 1;
- }
- if (action < cd->action) {
- cd->action = action;
- cd->res = metric_res;
- }
-
- if (!RSPAMD_TASK_IS_SKIPPED (task)) {
- cd->log_offset += rspamd_snprintf (cd->log_buf + cd->log_offset,
- cd->log_size - cd->log_offset,
- "(%s: %c (%s): [%.2f/%.2f/%.2f] [",
- (gchar *)key,
- is_spam ? 'T' : 'F',
- rspamd_action_to_str (action),
- metric_res->score,
- ms,
- rs);
- }
- else {
- cd->log_offset += rspamd_snprintf (cd->log_buf + cd->log_offset,
- cd->log_size - cd->log_offset,
- "(%s: %c (default): [%.2f/%.2f/%.2f] [",
- (gchar *)key,
- 'S',
- metric_res->score,
- ms,
- rs);
-
- }
- g_hash_table_foreach (metric_res->symbols, smtp_metric_symbols_callback,
- cd);
- /* Remove last , from log buf */
- if (cd->log_buf[cd->log_offset - 1] == ',') {
- cd->log_buf[--cd->log_offset] = '\0';
- }
-
- cd->log_offset += rspamd_snprintf (cd->log_buf + cd->log_offset,
- cd->log_size - cd->log_offset,
- "]), len: %z, time: %s,",
- task->msg.len,
- rspamd_log_check_time (task->time_real, task->time_virtual,
- task->cfg->clock_res));
- }
-
- gboolean
- make_smtp_tempfile (struct smtp_session *session)
- {
- gsize r;
-
- r = strlen (session->cfg->temp_dir) + sizeof ("/rspamd-XXXXXX");
- session->temp_name = rspamd_mempool_alloc (session->pool, r);
- rspamd_snprintf (session->temp_name,
- r,
- "%s/rspamd-XXXXXX",
- session->cfg->temp_dir);
- #ifdef HAVE_MKSTEMP
- /* Umask is set before */
- session->temp_fd = mkstemp (session->temp_name);
- #else
- session->temp_fd = g_mkstemp_full (session->temp_name,
- O_RDWR,
- S_IWUSR | S_IRUSR);
- #endif
- if (session->temp_fd == -1) {
- msg_err ("mkstemp error: %s", strerror (errno));
-
- return FALSE;
- }
-
- return TRUE;
- }
-
- gboolean
- write_smtp_reply (struct smtp_session *session)
- {
- gchar logbuf[1024], *new_subject;
- const gchar *old_subject;
- struct smtp_metric_callback_data cd;
- GMimeStream *stream;
- gint old_fd, sublen;
-
- /* Check metrics */
- cd.session = session;
- cd.action = METRIC_ACTION_NOACTION;
- cd.res = NULL;
- cd.log_buf = logbuf;
- cd.log_offset = rspamd_snprintf (logbuf,
- sizeof (logbuf),
- "id: <%s>, qid: <%s>, ",
- session->task->message_id,
- session->task->queue_id);
- cd.log_size = sizeof (logbuf);
- if (session->task->user) {
- cd.log_offset += rspamd_snprintf (logbuf + cd.log_offset,
- sizeof (logbuf) - cd.log_offset,
- "user: %s, ",
- session->task->user);
- }
-
- g_hash_table_foreach (session->task->results, smtp_metric_callback, &cd);
-
- msg_info ("%s", logbuf);
-
- if (cd.action <= METRIC_ACTION_REJECT) {
- if (!rspamd_dispatcher_write (session->dispatcher,
- session->ctx->reject_message, 0, FALSE, TRUE)) {
- return FALSE;
- }
- if (!rspamd_dispatcher_write (session->dispatcher, CRLF, sizeof (CRLF) -
- 1, FALSE, TRUE)) {
- return FALSE;
- }
- rspamd_session_destroy (session->s);
- return FALSE;
- }
- else if (cd.action <= METRIC_ACTION_ADD_HEADER || cd.action <=
- METRIC_ACTION_REWRITE_SUBJECT) {
- old_fd = session->temp_fd;
- if (!make_smtp_tempfile (session)) {
- session->error = SMTP_ERROR_FILE;
- session->state = SMTP_STATE_CRITICAL_ERROR;
- rspamd_dispatcher_restore (session->dispatcher);
- if (!rspamd_dispatcher_write (session->dispatcher, session->error,
- 0, FALSE, TRUE)) {
- goto err;
- }
- rspamd_session_destroy (session->s);
- return FALSE;
- }
-
- if (cd.action <= METRIC_ACTION_REWRITE_SUBJECT) {
- /* XXX: add this action */
- old_subject = g_mime_message_get_subject (session->task->message);
- if (old_subject != NULL) {
- sublen = strlen (old_subject) + sizeof (SPAM_SUBJECT);
- new_subject = rspamd_mempool_alloc (session->pool, sublen);
- rspamd_snprintf (new_subject,
- sublen,
- "%s%s",
- SPAM_SUBJECT,
- old_subject);
- }
- else {
- new_subject = SPAM_SUBJECT;
- }
- g_mime_message_set_subject (session->task->message, new_subject);
- }
- else if (cd.action <= METRIC_ACTION_ADD_HEADER) {
- #ifndef GMIME24
- g_mime_message_add_header (session->task->message, "X-Spam",
- "true");
- #else
- g_mime_object_append_header (GMIME_OBJECT (
- session->task->message), "X-Spam", "true");
- #endif
- }
- stream = g_mime_stream_fs_new (session->temp_fd);
- g_mime_stream_fs_set_owner (GMIME_STREAM_FS (stream), FALSE);
- close (old_fd);
-
- if (g_mime_object_write_to_stream (GMIME_OBJECT (session->task->message),
- stream) == -1) {
- msg_err ("cannot write MIME object to stream: %s",
- strerror (errno));
- session->error = SMTP_ERROR_FILE;
- session->state = SMTP_STATE_CRITICAL_ERROR;
- rspamd_dispatcher_restore (session->dispatcher);
- if (!rspamd_dispatcher_write (session->dispatcher, session->error,
- 0, FALSE, TRUE)) {
- goto err;
- }
- rspamd_session_destroy (session->s);
- return FALSE;
- }
- g_object_unref (stream);
- }
- /* XXX: Add other actions */
- return smtp_send_upstream_message (session);
- err:
- session->error = SMTP_ERROR_FILE;
- session->state = SMTP_STATE_CRITICAL_ERROR;
- if (!rspamd_dispatcher_write (session->dispatcher, session->error, 0, FALSE,
- TRUE)) {
- return FALSE;
- }
- rspamd_session_destroy (session->s);
- return FALSE;
- }
|