]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
[Minor] Add basic milter commands support
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Fri, 28 Apr 2017 10:42:33 +0000 (11:42 +0100)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Fri, 28 Apr 2017 10:42:33 +0000 (11:42 +0100)
src/libserver/milter.c
src/libserver/milter_internal.h

index 9bb6ead39bcd8d5e07383e08cdc390d00435504c..79bcd80e512ea5f81540151533decea83d307145 100644 (file)
@@ -54,25 +54,71 @@ rspamd_milter_plan_io (struct rspamd_milter_session *session,
        event_add (&priv->ev, priv->ptv);
 }
 
+static void
+rspamd_milter_on_protocol_error (struct rspamd_milter_session *session,
+               struct rspamd_milter_private *priv, GError *err)
+{
+       REF_RETAIN (session);
+       priv->err_cb (priv->fd, session, priv->ud, err);
+       REF_RELEASE (session);
+       g_error_free (err);
+}
+
+static gboolean
+rspamd_milter_process_command (struct rspamd_milter_session *session,
+               struct rspamd_milter_private *priv)
+{
+       switch (priv->parser.cur_cmd) {
+       case RSPAMD_MILTER_CMD_ABORT:
+               break;
+       case RSPAMD_MILTER_CMD_BODY:
+               break;
+       case RSPAMD_MILTER_CMD_CONNECT:
+               break;
+       case RSPAMD_MILTER_CMD_MACRO:
+               break;
+       case RSPAMD_MILTER_CMD_BODYEOB:
+               break;
+       case RSPAMD_MILTER_CMD_HELO:
+               break;
+       case RSPAMD_MILTER_CMD_QUIT_NC:
+               break;
+       case RSPAMD_MILTER_CMD_HEADER:
+               break;
+       case RSPAMD_MILTER_CMD_MAIL:
+               break;
+       case RSPAMD_MILTER_CMD_EOH:
+               break;
+       case RSPAMD_MILTER_CMD_OPTNEG:
+               break;
+       case RSPAMD_MILTER_CMD_QUIT:
+               break;
+       case RSPAMD_MILTER_CMD_RCPT:
+               break;
+       case RSPAMD_MILTER_CMD_DATA:
+               break;
+       default:
+               break;
+       }
+
+       return TRUE;
+}
+
 static gboolean
 rspamd_milter_consume_input (struct rspamd_milter_session *session,
                struct rspamd_milter_private *priv)
 {
        const guchar *p, *end;
+       GError *err;
 
        p = priv->parser.buf->str + priv->parser.pos;
        end = priv->parser.buf->str + priv->parser.buf->len;
 
        while (p < end) {
                switch (priv->parser.state) {
-               case st_read_cmd:
-                       priv->parser.cur_cmd = *p;
-                       priv->parser.state = st_len_1;
-                       priv->parser.datalen = 0;
-                       p++;
-                       break;
                case st_len_1:
                        /* The first length byte in big endian order */
+                       priv->parser.datalen = 0;
                        priv->parser.datalen |= *p << 24;
                        priv->parser.state = st_len_2;
                        p++;
@@ -92,14 +138,62 @@ rspamd_milter_consume_input (struct rspamd_milter_session *session,
                case st_len_4:
                        /* The fourth length byte in big endian order */
                        priv->parser.datalen |= *p;
+                       priv->parser.state = st_read_cmd;
+                       p++;
+                       break;
+               case st_read_cmd:
+                       priv->parser.cur_cmd = *p;
                        priv->parser.state = st_read_data;
+
+                       if (priv->parser.datalen < 1) {
+                               err = g_error_new (rspamd_milter_quark (), EINVAL,
+                                       "Command length is too short");
+                               rspamd_milter_on_protocol_error (session, priv, err);
+
+                               return FALSE;
+                       }
+                       else {
+                               /* Eat command itself */
+                               priv->parser.datalen --;
+                       }
+
                        p++;
                        break;
                case st_read_data:
                        /* We might need some more data in buffer for further steps */
+                       if (priv->parser.buf->allocated < priv->parser.datalen) {
+                               priv->parser.buf = rspamd_fstring_grow (priv->parser.buf,
+                                               priv->parser.pos + priv->parser.datalen);
+                               /* This can realloc buffer */
+                               p = priv->parser.buf->str + priv->parser.pos;
+                               rspamd_milter_plan_io (session, priv, EV_READ);
+                               goto end;
+                       }
+                       else {
+                               /* We may have the full command available */
+                               if (p + priv->parser.datalen <= end) {
+                                       /* We need to process command */
+                                       if (!rspamd_milter_process_command (session, priv)) {
+                                               return FALSE;
+                                       }
+
+                                       p += priv->parser.datalen;
+                                       priv->parser.state = st_len_1;
+                                       priv->parser.cur_cmd = '\0';
+                               }
+                               else {
+                                       /* Need to read more */
+                                       rspamd_milter_plan_io (session, priv, EV_READ);
+                                       goto end;
+                               }
+                       }
                        break;
                }
        }
+end:
+
+       priv->parser.pos = p - (const guchar *)priv->parser.buf->str;
+       return TRUE;
 }
 
 static gboolean
@@ -113,13 +207,13 @@ rspamd_milter_handle_session (struct rspamd_milter_session *session,
 
        switch (priv->state) {
        case RSPAMD_MILTER_READ_MORE:
-               if (priv->parser.pos >= priv->parser.buf->allocated) {
+               if (priv->parser.buf->len >= priv->parser.buf->allocated) {
                        priv->parser.buf = rspamd_fstring_grow (priv->parser.buf,
-                                       priv->parser.pos * 2);
+                                       priv->parser.buf->len * 2);
                }
 
-               r = read (priv->fd, priv->parser.buf->str + priv->parser.pos,
-                               priv->parser.buf->allocated - priv->parser.pos);
+               r = read (priv->fd, priv->parser.buf->str + priv->parser.buf->len,
+                               priv->parser.buf->allocated - priv->parser.buf->len);
 
                if (r == -1) {
                        if (errno == EAGAIN || errno == EINTR) {
@@ -169,7 +263,7 @@ rspamd_milter_handle_socket (gint fd, const struct timeval *tv,
        priv->ud = ud;
        priv->fin_cb = finish_cb;
        priv->err_cb = error_cb;
-       priv->parser.state = st_read_cmd;
+       priv->parser.state = st_len_1;
        priv->parser.buf = rspamd_fstring_sized_new (100);
        priv->ev_base = ev_base;
        priv->state = RSPAMD_MILTER_READ_MORE;
index fed2e6f11399455f88f83084cace7aeb065e82f3..933044772ba88aae141fa3fe7fea6af5abd7ce8d 100644 (file)
 #include <event.h>
 
 enum rspamd_milter_state {
-       st_read_cmd,
-       st_len_1,
+       st_len_1 = 0,
        st_len_2,
        st_len_3,
        st_len_4,
+       st_read_cmd,
        st_read_data
 };
 
@@ -64,4 +64,22 @@ struct rspamd_milter_private {
        int fd;
 };
 
+enum rspamd_milter_io_cmd {
+       RSPAMD_MILTER_CMD_ABORT = 'A', /* Abort */
+       RSPAMD_MILTER_CMD_BODY = 'B', /* Body chunk */
+       RSPAMD_MILTER_CMD_CONNECT = 'C', /* Connection information */
+       RSPAMD_MILTER_CMD_MACRO = 'D', /* Define macro */
+       RSPAMD_MILTER_CMD_BODYEOB = 'E', /* final body chunk (end of message) */
+       RSPAMD_MILTER_CMD_HELO = 'H', /* HELO/EHLO */
+       RSPAMD_MILTER_CMD_QUIT_NC = 'K', /* QUIT but new connection follows */
+       RSPAMD_MILTER_CMD_HEADER = 'L', /* Header */
+       RSPAMD_MILTER_CMD_MAIL = 'M', /* MAIL from */
+       RSPAMD_MILTER_CMD_EOH = 'N', /* EOH */
+       RSPAMD_MILTER_CMD_OPTNEG = 'O', /* Option negotiation */
+       RSPAMD_MILTER_CMD_QUIT = 'Q', /* QUIT */
+       RSPAMD_MILTER_CMD_RCPT = 'R', /* RCPT to */
+       RSPAMD_MILTER_CMD_DATA = 'T', /* DATA */
+       RSPAMD_MILTER_CMD_UNKNOWN = 'U' /* Any unknown command */
+};
+
 #endif