summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS5
-rw-r--r--ChangeLog4
-rw-r--r--common/smtppass.c68
-rw-r--r--common/stringx.c26
-rw-r--r--common/stringx.h4
-rw-r--r--configure.in4
-rw-r--r--src/clamsmtpd.c68
-rw-r--r--src/util.c26
-rw-r--r--src/util.h4
9 files changed, 177 insertions, 32 deletions
diff --git a/AUTHORS b/AUTHORS
index 6c1bf4c..82374c0 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -2,7 +2,8 @@ AUTHOR:
Nate Nielsen <nielsen@memberwebs.com>
PATCHES:
-Yamamoto Takao <takao@oakat.org>
-João Carlos Mendes Luís <jcmendes@int.gov.br>
Berk D. Demir <demir@meteksan.net.tr>
+João Carlos Mendes Luís <jcmendes@int.gov.br>
Jasper Slits <jasper@insiders.nl>
+Andreas Steinmetz <ast@domdv.de>
+Yamamoto Takao <takao@oakat.org>
diff --git a/ChangeLog b/ChangeLog
index cbbebf1..7c49094 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+0.7
+ - Added support for ESMTP [Andreas Steinmetz]
+ - Fixed other bugs
+
0.6
- Proper adding of customized header [Berk D. Demir]
- Fixes to documentation [Jasper Slits]
diff --git a/common/smtppass.c b/common/smtppass.c
index b682e83..0a20777 100644
--- a/common/smtppass.c
+++ b/common/smtppass.c
@@ -91,7 +91,13 @@ clamsmtp_thread_t;
#define SMTP_DATA "DATA" CRLF
#define SMTP_BANNER "220 clamsmtp" CRLF
-#define SMTP_DELIMS "\r\n\t :"
+#define SMTP_DELIMS "\r\n\t :-"
+
+#define ESMTP_PIPELINE "PIPELINING"
+#define ESMTP_TLS "STARTTLS"
+#define ESMTP_CHUNK "CHUNKING"
+#define ESMTP_BINARY "BINARYMIME"
+#define ESMTP_CHECK "CHECKPOINT"
#define HELO_CMD "HELO"
#define EHLO_CMD "EHLO"
@@ -99,6 +105,8 @@ clamsmtp_thread_t;
#define TO_CMD "RCPT TO"
#define DATA_CMD "DATA"
#define RSET_CMD "RSET"
+#define STARTTLS_CMD "STARTTLS"
+#define BDAT_CMD "BDAT"
#define DATA_END_SIG CRLF "." CRLF
@@ -668,6 +676,7 @@ static int smtp_passthru(clamsmtp_context_t* ctx)
char logline[LINE_LENGTH];
int r, ret = 0;
int first_rsp = 1;
+ int filter_ehlo = 0;
fd_set mask;
int neterror = 0;
@@ -738,13 +747,24 @@ static int smtp_passthru(clamsmtp_context_t* ctx)
}
/*
- * We don't support EHLO (ESMTP) because pipelining
- * and other nuances aren't implemented here. In order
- * to keep things reliable we just disable it all.
+ * We filter out features that we can't support in
+ * the EHLO response (ESMTP). See below
*/
else if(is_first_word(ctx->line, EHLO_CMD, KL(EHLO_CMD)))
{
- messagex(ctx, LOG_DEBUG, "ESMTP not implemented");
+ messagex(ctx, LOG_DEBUG, "filtering EHLO response");
+ filter_ehlo = 1;
+ }
+
+ /*
+ * We don't like these commands. Filter them out. We should have
+ * filtered out their service extensions earlier in the EHLO response.
+ * This is just for errant clients.
+ */
+ else if(is_first_word(ctx->line, STARTTLS_CMD, KL(STARTTLS_CMD)) ||
+ is_first_word(ctx->line, BDAT_CMD, KL(BDAT_CMD)))
+ {
+ messagex(ctx, LOG_DEBUG, "ESMTP feature not supported");
if(write_data(ctx, &(ctx->client), SMTP_NOTSUPP) == -1)
RETURN(-1);
@@ -812,6 +832,32 @@ static int smtp_passthru(clamsmtp_context_t* ctx)
}
}
+ /*
+ * Filter out any EHLO responses that we can't or don't want
+ * to support. For example pipelining or TLS.
+ */
+ if(filter_ehlo)
+ {
+ if((r = check_first_word(ctx->line, OK_RSP, KL(OK_RSP), SMTP_DELIMS)) > 0)
+ {
+ char* p = ctx->line + r;
+ if(is_first_word(p, ESMTP_PIPELINE, KL(ESMTP_PIPELINE)) ||
+ is_first_word(p, ESMTP_TLS, KL(ESMTP_TLS)) ||
+ is_first_word(p, ESMTP_CHUNK, KL(ESMTP_CHUNK)) ||
+ is_first_word(p, ESMTP_BINARY, KL(ESMTP_BINARY)) ||
+ is_first_word(p, ESMTP_CHECK, KL(ESMTP_CHECK)))
+ {
+ messagex(ctx, LOG_DEBUG, "filtered ESMTP feature: %s", p);
+ continue;
+ }
+ }
+ else
+ {
+ filter_ehlo = 0;
+ messagex(ctx, LOG_DEBUG, "done filtering ESMTP response");
+ }
+ }
+
if(write_data(ctx, &(ctx->client), ctx->line) == -1)
RETURN(-1);
@@ -844,15 +890,12 @@ static void add_to_logline(char* logline, char* prefix, char* line)
strlcat(logline, prefix, l);
/* Skip initial white space */
- while(*line && isspace(*line))
- *line++;
+ line = trim_start(line);
strlcat(logline, line, l);
- t = logline + strlen(logline);
/* Skip later white space */
- while(t > logline && isspace(*(t - 1)))
- *(--t) = 0;
+ trim_end(logline);
}
static int avcheck_data(clamsmtp_context_t* ctx, char* logline)
@@ -1380,10 +1423,7 @@ static void read_junk(clamsmtp_context_t* ctx, int fd)
break;
buf[l] = 0;
- t = buf;
-
- while(*t && isspace(*t))
- t++;
+ t = trim_start(buf);
if(!said && *t)
{
diff --git a/common/stringx.c b/common/stringx.c
index f4d9910..a2bc90d 100644
--- a/common/stringx.c
+++ b/common/stringx.c
@@ -261,6 +261,32 @@ int is_blank_line(const char* line)
return *line == 0;
}
+char* trim_start(const char* data)
+{
+ while(*data && isspace(*data))
+ ++data;
+ return (char*)data;
+}
+
+char* trim_end(char* data)
+{
+ char* t = data + strlen(data);
+
+ while(t > data && isspace(*(t - 1)))
+ {
+ t--;
+ *t = 0;
+ }
+
+ return data;
+}
+
+char* trim_space(char* data)
+{
+ data = (char*)trim_start(data);
+ return trim_end(data);
+}
+
/* -----------------------------------------------------------------------
* Locking
*/
diff --git a/common/stringx.h b/common/stringx.h
index 8a39c7e..8e6f2f4 100644
--- a/common/stringx.h
+++ b/common/stringx.h
@@ -50,6 +50,10 @@ int is_first_word(const char* line, const char* word, int len);
int is_last_word(const char* line, const char* word, int len);
int is_blank_line(const char* line);
+char* trim_start(const char* data);
+char* trim_end(char* data);
+char* trim_space(char* data);
+
void plock();
void punlock();
diff --git a/configure.in b/configure.in
index 770ff3b..6582543 100644
--- a/configure.in
+++ b/configure.in
@@ -36,8 +36,8 @@ dnl Nate Nielsen <nielsen@memberwebs.com>
dnl
dnl Process this file with autoconf to produce a configure script.
-AC_INIT(clamsmtp, 0.6, nielsen@memberwebs.com)
-AM_INIT_AUTOMAKE(clamsmtp, 0.6)
+AC_INIT(clamsmtp, 0.7.rc1, nielsen@memberwebs.com)
+AM_INIT_AUTOMAKE(clamsmtp, 0.7.rc1)
LDFLAGS="$LDFLAGS -L/usr/local/lib"
CFLAGS="$CFLAGS -I/usr/local/include"
diff --git a/src/clamsmtpd.c b/src/clamsmtpd.c
index b682e83..0a20777 100644
--- a/src/clamsmtpd.c
+++ b/src/clamsmtpd.c
@@ -91,7 +91,13 @@ clamsmtp_thread_t;
#define SMTP_DATA "DATA" CRLF
#define SMTP_BANNER "220 clamsmtp" CRLF
-#define SMTP_DELIMS "\r\n\t :"
+#define SMTP_DELIMS "\r\n\t :-"
+
+#define ESMTP_PIPELINE "PIPELINING"
+#define ESMTP_TLS "STARTTLS"
+#define ESMTP_CHUNK "CHUNKING"
+#define ESMTP_BINARY "BINARYMIME"
+#define ESMTP_CHECK "CHECKPOINT"
#define HELO_CMD "HELO"
#define EHLO_CMD "EHLO"
@@ -99,6 +105,8 @@ clamsmtp_thread_t;
#define TO_CMD "RCPT TO"
#define DATA_CMD "DATA"
#define RSET_CMD "RSET"
+#define STARTTLS_CMD "STARTTLS"
+#define BDAT_CMD "BDAT"
#define DATA_END_SIG CRLF "." CRLF
@@ -668,6 +676,7 @@ static int smtp_passthru(clamsmtp_context_t* ctx)
char logline[LINE_LENGTH];
int r, ret = 0;
int first_rsp = 1;
+ int filter_ehlo = 0;
fd_set mask;
int neterror = 0;
@@ -738,13 +747,24 @@ static int smtp_passthru(clamsmtp_context_t* ctx)
}
/*
- * We don't support EHLO (ESMTP) because pipelining
- * and other nuances aren't implemented here. In order
- * to keep things reliable we just disable it all.
+ * We filter out features that we can't support in
+ * the EHLO response (ESMTP). See below
*/
else if(is_first_word(ctx->line, EHLO_CMD, KL(EHLO_CMD)))
{
- messagex(ctx, LOG_DEBUG, "ESMTP not implemented");
+ messagex(ctx, LOG_DEBUG, "filtering EHLO response");
+ filter_ehlo = 1;
+ }
+
+ /*
+ * We don't like these commands. Filter them out. We should have
+ * filtered out their service extensions earlier in the EHLO response.
+ * This is just for errant clients.
+ */
+ else if(is_first_word(ctx->line, STARTTLS_CMD, KL(STARTTLS_CMD)) ||
+ is_first_word(ctx->line, BDAT_CMD, KL(BDAT_CMD)))
+ {
+ messagex(ctx, LOG_DEBUG, "ESMTP feature not supported");
if(write_data(ctx, &(ctx->client), SMTP_NOTSUPP) == -1)
RETURN(-1);
@@ -812,6 +832,32 @@ static int smtp_passthru(clamsmtp_context_t* ctx)
}
}
+ /*
+ * Filter out any EHLO responses that we can't or don't want
+ * to support. For example pipelining or TLS.
+ */
+ if(filter_ehlo)
+ {
+ if((r = check_first_word(ctx->line, OK_RSP, KL(OK_RSP), SMTP_DELIMS)) > 0)
+ {
+ char* p = ctx->line + r;
+ if(is_first_word(p, ESMTP_PIPELINE, KL(ESMTP_PIPELINE)) ||
+ is_first_word(p, ESMTP_TLS, KL(ESMTP_TLS)) ||
+ is_first_word(p, ESMTP_CHUNK, KL(ESMTP_CHUNK)) ||
+ is_first_word(p, ESMTP_BINARY, KL(ESMTP_BINARY)) ||
+ is_first_word(p, ESMTP_CHECK, KL(ESMTP_CHECK)))
+ {
+ messagex(ctx, LOG_DEBUG, "filtered ESMTP feature: %s", p);
+ continue;
+ }
+ }
+ else
+ {
+ filter_ehlo = 0;
+ messagex(ctx, LOG_DEBUG, "done filtering ESMTP response");
+ }
+ }
+
if(write_data(ctx, &(ctx->client), ctx->line) == -1)
RETURN(-1);
@@ -844,15 +890,12 @@ static void add_to_logline(char* logline, char* prefix, char* line)
strlcat(logline, prefix, l);
/* Skip initial white space */
- while(*line && isspace(*line))
- *line++;
+ line = trim_start(line);
strlcat(logline, line, l);
- t = logline + strlen(logline);
/* Skip later white space */
- while(t > logline && isspace(*(t - 1)))
- *(--t) = 0;
+ trim_end(logline);
}
static int avcheck_data(clamsmtp_context_t* ctx, char* logline)
@@ -1380,10 +1423,7 @@ static void read_junk(clamsmtp_context_t* ctx, int fd)
break;
buf[l] = 0;
- t = buf;
-
- while(*t && isspace(*t))
- t++;
+ t = trim_start(buf);
if(!said && *t)
{
diff --git a/src/util.c b/src/util.c
index f4d9910..a2bc90d 100644
--- a/src/util.c
+++ b/src/util.c
@@ -261,6 +261,32 @@ int is_blank_line(const char* line)
return *line == 0;
}
+char* trim_start(const char* data)
+{
+ while(*data && isspace(*data))
+ ++data;
+ return (char*)data;
+}
+
+char* trim_end(char* data)
+{
+ char* t = data + strlen(data);
+
+ while(t > data && isspace(*(t - 1)))
+ {
+ t--;
+ *t = 0;
+ }
+
+ return data;
+}
+
+char* trim_space(char* data)
+{
+ data = (char*)trim_start(data);
+ return trim_end(data);
+}
+
/* -----------------------------------------------------------------------
* Locking
*/
diff --git a/src/util.h b/src/util.h
index 8a39c7e..8e6f2f4 100644
--- a/src/util.h
+++ b/src/util.h
@@ -50,6 +50,10 @@ int is_first_word(const char* line, const char* word, int len);
int is_last_word(const char* line, const char* word, int len);
int is_blank_line(const char* line);
+char* trim_start(const char* data);
+char* trim_end(char* data);
+char* trim_space(char* data);
+
void plock();
void punlock();