Fixed piler-smtp to properly handle emails with NUL byte(s)

Signed-off-by: Janos SUTO <sj@acts.hu>
This commit is contained in:
Janos SUTO 2021-07-26 16:56:45 +02:00
parent 307a84b12b
commit e1ea14374a
6 changed files with 45 additions and 16 deletions

View File

@ -402,6 +402,7 @@ struct smtp_session {
char rcptto[MAX_RCPT_TO][SMALLBUFSIZE];
char buf[MAXBUFSIZE];
char remote_host[INET6_ADDRSTRLEN+1];
char nullbyte;
time_t lasttime;
int protocol_state;
int slot;

View File

@ -58,7 +58,7 @@ void process_buffer(char *buf, int buflen, uint64 *count, struct session_data *s
void import_from_pilerexport(struct session_data *sdata, struct data *data, struct config *cfg){
int n, rc, savedlen=0, puflen;
int n, rc, nullbyte, savedlen=0, puflen;
uint64 count=0;
char *p, copybuf[2*BIGBUFSIZE+1], buf[BIGBUFSIZE], savedbuf[BIGBUFSIZE], puf[BIGBUFSIZE];
@ -70,12 +70,16 @@ void import_from_pilerexport(struct session_data *sdata, struct data *data, stru
memset(buf, 0, sizeof(buf));
n = fread(buf, 1, sizeof(buf)-1, stdin);
int remaininglen = n;
if(savedlen > 0){
memset(copybuf, 0, sizeof(copybuf));
memcpy(copybuf, savedbuf, savedlen);
memcpy(&copybuf[savedlen], buf, n);
remaininglen += savedlen;
savedlen = 0;
memset(savedbuf, 0, sizeof(savedbuf));
@ -86,8 +90,9 @@ void import_from_pilerexport(struct session_data *sdata, struct data *data, stru
}
do {
puflen = read_one_line(p, '\n', puf, sizeof(puf), &rc);
puflen = read_one_line(p, remaininglen, '\n', puf, sizeof(puf), &rc, &nullbyte);
p += puflen;
remaininglen -= puflen;
if(puflen > 0){
if(rc == OK){

View File

@ -652,34 +652,42 @@ void move_email(struct smtp_session *session){
snprintf(buf, sizeof(buf)-1, "%d/%s", session->ttmpfile[0] % session->cfg->number_of_worker_processes, session->ttmpfile);
if(session->nullbyte){
snprintf(buf, sizeof(buf)-1, "%s/%s", ERROR_DIR, session->ttmpfile);
syslog(LOG_PRIORITY, "ERROR: %s contains an invalid NUL-byte, moving it to %s", session->ttmpfile, ERROR_DIR);
}
if(rename(session->ttmpfile, buf)){
syslog(LOG_PRIORITY, "ERROR: couldn't rename %s to %s (reason: %s)", session->ttmpfile, buf, strerror(errno));
}
}
int read_one_line(char *s, int c, char *buf, int buflen, int *rc){
int read_one_line(char *s, int slen, int c, char *buf, int buflen, int *rc, int *nullbyte){
int i=0;
*rc = ERR;
*nullbyte = 0;
memset(buf, 0, buflen);
if(s == NULL){
return i;
for(int j=0; j<slen; j++){
if(i<buflen-2){
if(*(s+j) == 0){
*nullbyte = 1;
}
for(; *s; s++){
if(i<buflen-2){
buf[i] = *s;
buf[i] = *(s+j);
i++;
if(*s == c){
if(*(s+j) == c){
*rc = OK;
break;
}
}
else break;
else {
break;
}
}
return i;

View File

@ -46,7 +46,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);
int read_one_line(char *s, int slen, int c, char *buf, int buflen, int *rc, int *nullbyte);
int init_ssl_to_server(struct data *data);

View File

@ -100,11 +100,15 @@ int pop3_download_email(struct data *data, int i){
int n = 0;
while((n = recvtimeoutssl(data->net, buf, sizeof(buf))) > 0){
int remaininglen = n;
if(savedlen){
memset(copybuf, 0, sizeof(copybuf));
memcpy(copybuf, savedbuf, savedlen);
memcpy(&copybuf[savedlen], buf, n);
remaininglen += savedlen;
savedlen = 0;
memset(savedbuf, 0, sizeof(savedbuf));
@ -115,10 +119,13 @@ int pop3_download_email(struct data *data, int i){
int puflen=0;
int rc=OK;
int nullbyte=0;
do {
char puf[MAXBUFSIZE];
puflen = read_one_line(p, '\n', puf, sizeof(puf)-1, &rc);
puflen = read_one_line(p, remaininglen, '\n', puf, sizeof(puf)-1, &rc, &nullbyte);
remaininglen -= puflen;
nlines++;
if(nlines == 1){

View File

@ -99,6 +99,7 @@ void init_smtp_session(struct smtp_session *session, int slot, int sd, char *cli
session->net.ctx = NULL;
session->net.ssl = NULL;
session->nullbyte = 0;
session->last_data_char = 0;
session->fd = -1;
@ -160,11 +161,13 @@ 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){
int puflen, rc;
int puflen, rc, nullbyte;
char *p, copybuf[BIGBUFSIZE+MAXBUFSIZE], puf[MAXBUFSIZE];
// if there's something in the saved buffer, then let's merge them
int remaininglen = readlen + session->buflen;
if(session->buflen > 0){
memset(copybuf, 0, sizeof(copybuf));
@ -183,8 +186,13 @@ void handle_data(struct smtp_session *session, char *readbuf, int readlen, struc
do {
puflen = read_one_line(p, '\n', puf, sizeof(puf)-1, &rc);
puflen = read_one_line(p, remaininglen, '\n', puf, sizeof(puf)-1, &rc, &nullbyte);
p += puflen;
remaininglen -= puflen;
if(nullbyte){
session->nullbyte = 1;
}
// complete line: rc == OK and puflen > 0
// incomplete line with something in the buffer: rc == ERR and puflen > 0
@ -195,7 +203,7 @@ void handle_data(struct smtp_session *session, char *readbuf, int readlen, struc
// Save incomplete line to buffer
if(rc == ERR){
snprintf(session->buf, sizeof(session->buf)-1, "%s", puf);
memcpy(session->buf, puf, puflen);
session->buflen = puflen;
}