From 1ae11397188d9827996ac8e8db0a15b387196437 Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Wed, 25 Aug 2004 22:49:31 +0000 Subject: Added support for ESMTP --- AUTHORS | 5 ++-- ChangeLog | 4 ++++ common/smtppass.c | 68 +++++++++++++++++++++++++++++++++++++++++++------------ common/stringx.c | 26 +++++++++++++++++++++ common/stringx.h | 4 ++++ configure.in | 4 ++-- src/clamsmtpd.c | 68 +++++++++++++++++++++++++++++++++++++++++++------------ src/util.c | 26 +++++++++++++++++++++ src/util.h | 4 ++++ 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 PATCHES: -Yamamoto Takao -João Carlos Mendes Luís Berk D. Demir +João Carlos Mendes Luís Jasper Slits +Andreas Steinmetz +Yamamoto Takao 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 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(); -- cgit v1.2.3