revised smtp protocol handling

Signed-off-by: Janos SUTO <sj@acts.hu>
This commit is contained in:
Janos SUTO 2018-03-02 22:46:48 +01:00
parent 52d44ddee1
commit e18ec3a701
8 changed files with 86 additions and 187 deletions

View File

@ -9,9 +9,9 @@
#include "piler-config.h" #include "piler-config.h"
#include "params.h" #include "params.h"
#define VERSION "1.3.3" #define VERSION "1.3.4"
#define BUILD 990 #define BUILD 991
#define HOSTID "mailarchiver" #define HOSTID "mailarchiver"

View File

@ -383,7 +383,7 @@ struct smtp_session {
char ttmpfile[SMALLBUFSIZE]; char ttmpfile[SMALLBUFSIZE];
char mailfrom[SMALLBUFSIZE]; char mailfrom[SMALLBUFSIZE];
char rcptto[MAX_RCPT_TO][SMALLBUFSIZE]; char rcptto[MAX_RCPT_TO][SMALLBUFSIZE];
char buf[SMALLBUFSIZE]; char buf[MAXBUFSIZE];
char remote_host[INET6_ADDRSTRLEN]; char remote_host[INET6_ADDRSTRLEN];
time_t lasttime; time_t lasttime;
int protocol_state; int protocol_state;

View File

@ -84,44 +84,6 @@ long tvdiff(struct timeval a, struct timeval b){
} }
/*
* search something in a buffer
*/
int searchStringInBuffer(char *s, int len1, char *what, int len2){
int i, k, r;
for(i=0; i<len1; i++){
r = 0;
for(k=0; k<len2; k++){
if(*(s+i+k) == *(what+k))
r++;
}
if(r == len2)
return i;
}
return -1;
}
int search_char_backward(char *buf, int buflen, char c){
int n, m;
m = buflen - 1 - 5;
if(m < 0) m = 0;
for(n=m; n<buflen; n++){
if(*(buf + n) == c){
return n;
}
}
return -1;
}
/* /*
* count a character in buffer * count a character in buffer
*/ */
@ -739,6 +701,34 @@ void move_email(struct smtp_session *session){
} }
int read_one_line(char *s, int c, char *buf, int buflen, int *rc){
int i=0;
*rc = ERR;
memset(buf, 0, buflen);
if(s == NULL){
return i;
}
for(; *s; s++){
if(i<buflen-2){
buf[i] = *s;
i++;
if(*s == c){
*rc = OK;
break;
}
}
else break;
}
return i;
}
#ifndef _GNU_SOURCE #ifndef _GNU_SOURCE
char *strcasestr(const char *s, const char *find){ char *strcasestr(const char *s, const char *find){
char c, sc; char c, sc;

View File

@ -19,8 +19,6 @@ int get_build();
void get_extractor_list(); void get_extractor_list();
void __fatal(char *s); void __fatal(char *s);
long tvdiff(struct timeval a, struct timeval b); long tvdiff(struct timeval a, struct timeval b);
int searchStringInBuffer(char *s, int len1, char *what, int len2);
int search_char_backward(char *buf, int buflen, char c);
int countCharacterInBuffer(char *p, char c); int countCharacterInBuffer(char *p, char c);
void replaceCharacterInBuffer(char *p, char from, char to); void replaceCharacterInBuffer(char *p, char from, char to);
char *split(char *str, int ch, char *buf, int buflen, int *result); char *split(char *str, int ch, char *buf, int buflen, int *result);
@ -51,6 +49,7 @@ int create_and_bind(char *listen_addr, int listen_port);
int can_i_write_directory(char *dir); int can_i_write_directory(char *dir);
void move_email(struct smtp_session *session); void move_email(struct smtp_session *session);
int read_one_line(char *s, int c, char *buf, int buflen, int *rc);
#ifndef _GNU_SOURCE #ifndef _GNU_SOURCE
char *strcasestr(const char *s, const char *find); char *strcasestr(const char *s, const char *find);

View File

@ -126,7 +126,7 @@ void init_smtp_session(struct smtp_session *session, int slot, int sd, struct co
session->num_of_rcpt_to = 0; session->num_of_rcpt_to = 0;
for(i=0; i<MAX_RCPT_TO; i++) memset(session->rcptto[i], 0, SMALLBUFSIZE); for(i=0; i<MAX_RCPT_TO; i++) memset(session->rcptto[i], 0, SMALLBUFSIZE);
memset(session->buf, 0, SMALLBUFSIZE); memset(session->buf, 0, MAXBUFSIZE);
memset(session->remote_host, 0, INET6_ADDRSTRLEN); memset(session->remote_host, 0, INET6_ADDRSTRLEN);
reset_bdat_counters(session); reset_bdat_counters(session);
@ -169,64 +169,64 @@ void tear_down_session(struct smtp_session **sessions, int slot, int *num_connec
void handle_data(struct smtp_session *session, char *readbuf, int readlen, struct config *cfg){ void handle_data(struct smtp_session *session, char *readbuf, int readlen, struct config *cfg){
char *p, puf[MAXBUFSIZE]; int puflen, rc, lines=0;
int result; char *p, copybuf[BIGBUFSIZE+MAXBUFSIZE], puf[MAXBUFSIZE];
// process BDAT stuff // if there's something in the saved buffer, then let's merge them
if(session->protocol_state == SMTP_STATE_BDAT){ if(session->buflen > 0){
if(session->bad == 1){ memset(copybuf, 0, sizeof(copybuf));
// something bad happened in the BDAT processing
return;
}
process_bdat(session, readbuf, readlen, cfg); memcpy(copybuf, session->buf, session->buflen);
memcpy(&copybuf[session->buflen], readbuf, readlen);
session->buflen = 0;
memset(session->buf, 0, MAXBUFSIZE);
p = &copybuf[0];
} }
// process DATA
else if(session->protocol_state == SMTP_STATE_DATA){
process_data(session, readbuf, readlen);
}
// process other SMTP commands
else { else {
if(session->buflen > 0){
snprintf(puf, sizeof(puf)-1, "%s%s", session->buf, readbuf);
snprintf(readbuf, BIGBUFSIZE-1, "%s", puf);
session->buflen = 0;
memset(session->buf, 0, SMALLBUFSIZE);
}
p = readbuf; p = readbuf;
}
do {
memset(puf, 0, sizeof(puf));
p = split(p, '\n', puf, sizeof(puf)-1, &result);
if(puf[0] == '\0') continue; do {
puflen = read_one_line(p, '\n', puf, sizeof(puf)-1, &rc);
p += puflen;
if(result == 1){ lines++;
process_smtp_command(session, puf, cfg);
// if chunking is enabled and we have data after BDAT <len> if(rc == OK){
// then process the rest if(session->protocol_state == SMTP_STATE_BDAT){
if(session->bad == 1){
if(session->cfg->enable_chunking == 1 && p && session->protocol_state == SMTP_STATE_BDAT){ // something bad happened in the BDAT processing
process_bdat(session, p, strlen(p), cfg); return;
break;
} }
process_bdat(session, puf, puflen, cfg);
}
else if(session->protocol_state == SMTP_STATE_DATA){
process_data(session, puf, puflen);
}
else {
process_smtp_command(session, puf, cfg);
}
}
else if(puflen > 0){
// if it's BDAT state, then don't buffer, rather give it to
// the BDAT processing function
if(session->protocol_state == SMTP_STATE_BDAT){
process_bdat(session, puf, puflen, cfg);
} }
else { else {
snprintf(session->buf, SMALLBUFSIZE-1, "%s", puf); snprintf(session->buf, MAXBUFSIZE-1, "%s", puf);
session->buflen = strlen(puf); session->buflen = puflen;
} }
} while(p); }
} } while(puflen > 0);
} }

View File

@ -70,61 +70,17 @@ void process_smtp_command(struct smtp_session *session, char *buf, struct config
} }
void process_data(struct smtp_session *session, char *readbuf, int readlen){ void process_data(struct smtp_session *session, char *buf, int buflen){
char puf[SMALLBUFSIZE+BIGBUFSIZE]; if(strcmp(buf, ".\r\n") == 0){
int n, pos, len, writelen;
memset(puf, 0, sizeof(puf));
len = readlen;
if(session->buflen > 0){
memcpy(&puf[0], session->buf, session->buflen);
memcpy(&puf[session->buflen], readbuf, readlen);
len += session->buflen;
}
else {
memcpy(&puf[0], readbuf, readlen);
}
pos = searchStringInBuffer(&puf[0], len, SMTP_CMD_PERIOD, 5);
if(pos > 0){
if(write(session->fd, puf, pos) != -1){
session->tot_len += pos;
process_command_period(session);
}
else syslog(LOG_PRIORITY, "ERROR (line: %d): process_data(): failed to write %d bytes", __LINE__, pos);
}
else if(pos < 0){
n = search_char_backward(&puf[0], len, '\r');
if(n == -1 || len - n > 4){
if(n == -1) writelen = len;
else writelen = n-1;
if(writelen > 0){
if(write(session->fd, puf, writelen) != -1){
session->tot_len += writelen;
}
else syslog(LOG_PRIORITY, "ERROR (line: %d): process_data(): failed to write %d bytes", __LINE__, writelen);
}
}
else {
if(write(session->fd, puf, n) != -1){
session->tot_len += n;
}
else syslog(LOG_PRIORITY, "ERROR (line: %d) process_data(): failed to write %d bytes", __LINE__, n);
snprintf(session->buf, SMALLBUFSIZE-1, "%s", &puf[n]);
session->buflen = len - n;
}
}
else {
// The buffer contains only the CR-LF-DOT-CR-LF sequence
process_command_period(session); process_command_period(session);
} }
else {
// write line to file
if(write(session->fd, buf, buflen) != -1){
session->tot_len += buflen;
}
else syslog(LOG_PRIORITY, "ERROR (line: %d) process_data(): failed to write %d bytes", __LINE__, buflen);
}
} }

View File

@ -8,7 +8,7 @@
#include <piler.h> #include <piler.h>
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);
void process_data(struct smtp_session *session, char *readbuf, int readlen); void process_data(struct smtp_session *session, char *buf, int buflen);
void send_smtp_response(struct smtp_session *session, char *buf); void send_smtp_response(struct smtp_session *session, char *buf);
void process_command_helo(struct smtp_session *session, char *buf, int buflen); void process_command_helo(struct smtp_session *session, char *buf, int buflen);

