revised bdat support

Signed-off-by: Janos SUTO <sj@acts.hu>
This commit is contained in:
Janos SUTO 2018-05-13 14:26:21 +02:00
parent 41777063f0
commit 97830bc265
5 changed files with 34 additions and 45 deletions

View File

@ -21,8 +21,6 @@
void reset_bdat_counters(struct smtp_session *session){ void reset_bdat_counters(struct smtp_session *session){
session->bdat_rounds = 0;
session->bdat_last_round = 0;
session->bdat_bytes_to_read = 0; session->bdat_bytes_to_read = 0;
session->bad = 0; session->bad = 0;
} }
@ -31,17 +29,12 @@ void reset_bdat_counters(struct smtp_session *session){
void get_bdat_size_to_read(struct smtp_session *session, char *buf){ void get_bdat_size_to_read(struct smtp_session *session, char *buf){
char *p; char *p;
session->bdat_rounds++;
session->bdat_bytes_to_read = 0; session->bdat_bytes_to_read = 0;
session->protocol_state = SMTP_STATE_BDAT; session->protocol_state = SMTP_STATE_BDAT;
// determine if this is the last BDAT command
p = strcasestr(buf, " LAST"); p = strcasestr(buf, " LAST");
if(p){ if(p){
session->bdat_last_round = 1;
syslog(LOG_INFO, "%s: BDAT LAST", session->ttmpfile);
*p = '\0'; *p = '\0';
} }
@ -61,12 +54,11 @@ void get_bdat_size_to_read(struct smtp_session *session, char *buf){
void process_bdat(struct smtp_session *session, char *readbuf, int readlen, struct config *cfg){ void process_bdat(struct smtp_session *session, char *readbuf, int readlen, struct config *cfg){
int i;
char buf[SMALLBUFSIZE]; char buf[SMALLBUFSIZE];
if(readlen <= 0) return; if(readlen <= 0) return;
if(session->bdat_rounds == 1 && session->fd == -1){ if(session->fd == -1){
session->fd = open(session->ttmpfile, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR|S_IRGRP); session->fd = open(session->ttmpfile, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR|S_IRGRP);
if(session->fd == -1){ if(session->fd == -1){
syslog(LOG_PRIORITY, "%s: %s", ERR_OPEN_TMP_FILE, session->ttmpfile); syslog(LOG_PRIORITY, "%s: %s", ERR_OPEN_TMP_FILE, session->ttmpfile);
@ -81,7 +73,7 @@ void process_bdat(struct smtp_session *session, char *readbuf, int readlen, stru
if(write(session->fd, readbuf, readlen) != -1){ if(write(session->fd, readbuf, readlen) != -1){
session->tot_len += readlen; session->tot_len += readlen;
if(session->cfg->verbosity >= _LOG_DEBUG) syslog(LOG_INFO, "%s: wrote %d bytes, %d bytes to go", session->ttmpfile, readlen, session->bdat_bytes_to_read); if(session->cfg->verbosity >= _LOG_EXTREME) syslog(LOG_INFO, "%s: wrote %d bytes, %d bytes to go", session->ttmpfile, readlen, session->bdat_bytes_to_read);
} }
else syslog(LOG_PRIORITY, "ERROR: write(), %s, %d, %s", __func__, __LINE__, __FILE__); else syslog(LOG_PRIORITY, "ERROR: write(), %s, %d, %s", __func__, __LINE__, __FILE__);
} }
@ -94,45 +86,36 @@ void process_bdat(struct smtp_session *session, char *readbuf, int readlen, stru
close(session->fd); close(session->fd);
unlink(session->ttmpfile); unlink(session->ttmpfile);
session->fd = 1;
} }
if(session->bdat_bytes_to_read == 0){
if(session->bdat_last_round == 1){ // If there's nothing more to read, then send response to smtp client
if(session->cfg->verbosity >= _LOG_DEBUG) syslog(LOG_INFO, "%s: read all bdat data in %d rounds", session->ttmpfile, session->bdat_rounds);
// send back the smtp answers if(session->bdat_bytes_to_read <= 0){
for(i=0; i<session->bdat_rounds; i++){
if(session->fd == -1){
send_smtp_response(session, SMTP_RESP_421_ERR_WRITE_FAILED);
}
else {
if(i == 0){
fsync(session->fd);
close(session->fd);
move_email(session); if(session->fd == -1){
close(session->fd);
session->fd = -1;
snprintf(buf, sizeof(buf)-1, "250 OK <%s>\r\n", session->ttmpfile); send_smtp_response(session, SMTP_RESP_421_ERR_WRITE_FAILED);
send_smtp_response(session, buf); }
syslog(LOG_PRIORITY, "received: %s, from=%s, size=%d, client=%s", session->ttmpfile, session->mailfrom, session->tot_len, session->remote_host); else {
} fsync(session->fd);
else send_smtp_response(session, SMTP_RESP_250_BDAT); close(session->fd);
}
}
// technically we are not in the PERIOD state, but it's good enough
// to quit the BDAT processing state
session->protocol_state = SMTP_STATE_PERIOD;
session->fd = -1; session->fd = -1;
move_email(session);
snprintf(buf, sizeof(buf)-1, "250 OK <%s>\r\n", session->ttmpfile);
send_smtp_response(session, buf);
syslog(LOG_PRIORITY, "received: %s, from=%s, size=%d, client=%s", session->ttmpfile, session->mailfrom, session->tot_len, session->remote_host);
} }
else { // technically we are not in the PERIOD state, but it's good enough
// this is not the last BDAT round, let's go back // to quit the BDAT processing state
// after the rcpt state, and wait for the next session->protocol_state = SMTP_STATE_PERIOD;
// BDAT command
session->protocol_state = SMTP_STATE_RCPT_TO;
}
} }
} }

View File

@ -11,7 +11,7 @@
#define VERSION "1.3.5-pre1" #define VERSION "1.3.5-pre1"
#define BUILD 995 #define BUILD 996
#define HOSTID "mailarchiver" #define HOSTID "mailarchiver"

View File

@ -393,8 +393,6 @@ struct smtp_session {
int buflen; int buflen;
int last_data_char; int last_data_char;
int tot_len; int tot_len;
int bdat_rounds;
int bdat_last_round;
int bdat_bytes_to_read; int bdat_bytes_to_read;
int num_of_rcpt_to; int num_of_rcpt_to;
struct config *cfg; struct config *cfg;

View File

@ -163,6 +163,13 @@ void tear_down_session(struct smtp_session **sessions, int slot, int *num_connec
close(sessions[slot]->net.socket); close(sessions[slot]->net.socket);
if(sessions[slot]->fd != -1){
syslog(LOG_PRIORITY, "Removing %s", sessions[slot]->ttmpfile);
close(sessions[slot]->fd);
unlink(sessions[slot]->ttmpfile);
sessions[slot]->fd = -1;
}
free_smtp_session(sessions[slot]); free_smtp_session(sessions[slot]);
sessions[slot] = NULL; sessions[slot] = NULL;

View File

@ -18,7 +18,7 @@
void process_smtp_command(struct smtp_session *session, char *buf, struct config *cfg){ void process_smtp_command(struct smtp_session *session, char *buf, struct config *cfg){
char response[SMALLBUFSIZE]; char response[SMALLBUFSIZE];
if(session->cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "processing command: *%s*", buf); if(session->cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "(fd: %d) processing command: *%s*", session->net.socket, buf);
if(strncasecmp(buf, SMTP_CMD_HELO, strlen(SMTP_CMD_HELO)) == 0){ if(strncasecmp(buf, SMTP_CMD_HELO, strlen(SMTP_CMD_HELO)) == 0){
process_command_helo(session, response, sizeof(response)); process_command_helo(session, response, sizeof(response));
@ -46,7 +46,8 @@ void process_smtp_command(struct smtp_session *session, char *buf, struct config
return; return;
} }
if(session->cfg->enable_chunking == 1 && strncasecmp(buf, SMTP_CMD_BDAT, strlen(SMTP_CMD_BDAT)) == 0){ /* Support only BDAT xxxx LAST command */
if(session->cfg->enable_chunking == 1 && strncasecmp(buf, SMTP_CMD_BDAT, strlen(SMTP_CMD_BDAT)) == 0 && strncasecmp(buf, "LAST", strlen(SMTP_CMD_BDAT)) == 0){
get_bdat_size_to_read(session, buf); get_bdat_size_to_read(session, buf);
return; return;
} }