| Bug-Debian: http://bugs.debian.org/584162 |
| Reported-By: Christoph Biedl <debian.axhn@manchmal.in-ulm.de> |
| Forwarded: not-needed |
| Reviewed-By: Anibal Monsalve Salazar <anibal@debian.org> |
| Last-Update: 2014-08-15 |
| |
| From: "Daniel Richard G." <skunk@iSKUNK.ORG> |
| Subject: Re: ssmtp: Partial loss of message body, sending message to wrong recipicients |
| Date: Thu, 19 Jun 2014 14:44:30 -0400 |
| |
| Attached is a patch against the original 2.64 source that should address |
| this bug, and hopefully not break anything. An overview of my changes: |
| |
| * Added code to standarise() to drop the trailing '\r' if the line |
| originally ended with "\r\n". |
| |
| * Added a check to header_parse() that effectively converts an "\r\n" in |
| the input into '\n'. |
| |
| * Added a conditional so that header_parse() doesn't pass the empty |
| string to header_save()---a behavior I observed in testing, at the end |
| of a header block with "\r\n" line endings. |
| |
| * Simplified the last if(in_header) conditional in header_parse(), |
| because it erroneously assumes that if in_header == True, then c could |
| have some value other than EOF. (See the condition on the previous |
| "while" loop, and the lack of any other way to exit said loop.) |
| |
| header_parse() will now properly grab a header if fed a message |
| without a body (i.e. no "\n\n" ending the header block), although this |
| code will still drop a header if there is no newline at the end. |
| |
| Christoph, thank you for your excellent analysis, and the test cases. I |
| made use of them, and with my changes sSMTP appears to do the right |
| thing. |
| |
| Debian patch from: https://sources.debian.net/patches/ssmtp/2.64-8/ |
| |
| Upstream-Status: Backport [debian] |
| |
| Signed-off-by: Andre McCurdy <armccurdy@gmail.com> |
| |
| Index: ssmtp-2.64/ssmtp.c |
| =================================================================== |
| --- ssmtp-2.64.orig/ssmtp.c |
| +++ ssmtp-2.64/ssmtp.c |
| @@ -375,6 +375,12 @@ bool_t standardise(char *str, bool_t *li |
| if((p = strchr(str, '\n'))) { |
| *p = (char)NULL; |
| *linestart = True; |
| + |
| + /* If the line ended in "\r\n", then drop the '\r' too */ |
| + sl = strlen(str); |
| + if(sl >= 1 && str[sl - 1] == '\r') { |
| + str[sl - 1] = (char)NULL; |
| + } |
| } |
| return(leadingdot); |
| } |
| @@ -768,6 +774,14 @@ void header_parse(FILE *stream) |
| } |
| len++; |
| |
| + if(l == '\r' && c == '\n') { |
| + /* Properly handle input that already has "\r\n" |
| + line endings; see https://bugs.debian.org/584162 */ |
| + l = (len >= 2 ? *(q - 2) : '\n'); |
| + q--; |
| + len--; |
| + } |
| + |
| if(l == '\n') { |
| switch(c) { |
| case ' ': |
| @@ -790,7 +804,9 @@ void header_parse(FILE *stream) |
| if((q = strrchr(p, '\n'))) { |
| *q = (char)NULL; |
| } |
| - header_save(p); |
| + if(len > 0) { |
| + header_save(p); |
| + } |
| |
| q = p; |
| len = 0; |
| @@ -800,35 +816,12 @@ void header_parse(FILE *stream) |
| |
| l = c; |
| } |
| - if(in_header) { |
| - if(l == '\n') { |
| - switch(c) { |
| - case ' ': |
| - case '\t': |
| - /* Must insert '\r' before '\n's embedded in header |
| - fields otherwise qmail won't accept our mail |
| - because a bare '\n' violates some RFC */ |
| - |
| - *(q - 1) = '\r'; /* Replace previous \n with \r */ |
| - *q++ = '\n'; /* Insert \n */ |
| - len++; |
| - |
| - break; |
| - |
| - case '\n': |
| - in_header = False; |
| - |
| - default: |
| - *q = (char)NULL; |
| - if((q = strrchr(p, '\n'))) { |
| - *q = (char)NULL; |
| - } |
| - header_save(p); |
| - |
| - q = p; |
| - len = 0; |
| - } |
| + if(in_header && l == '\n') { |
| + /* Got EOF while reading the header */ |
| + if((q = strrchr(p, '\n'))) { |
| + *q = (char)NULL; |
| } |
| + header_save(p); |
| } |
| (void)free(p); |
| } |