diff options
Diffstat (limited to 'src/libserver/milter.c')
-rw-r--r-- | src/libserver/milter.c | 116 |
1 files changed, 105 insertions, 11 deletions
diff --git a/src/libserver/milter.c b/src/libserver/milter.c index 9bb6ead39..79bcd80e5 100644 --- a/src/libserver/milter.c +++ b/src/libserver/milter.c @@ -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; |