Hello,a new version of the patch, in accordance to RFC 5321 only accepting CRLF as line separator, and with usage of builtin struct member _crlf to remember CRLFs.
By the way, clamsmtp maintainers already integrated my patch into their package.
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; }