diff --git a/src/misc.c b/src/misc.c index 26b94579..9643acdc 100644 --- a/src/misc.c +++ b/src/misc.c @@ -103,7 +103,7 @@ int searchStringInBuffer(char *s, int len1, char *what, int len2){ return i; } - return 0; + return -1; } diff --git a/src/smtp.c b/src/smtp.c index 062f1ce9..5512ed73 100644 --- a/src/smtp.c +++ b/src/smtp.c @@ -72,18 +72,19 @@ void process_smtp_command(struct smtp_session *session, char *buf){ void process_data(struct smtp_session *session, char *readbuf, int readlen){ char puf[SMALLBUFSIZE+BIGBUFSIZE]; - int n, pos, len; + 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 + readlen; + + len += session->buflen; } else { memcpy(&puf[0], readbuf, readlen); - len = readlen; } pos = searchStringInBuffer(&puf[0], len, SMTP_CMD_PERIOD, 5); @@ -93,27 +94,37 @@ void process_data(struct smtp_session *session, char *readbuf, int readlen){ session->tot_len += pos; process_command_period(session); } - else syslog(LOG_PRIORITY, "ERROR: process_data(): failed to write %d bytes", pos); + else syslog(LOG_PRIORITY, "ERROR (line: %d): process_data(): failed to write %d bytes", __LINE__, pos); } - else { + else if(pos < 0){ n = search_char_backward(&puf[0], len, '\r'); if(n == -1 || len - n > 4){ - if(write(session->fd, puf, len) != -1){ - session->tot_len += len; + + 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 syslog(LOG_PRIORITY, "ERROR: process_data(): failed to write %d bytes", len); } else { if(write(session->fd, puf, n) != -1){ session->tot_len += n; } - else syslog(LOG_PRIORITY, "process_data(): failed to write %d bytes", 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); + } } diff --git a/unit_tests/smtp.c b/unit_tests/smtp.c index 9b43f830..d71a69b8 100644 --- a/unit_tests/smtp.c +++ b/unit_tests/smtp.c @@ -309,6 +309,56 @@ static void test_smtp_commands_starttls(char *server, int port, struct data *dat } +static void test_smtp_commands_period_command_in_2_parts(char *server, int port, char *part1, char *part2, struct data *data){ + char recvbuf[MAXBUFSIZE], sendbuf[MAXBUFSIZE]; + + connect_to_smtp_server(server, port, data); + + send_helo_command(data->net); + + send_smtp_command(data->net, "MAIL FROM: \r\nRCPT TO: \r\nDATA\r\n", recvbuf, sizeof(recvbuf)-1); + assert(strncmp(recvbuf, "250 ", 4) == 0 && "MAIL"); + + snprintf(sendbuf, sizeof(sendbuf)-1, "%s%s", testmessage, part1); + write1(data->net, sendbuf, strlen(sendbuf)); + + snprintf(sendbuf, sizeof(sendbuf), "%s", part2); + send_smtp_command(data->net, sendbuf, recvbuf, sizeof(recvbuf)-1); + + snprintf(sendbuf, sizeof(sendbuf)-1, "QUIT\r\n"); + send_smtp_command(data->net, sendbuf, recvbuf, sizeof(recvbuf)-1); + + assert(strncmp(recvbuf, "250 ", 4) == 0 && "QUIT"); + + close(data->net->socket); +} + + +static void test_smtp_commands_period_command_in_its_own_packet(char *server, int port, struct data *data){ + char recvbuf[MAXBUFSIZE], sendbuf[MAXBUFSIZE]; + + connect_to_smtp_server(server, port, data); + + send_helo_command(data->net); + + send_smtp_command(data->net, "MAIL FROM: \r\nRCPT TO: \r\nDATA\r\n", recvbuf, sizeof(recvbuf)-1); + assert(strncmp(recvbuf, "250 ", 4) == 0 && "MAIL"); + + snprintf(sendbuf, sizeof(sendbuf)-1, "%s", testmessage); + write1(data->net, sendbuf, strlen(sendbuf)); + + snprintf(sendbuf, sizeof(sendbuf), "\r\n.\r\n"); + send_smtp_command(data->net, sendbuf, recvbuf, sizeof(recvbuf)-1); + + snprintf(sendbuf, sizeof(sendbuf)-1, "QUIT\r\n"); + send_smtp_command(data->net, sendbuf, recvbuf, sizeof(recvbuf)-1); + + assert(strncmp(recvbuf, "250 ", 4) == 0 && "QUIT"); + + close(data->net->socket); +} + + int main(int argc, char **argv){ int c, port=25; char *server=NULL; @@ -380,6 +430,11 @@ int main(int argc, char **argv){ test_smtp_commands_with_reset_command(server, port, &data); test_smtp_commands_partial_command(server, port, &data); test_smtp_commands_partial_command_pipelining(server, port, &data); + test_smtp_commands_period_command_in_2_parts(server, port, "\r", "\n.\r\n", &data); + test_smtp_commands_period_command_in_2_parts(server, port, "\r\n", ".\r\n", &data); + test_smtp_commands_period_command_in_2_parts(server, port, "\r\n.", "\r\n", &data); + test_smtp_commands_period_command_in_2_parts(server, port, "\r\n.\r", "\n", &data); + test_smtp_commands_period_command_in_its_own_packet(server, port, &data); helo = 1; // we must use EHLO to get the STARTTLS in the response test_smtp_commands_starttls(server, port, &data);