summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/smtppass.c125
-rw-r--r--common/smtppass.h6
-rw-r--r--common/sppriv.h5
-rw-r--r--src/proxsmtpd.c10
4 files changed, 126 insertions, 20 deletions
diff --git a/common/smtppass.c b/common/smtppass.c
index 7fcafd0..0a85f4e 100644
--- a/common/smtppass.c
+++ b/common/smtppass.c
@@ -180,6 +180,9 @@ spthread_t;
#define CFG_USER "User"
#define CFG_PIDFILE "PidFile"
#define CFG_XCLIENT "XClient"
+#define CFG_SKIP "Skip"
+
+#define VAL_AUTHENTICATED "authenticated"
/* -----------------------------------------------------------------------
* DEFAULT SETTINGS
@@ -216,6 +219,7 @@ static int parse_config_file(const char* configfile);
static char* parse_address(char* line);
static char* parse_xforward(char* line, const char* part);
static const char* get_successful_rsp(const char* line, int* cont);
+static const char* get_continue_rsp(const char* line);
static void do_server_noop(spctx_t* ctx);
/* Used externally in some cases */
@@ -885,6 +889,37 @@ static int make_connections(spctx_t* ctx, int client)
* SMTP HANDLING
*/
+static int data_passthru(spctx_t* ctx)
+{
+ int r, count = 0;
+ const char* data;
+
+ while((r = sp_read_data(ctx, &data)) != 0)
+ {
+ if(r < 0)
+ return -1; /* Message already printed */
+
+ count += r;
+
+ if(spio_write_data_raw(ctx, &(ctx->server), (unsigned char*)data, r) == -1)
+ return -1;
+
+ }
+
+ sp_messagex(ctx, LOG_DEBUG, "skipped %d data bytes", count);
+ return count;
+}
+
+static int should_skip_processing(spctx_t* ctx)
+{
+ if(ctx->authenticated && (g_state.skip & SKIP_AUTHENTICATED))
+ {
+ sp_messagex(ctx, LOG_DEBUG, "skipping data processing because client is authenticated");
+ return 1;
+ }
+ return 0;
+}
+
static int smtp_passthru(spctx_t* ctx)
{
char* t;
@@ -896,6 +931,7 @@ static int smtp_passthru(spctx_t* ctx)
int first_rsp = 1; /* The first 220 response from server to be filtered */
int filter_host = 0; /* Next response is 250 hostname, which we change */
int auth_started = 0; /* Started performing authentication */
+ int data_mode = 0; /* Skip processing of data */
/* XCLIENT is for use in access control */
int xclient_sup = 0; /* Is XCLIENT supported? */
@@ -939,6 +975,9 @@ static int smtp_passthru(spctx_t* ctx)
/* Only valid after EHLO or HELO commands */
filter_host = 0;
+ /* Only valid after a DATA command (when should skip) */
+ data_mode = 0;
+
/*
* At this point we may want to send our XCLIENT. This is a per
* connection command.
@@ -962,26 +1001,30 @@ static int smtp_passthru(spctx_t* ctx)
/* Handle the DATA section via our AV checker */
if(is_first_word(C_LINE, DATA_CMD, KL(DATA_CMD)))
{
- /* Send back the intermediate response to the client */
- if(spio_write_data(ctx, &(ctx->client), SMTP_DATAINTERMED) == -1)
- RETURN(-1);
+ if(should_skip_processing (ctx))
+ {
+ data_mode = 1;
+ }
+ else
+ {
+ /*
+ * Now go into scan mode. This also handles the eventual
+ * sending of the data to the server, making the av check
+ * transparent
+ */
- /*
- * Now go into scan mode. This also handles the eventual
- * sending of the data to the server, making the av check
- * transparent
- */
- if(cb_check_data(ctx) == -1)
- RETURN(-1);
+ if(cb_check_data(ctx) == -1)
+ RETURN(-1);
- /* Print the log out for this email */
- sp_messagex(ctx, LOG_INFO, "%s", ctx->logline);
+ /* Print the log out for this email */
+ sp_messagex(ctx, LOG_INFO, "%s", ctx->logline);
- /* Done with that email */
- cleanup_context(ctx);
+ /* Done with that email */
+ cleanup_context(ctx);
- /* Command handled */
- continue;
+ /* Command handled */
+ continue;
+ }
}
/*
@@ -1043,7 +1086,6 @@ static int smtp_passthru(spctx_t* ctx)
else if(is_first_word(C_LINE, AUTH_CMD, KL(AUTH_CMD)))
{
- sp_messagex(ctx, LOG_DEBUG, "Tracking authentication");
auth_started = 1;
}
@@ -1094,6 +1136,16 @@ static int smtp_passthru(spctx_t* ctx)
}
}
+ /*
+ * If we're preparing for data mode, and didn't get a satisfactory
+ * repsonse from server then cancel it.
+ */
+ if(data_mode && !get_continue_rsp(S_LINE))
+ {
+ sp_messagex(ctx, LOG_DEBUG, "server did not accept data");
+ data_mode = 0;
+ }
+
if((p = get_successful_rsp(S_LINE, &cont)) != NULL)
{
/*
@@ -1236,9 +1288,18 @@ static int smtp_passthru(spctx_t* ctx)
}
}
+ /* Send the line to the client */
if(spio_write_data(ctx, &(ctx->client), S_LINE) == -1)
RETURN(-1);
+ /* Should we enter data passthru mode? */
+ if(data_mode)
+ {
+ data_mode = 0;
+ if(data_passthru(ctx) < 0)
+ RETURN(-1);
+ }
+
continue;
}
}
@@ -1315,6 +1376,20 @@ static char* parse_xforward(char* line, const char* part)
return t;
}
+static const char* get_continue_rsp(const char* line)
+{
+ /*
+ * We check for '3XX xxx' type replies
+ */
+
+ line = trim_start(line);
+
+ if(line[0] == '3' && isdigit(line[1]) && isdigit(line[2]) && line[3] == ' ')
+ return line + 4;
+
+ return NULL;
+}
+
static const char* get_successful_rsp(const char* line, int* cont)
{
/*
@@ -1368,6 +1443,12 @@ void sp_add_log(spctx_t* ctx, char* prefix, char* line)
trim_end(t);
}
+int sp_start_data(spctx_t* ctx)
+{
+ /* Send back the intermediate response to the client */
+ return spio_write_data(ctx, &(ctx->client), SMTP_DATAINTERMED);
+}
+
int sp_read_data(spctx_t* ctx, const char** data)
{
int r;
@@ -2095,6 +2176,16 @@ int sp_parse_option(const char* name, const char* value)
ret = 1;
}
+ else if(strcasecmp(CFG_SKIP, name) == 0)
+ {
+ if(strcasecmp(value, VAL_AUTHENTICATED) == 0)
+ g_state.skip |= SKIP_AUTHENTICATED;
+ else
+ errx(2, "invalid value for " CFG_SKIP
+ " (must specify '" VAL_AUTHENTICATED "')");
+ return 1;
+ }
+
/* Always pass through to program */
if(cb_parse_option(name, value) == 1)
ret = 1;
diff --git a/common/smtppass.h b/common/smtppass.h
index 0fbe458..7f1892e 100644
--- a/common/smtppass.h
+++ b/common/smtppass.h
@@ -191,6 +191,12 @@ int sp_parse_option(const char* name, const char* option);
void sp_add_log(spctx_t* ctx, char* prefix, char* line);
/*
+ * Tells client to start sending data. Sends appropriate
+ * response code.
+ */
+int sp_start_data(spctx_t* ctx);
+
+/*
* Reads a line of DATA from client. Or less than a line if
* line is longer than LINE_LENGTH. No trimming or anything
* is done on the read line. This will end automatically
diff --git a/common/sppriv.h b/common/sppriv.h
index 777025f..883097d 100644
--- a/common/sppriv.h
+++ b/common/sppriv.h
@@ -41,6 +41,10 @@
#include "smtppass.h"
+enum {
+ SKIP_AUTHENTICATED = 0x01,
+};
+
typedef struct spstate
{
/* Settings ------------------------------- */
@@ -54,6 +58,7 @@ typedef struct spstate
const char* user; /* User to run as */
const char* pidfile; /* The pid file for daemon */
const char* header; /* A header to include in the email */
+ int skip; /* Various types of email to skip processing */
struct sockaddr_any outaddr; /* The outgoing address */
const char* outname;
diff --git a/src/proxsmtpd.c b/src/proxsmtpd.c
index 407bcaf..9402641 100644
--- a/src/proxsmtpd.c
+++ b/src/proxsmtpd.c
@@ -229,12 +229,16 @@ int cb_check_data(spctx_t* ctx)
if(g_pxstate.filter_type == FILTER_REJECT)
{
- if(sp_cache_data(ctx) < 0 ||
- sp_fail_data(ctx, g_pxstate.reject) < 0)
+ if(sp_fail_data(ctx, g_pxstate.reject) < 0)
return -1; /* Message already printed */
return 0;
}
- else if(!g_pxstate.command)
+
+ /* Tell client to start sending data */
+ if(sp_start_data (ctx) < 0)
+ return -1; /* Message already printed */
+
+ if(!g_pxstate.command)
{
sp_messagex(ctx, LOG_WARNING, "no filter command specified. passing message through");