View File

@ -89,50 +89,6 @@ static void test_trim_buffer(){
} }
static void test_search_string_in_buffer(){
unsigned int i;
int pos;
struct test_data_s_s_i test_data_s_s_i[] = {
{ "ajaja\r\n.\r\n", SMTP_CMD_PERIOD, 5 },
{ "ajaja\r\n.\r\ndhdjdhj", SMTP_CMD_PERIOD, 5 },
{ "ajajadjdhj", "a", 0 },
{ "ajajadjdhj", "aja", 0 },
{ "ajajadjdhj", "jaja", 1 },
{ "ajajadjdhj", "qqq", -1 },
};
TEST_HEADER();
for(i=0; i<sizeof(test_data_s_s_i)/sizeof(struct test_data_s_s_i); i++){
pos = searchStringInBuffer(test_data_s_s_i[i].s1, strlen(test_data_s_s_i[i].s1), test_data_s_s_i[i].s2, strlen(test_data_s_s_i[i].s2));
//printf("%s %s %d, %d\n", test_data_s_s_i[i].s1, test_data_s_s_i[i].s2, pos, test_data_s_s_i[i].result);
ASSERT(pos == test_data_s_s_i[i].result, test_data_s_s_i[i].s1);
}
TEST_FOOTER();
}
static void test_search_char_backward(){
unsigned int i;
int pos;
struct test_data_s_s_i test_data_s_s_i[] = {
{ "abcdefghij\r\n.\r\n", "\r", 10 },
{ "abcdefghij\n\n.\r\n", "\r", 13 },
{ "abcdefghij\n\n.\n\n", "\r", -1 },
};
TEST_HEADER();
for(i=0; i<sizeof(test_data_s_s_i)/sizeof(struct test_data_s_s_i); i++){
pos = search_char_backward(test_data_s_s_i[i].s1, strlen(test_data_s_s_i[i].s1), test_data_s_s_i[i].s2[0]);
ASSERT(pos == test_data_s_s_i[i].result, test_data_s_s_i[i].s1);
}
TEST_FOOTER();
}
static void test_make_random_string(){ static void test_make_random_string(){
unsigned int i; unsigned int i;
char buf[SMALLBUFSIZE]; char buf[SMALLBUFSIZE];
@ -229,8 +185,6 @@ int main(){
test_extract_verp_address(); test_extract_verp_address();
test_extract_email(); test_extract_email();
test_trim_buffer(); test_trim_buffer();
test_search_string_in_buffer();
test_search_char_backward();
test_make_random_string(); test_make_random_string();
test_create_id(); test_create_id();
test_split(); test_split();