mirror of
https://bitbucket.org/jsuto/piler.git
synced 2024-11-08 00:31:58 +01:00
revised smtp protocol handling
Signed-off-by: Janos SUTO <sj@acts.hu>
This commit is contained in:
parent
52d44ddee1
commit
e18ec3a701
@ -9,9 +9,9 @@
|
||||
#include "piler-config.h"
|
||||
#include "params.h"
|
||||
|
||||
#define VERSION "1.3.3"
|
||||
#define VERSION "1.3.4"
|
||||
|
||||
#define BUILD 990
|
||||
#define BUILD 991
|
||||
|
||||
#define HOSTID "mailarchiver"
|
||||
|
||||
|
@ -383,7 +383,7 @@ struct smtp_session {
|
||||
char ttmpfile[SMALLBUFSIZE];
|
||||
char mailfrom[SMALLBUFSIZE];
|
||||
char rcptto[MAX_RCPT_TO][SMALLBUFSIZE];
|
||||
char buf[SMALLBUFSIZE];
|
||||
char buf[MAXBUFSIZE];
|
||||
char remote_host[INET6_ADDRSTRLEN];
|
||||
time_t lasttime;
|
||||
int protocol_state;
|
||||
|
66
src/misc.c
66
src/misc.c
@ -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
|
||||
*/
|
||||
@ -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
|
||||
char *strcasestr(const char *s, const char *find){
|
||||
char c, sc;
|
||||
|
@ -19,8 +19,6 @@ int get_build();
|
||||
void get_extractor_list();
|
||||
void __fatal(char *s);
|
||||
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);
|
||||
void replaceCharacterInBuffer(char *p, char from, char to);
|
||||
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);
|
||||
|
||||
void move_email(struct smtp_session *session);
|
||||
int read_one_line(char *s, int c, char *buf, int buflen, int *rc);
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
char *strcasestr(const char *s, const char *find);
|
||||
|
@ -126,7 +126,7 @@ void init_smtp_session(struct smtp_session *session, int slot, int sd, struct co
|
||||
session->num_of_rcpt_to = 0;
|
||||
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);
|
||||
|
||||
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){
|
||||
char *p, puf[MAXBUFSIZE];
|
||||
int result;
|
||||
int puflen, rc, lines=0;
|
||||
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->bad == 1){
|
||||
// something bad happened in the BDAT processing
|
||||
return;
|
||||
}
|
||||
if(session->buflen > 0){
|
||||
memset(copybuf, 0, sizeof(copybuf));
|
||||
|
||||
process_bdat(session, readbuf, readlen, cfg);
|
||||
memcpy(copybuf, session->buf, session->buflen);
|
||||
memcpy(©buf[session->buflen], readbuf, readlen);
|
||||
|
||||
session->buflen = 0;
|
||||
memset(session->buf, 0, MAXBUFSIZE);
|
||||
|
||||
p = ©buf[0];
|
||||
}
|
||||
|
||||
// process DATA
|
||||
|
||||
else if(session->protocol_state == SMTP_STATE_DATA){
|
||||
process_data(session, readbuf, readlen);
|
||||
}
|
||||
|
||||
// process other SMTP commands
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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){
|
||||
process_smtp_command(session, puf, cfg);
|
||||
lines++;
|
||||
|
||||
// if chunking is enabled and we have data after BDAT <len>
|
||||
// then process the rest
|
||||
|
||||
if(session->cfg->enable_chunking == 1 && p && session->protocol_state == SMTP_STATE_BDAT){
|
||||
process_bdat(session, p, strlen(p), cfg);
|
||||
break;
|
||||
if(rc == OK){
|
||||
if(session->protocol_state == SMTP_STATE_BDAT){
|
||||
if(session->bad == 1){
|
||||
// something bad happened in the BDAT processing
|
||||
return;
|
||||
}
|
||||
|
||||
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 {
|
||||
snprintf(session->buf, SMALLBUFSIZE-1, "%s", puf);
|
||||
session->buflen = strlen(puf);
|
||||
snprintf(session->buf, MAXBUFSIZE-1, "%s", puf);
|
||||
session->buflen = puflen;
|
||||
}
|
||||
} while(p);
|
||||
}
|
||||
|
||||
}
|
||||
} while(puflen > 0);
|
||||
|
||||
}
|
||||
|
||||
|
62
src/smtp.c
62
src/smtp.c
@ -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){
|
||||
char puf[SMALLBUFSIZE+BIGBUFSIZE];
|
||||
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
|
||||
void process_data(struct smtp_session *session, char *buf, int buflen){
|
||||
if(strcmp(buf, ".\r\n") == 0){
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include <piler.h>
|
||||
|
||||
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 process_command_helo(struct smtp_session *session, char *buf, int buflen);
|
||||
|
@ -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(){
|
||||
unsigned int i;
|
||||
char buf[SMALLBUFSIZE];
|
||||
@ -229,8 +185,6 @@ int main(){
|
||||
test_extract_verp_address();
|
||||
test_extract_email();
|
||||
test_trim_buffer();
|
||||
test_search_string_in_buffer();
|
||||
test_search_char_backward();
|
||||
test_make_random_string();
|
||||
test_create_id();
|
||||
test_split();
|
||||
|
Loading…
Reference in New Issue
Block a user