Bug#819060: clamsmtp/proxsmtp does not handle lines with leading dots correctly
Hello,
after this has been undealed with since almost two years, I wrote a
patch myself. Maybe someone finds at least the time to review it.
Regards
Christoph
Index: proxsmtp-1.10/common/smtppass.c
===================================================================
--- proxsmtp-1.10.orig/common/smtppass.c 2018-02-16 13:34:32.445788258 +0100
+++ proxsmtp-1.10/common/smtppass.c 2018-02-16 14:28:03.119531212 +0100
@@ -1524,16 +1524,37 @@
{
int r, count = 0;
const char* data;
+ int linestart;
+
+ linestart = 1;
while((r = sp_read_data(ctx, &data)) != 0)
{
- if(r < 0)
- return -1; /* Message already printed */
+ if(r < 0)
+ return -1; /* Message already printed */
+
+ sp_messagex(ctx, LOG_DEBUG, "data is %d characters long", strlen(data));
+ sp_messagex(ctx, LOG_DEBUG, "r is %d", r);
- count += r;
+ /* SMTP RFCs say that servers must remove leading dots at the beginning
+ * of a line. We do that here.
+ */
+
+ if (linestart && (data[0] == '.'))
+ {
+ data++;
+ r--;
+ }
+
+ if (data[r-1] == '\n')
+ linestart = 1;
+ else
+ linestart = 0;
- if((r = sp_write_data(ctx, data, r)) < 0)
- return -1; /* Message already printed */
+ count += r;
+
+ if((r = sp_write_data(ctx, data, r)) < 0)
+ return -1; /* Message already printed */
}
/* End the caching */
@@ -1707,9 +1728,12 @@
int ret = 0;
char *line;
char header[MAX_HEADER_LENGTH] = "";
- size_t header_len, line_len;
+ size_t header_len;
int header_prepend = 0;
ssize_t rc;
+ size_t buf_len;
+ int linestart;
+ char *buf;
ASSERT(ctx->cachename[0]); /* Must still be around */
ASSERT(!ctx->cachefile); /* File must be closed */
@@ -1717,10 +1741,12 @@
memset(header, 0, sizeof(header));
/* Alloc line buffer */
- line_len = SP_LINE_LENGTH;
- if((line = (char *)malloc(line_len)) == NULL)
+ buf_len = SP_LINE_LENGTH;
+ if((buf = (char *)malloc(buf_len)) == NULL)
RETURN(-1);
+ buf[0] = '.';
+
/* Open the file */
file = fopen(ctx->cachename, "r");
if(file == NULL)
@@ -1766,17 +1792,23 @@
header[0] = '\0';
}
+ linestart = 1;
+
/* Transfer actual file data */
- while((rc = getline(&line, &line_len, file)) != -1)
+ while(line = (fgets(buf + 1, buf_len - 1, file)))
{
- /*
- * If the line is <CRLF>.<CRLF> we need to change it so that
- * it doesn't end the email. We do this by adding a space.
- * This won't occur much in clamsmtpd, but proxsmtpd might
- * have filters that accidentally put this in.
- */
- if(strcmp(line, "." CRLF) == 0)
- strncpy(line, ". " CRLF, SP_LINE_LENGTH);
+ /* SMTP RFCs say that clients must prepend an additional dot
+ * to every line starting with a dot. We do that here.
+ */
+ if (linestart && (line[0] == '.'))
+ line = buf;
+
+ rc = strlen(line);
+
+ if (line[rc-1] == '\n')
+ linestart = 1;
+ else
+ linestart = 0;
if(header[0] != '\0')
{
@@ -1818,10 +1850,10 @@
cleanup:
- if(line)
- free(line);
- if(file)
- fclose(file); /* read-only so no error check */
+ if(buf)
+ free(buf);
+ if(file)
+ fclose(file); /* read-only so no error check */
return ret;
}
Reply to: