From ad7ee29e6187617af43197293b580582d88b320d Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Tue, 5 May 2015 15:10:54 +0100 Subject: [PATCH] Fix various issues in encrypted messages support. --- src/libutil/http.c | 163 ++++++++++++++++++++++++++++++--------------- src/libutil/http.h | 27 ++++++-- 2 files changed, 132 insertions(+), 58 deletions(-) diff --git a/src/libutil/http.c b/src/libutil/http.c index 4547aa5f8..fe1120870 100644 --- a/src/libutil/http.c +++ b/src/libutil/http.c @@ -601,43 +601,42 @@ rspamd_http_on_message_complete (http_parser * parser) priv = conn->priv; - if (conn->body_handler != NULL) { + if ((conn->opts & RSPAMD_HTTP_BODY_PARTIAL) == 0 && priv->encrypted) { + if (priv->local_key == NULL || priv->msg->peer_key == NULL || + priv->msg->body->len < rspamd_cryptobox_NONCEBYTES + + rspamd_cryptobox_MACBYTES) { + msg_err ("cannot decrypt message"); + return -1; + } + /* We have keys, so we can decrypt message */ + /* TODO: add pubkey<->privkey pairs to LRU cache */ + nonce = priv->msg->body->str; + m = priv->msg->body->str + rspamd_cryptobox_NONCEBYTES + + rspamd_cryptobox_MACBYTES; + dec_len = priv->msg->body->len - rspamd_cryptobox_NONCEBYTES - + rspamd_cryptobox_MACBYTES; + peer_key = (struct rspamd_http_keypair *)priv->msg->peer_key; - if (priv->encrypted) { - if (priv->local_key == NULL || priv->msg->peer_key == NULL || - priv->msg->body->len < rspamd_cryptobox_NONCEBYTES + - rspamd_cryptobox_MACBYTES) { - msg_err ("cannot decrypt message"); + if (conn->cache) { + if (!rspamd_cryptobox_decrypt_nm_inplace (m, dec_len, nonce, + peer_key->nm, m - rspamd_cryptobox_MACBYTES) != 0) { + msg_err ("cannot verify encrypted message"); return -1; } - /* We have keys, so we can decrypt message */ - /* TODO: add pubkey<->privkey pairs to LRU cache */ - nonce = priv->msg->body->str; - m = priv->msg->body->str + rspamd_cryptobox_NONCEBYTES + - rspamd_cryptobox_MACBYTES; - dec_len = priv->msg->body->len - rspamd_cryptobox_NONCEBYTES - - rspamd_cryptobox_MACBYTES; - peer_key = (struct rspamd_http_keypair *)priv->msg->peer_key; - - if (conn->cache) { - if (!rspamd_cryptobox_decrypt_nm_inplace (m, dec_len, nonce, - peer_key->nm, m - rspamd_cryptobox_MACBYTES) != 0) { - msg_err ("cannot verify encrypted message"); - return -1; - } - } - else { - if (!rspamd_cryptobox_decrypt_inplace (m, dec_len, nonce, - peer_key->pk, priv->local_key->sk, - m - rspamd_cryptobox_MACBYTES) != 0) { - msg_err ("cannot verify encrypted message"); - return -1; - } + } + else { + if (!rspamd_cryptobox_decrypt_inplace (m, dec_len, nonce, + peer_key->pk, priv->local_key->sk, + m - rspamd_cryptobox_MACBYTES) != 0) { + msg_err ("cannot verify encrypted message"); + return -1; } + } - priv->msg->body->str = m; - priv->msg->body->len = dec_len; + priv->msg->body->str = m; + priv->msg->body->len = dec_len; + if (conn->body_handler != NULL) { rspamd_http_connection_ref (conn); ret = conn->body_handler (conn, priv->msg, @@ -645,14 +644,15 @@ rspamd_http_on_message_complete (http_parser * parser) dec_len); rspamd_http_connection_unref (conn); } - else if ((conn->opts & RSPAMD_HTTP_BODY_PARTIAL) == 0) { - rspamd_http_connection_ref (conn); - ret = conn->body_handler (conn, - priv->msg, - priv->msg->body->str, - priv->msg->body->len); - rspamd_http_connection_unref (conn); - } + } + else if ((conn->opts & RSPAMD_HTTP_BODY_PARTIAL) == 0 && conn->body_handler) { + g_assert (conn->body_handler != NULL); + rspamd_http_connection_ref (conn); + ret = conn->body_handler (conn, + priv->msg, + priv->msg->body->str, + priv->msg->body->len); + rspamd_http_connection_unref (conn); } if (ret == 0) { @@ -805,9 +805,11 @@ rspamd_http_event_handler (int fd, short what, gpointer ud) conn->error_handler (conn, err); g_error_free (err); - REF_RELEASE (pbuf); - rspamd_http_connection_unref (conn); + } + REF_RELEASE (pbuf); + rspamd_http_connection_unref (conn); + return; } else { @@ -923,6 +925,7 @@ rspamd_http_connection_reset (struct rspamd_http_connection *conn) event_del (&priv->ev); if (priv->buf != NULL) { REF_RELEASE (priv->buf); + priv->buf = NULL; } rspamd_http_parser_reset (conn); @@ -933,6 +936,27 @@ rspamd_http_connection_reset (struct rspamd_http_connection *conn) } } +struct rspamd_http_message * +rspamd_http_connection_steal_msg (struct rspamd_http_connection *conn) +{ + struct rspamd_http_connection_private *priv; + struct rspamd_http_message *msg; + + priv = conn->priv; + msg = priv->msg; + + /* Clear request */ + if (msg != NULL) { + if (msg->peer_key) { + priv->peer_key = msg->peer_key; + msg->peer_key = NULL; + } + priv->msg = NULL; + } + + return msg; +} + void rspamd_http_connection_free (struct rspamd_http_connection *conn) { @@ -940,17 +964,21 @@ rspamd_http_connection_free (struct rspamd_http_connection *conn) struct rspamd_http_keypair *peer_key; priv = conn->priv; - rspamd_http_connection_reset (conn); - if (priv->local_key) { - REF_RELEASE (priv->local_key); - } - if (priv->peer_key) { - peer_key = (struct rspamd_http_keypair *)priv->peer_key; - REF_RELEASE (peer_key); + if (priv != NULL) { + rspamd_http_connection_reset (conn); + + if (priv->local_key) { + REF_RELEASE (priv->local_key); + } + if (priv->peer_key) { + peer_key = (struct rspamd_http_keypair *)priv->peer_key; + REF_RELEASE (peer_key); + } + + g_slice_free1 (sizeof (struct rspamd_http_connection_private), priv); } - g_slice_free1 (sizeof (struct rspamd_http_connection_private), priv); g_slice_free1 (sizeof (struct rspamd_http_connection), conn); } @@ -976,10 +1004,11 @@ rspamd_http_connection_read_message (struct rspamd_http_connection *conn, if (timeout == NULL) { priv->ptv = NULL; } - else { + else if (&priv->tv != timeout) { memcpy (&priv->tv, timeout, sizeof (struct timeval)); priv->ptv = &priv->tv; } + priv->header = NULL; priv->buf = g_slice_alloc0 (sizeof (*priv->buf)); REF_INIT_RETAIN (priv->buf, rspamd_http_privbuf_dtor); @@ -1023,10 +1052,11 @@ rspamd_http_connection_write_message (struct rspamd_http_connection *conn, if (timeout == NULL) { priv->ptv = NULL; } - else { + else if (timeout != &priv->tv) { memcpy (&priv->tv, timeout, sizeof (struct timeval)); priv->ptv = &priv->tv; } + priv->header = NULL; priv->buf = g_slice_alloc0 (sizeof (*priv->buf)); REF_INIT_RETAIN (priv->buf, rspamd_http_privbuf_dtor); @@ -1196,7 +1226,10 @@ rspamd_http_connection_write_message (struct rspamd_http_connection *conn, priv->wr_total -= 2; } if (msg->body != NULL) { - msg->body_buf.str = msg->body->str; + + if (msg->body_buf.str == NULL) { + msg->body_buf.str = msg->body->str; + } if (encrypted && peer_key != NULL && np != NULL && mp != NULL) { if (conn->cache) { @@ -1362,7 +1395,7 @@ rspamd_http_message_find_header (struct rspamd_http_message *msg, LL_FOREACH (msg->headers, hdr) { if (hdr->name->len == slen) { - if (g_ascii_strncasecmp(hdr->name->str, name, slen) == 0) { + if (g_ascii_strncasecmp (hdr->name->str, name, slen) == 0) { res = hdr->value->str; break; } @@ -1373,6 +1406,30 @@ rspamd_http_message_find_header (struct rspamd_http_message *msg, return res; } +gboolean rspamd_http_message_remove_header (struct rspamd_http_message *msg, + const gchar *name) +{ + struct rspamd_http_header *hdr, *tmp; + gboolean res = FALSE; + guint slen = strlen (name); + + if (msg != NULL) { + DL_FOREACH_SAFE (msg->headers, hdr, tmp) { + if (hdr->name->len == slen) { + if (g_ascii_strncasecmp (hdr->name->str, name, slen) == 0) { + res = TRUE; + DL_DELETE (msg->headers, hdr); + g_string_free (hdr->name, TRUE); + g_string_free (hdr->value, TRUE); + g_slice_free1 (sizeof (*hdr), hdr); + } + } + } + } + + return res; +} + /* * HTTP router functions */ diff --git a/src/libutil/http.h b/src/libutil/http.h index 0c1515b47..41e3bb2bd 100644 --- a/src/libutil/http.h +++ b/src/libutil/http.h @@ -287,6 +287,14 @@ rspamd_http_connection_unref (struct rspamd_http_connection *conn) */ void rspamd_http_connection_reset (struct rspamd_http_connection *conn); +/** + * Extract the current message from a connection to deal with separately + * @param conn + * @return + */ +struct rspamd_http_message * rspamd_http_connection_steal_msg ( + struct rspamd_http_connection *conn); + /** * Create new HTTP message * @param type request or response @@ -307,21 +315,30 @@ struct rspamd_http_message* rspamd_http_message_from_url (const gchar *url); * @param name * @param value */ -void rspamd_http_message_add_header (struct rspamd_http_message *rep, +void rspamd_http_message_add_header (struct rspamd_http_message *msg, const gchar *name, const gchar *value); /** * Search for a specified header in message - * @param rep message + * @param msg message * @param name name of header */ -const gchar * rspamd_http_message_find_header (struct rspamd_http_message *rep, +const gchar * rspamd_http_message_find_header (struct rspamd_http_message *msg, const gchar *name); /** - * Free HTTP reply - * @param rep + * Remove specific header from a message + * @param msg + * @param name + * @return + */ +gboolean rspamd_http_message_remove_header (struct rspamd_http_message *msg, + const gchar *name); + +/** + * Free HTTP message + * @param msg */ void rspamd_http_message_free (struct rspamd_http_message *msg); -- 2.39.5