1Bug-Debian: http://bugs.debian.org/584162 2Reported-By: Christoph Biedl <debian.axhn@manchmal.in-ulm.de> 3Forwarded: not-needed 4Reviewed-By: Anibal Monsalve Salazar <anibal@debian.org> 5Last-Update: 2014-08-15 6 7From: "Daniel Richard G." <skunk@iSKUNK.ORG> 8Subject: Re: ssmtp: Partial loss of message body, sending message to wrong recipicients 9Date: Thu, 19 Jun 2014 14:44:30 -0400 10 11Attached is a patch against the original 2.64 source that should address 12this bug, and hopefully not break anything. An overview of my changes: 13 14* Added code to standarise() to drop the trailing '\r' if the line 15 originally ended with "\r\n". 16 17* Added a check to header_parse() that effectively converts an "\r\n" in 18 the input into '\n'. 19 20* Added a conditional so that header_parse() doesn't pass the empty 21 string to header_save()---a behavior I observed in testing, at the end 22 of a header block with "\r\n" line endings. 23 24* Simplified the last if(in_header) conditional in header_parse(), 25 because it erroneously assumes that if in_header == True, then c could 26 have some value other than EOF. (See the condition on the previous 27 "while" loop, and the lack of any other way to exit said loop.) 28 29 header_parse() will now properly grab a header if fed a message 30 without a body (i.e. no "\n\n" ending the header block), although this 31 code will still drop a header if there is no newline at the end. 32 33Christoph, thank you for your excellent analysis, and the test cases. I 34made use of them, and with my changes sSMTP appears to do the right 35thing. 36 37Debian patch from: https://sources.debian.net/patches/ssmtp/2.64-8/ 38 39Upstream-Status: Backport [debian] 40 41Signed-off-by: Andre McCurdy <armccurdy@gmail.com> 42 43Index: ssmtp-2.64/ssmtp.c 44=================================================================== 45--- ssmtp-2.64.orig/ssmtp.c 46+++ ssmtp-2.64/ssmtp.c 47@@ -375,6 +375,12 @@ bool_t standardise(char *str, bool_t *li 48 if((p = strchr(str, '\n'))) { 49 *p = (char)NULL; 50 *linestart = True; 51+ 52+ /* If the line ended in "\r\n", then drop the '\r' too */ 53+ sl = strlen(str); 54+ if(sl >= 1 && str[sl - 1] == '\r') { 55+ str[sl - 1] = (char)NULL; 56+ } 57 } 58 return(leadingdot); 59 } 60@@ -768,6 +774,14 @@ void header_parse(FILE *stream) 61 } 62 len++; 63 64+ if(l == '\r' && c == '\n') { 65+ /* Properly handle input that already has "\r\n" 66+ line endings; see https://bugs.debian.org/584162 */ 67+ l = (len >= 2 ? *(q - 2) : '\n'); 68+ q--; 69+ len--; 70+ } 71+ 72 if(l == '\n') { 73 switch(c) { 74 case ' ': 75@@ -790,7 +804,9 @@ void header_parse(FILE *stream) 76 if((q = strrchr(p, '\n'))) { 77 *q = (char)NULL; 78 } 79- header_save(p); 80+ if(len > 0) { 81+ header_save(p); 82+ } 83 84 q = p; 85 len = 0; 86@@ -800,35 +816,12 @@ void header_parse(FILE *stream) 87 88 l = c; 89 } 90- if(in_header) { 91- if(l == '\n') { 92- switch(c) { 93- case ' ': 94- case '\t': 95- /* Must insert '\r' before '\n's embedded in header 96- fields otherwise qmail won't accept our mail 97- because a bare '\n' violates some RFC */ 98- 99- *(q - 1) = '\r'; /* Replace previous \n with \r */ 100- *q++ = '\n'; /* Insert \n */ 101- len++; 102- 103- break; 104- 105- case '\n': 106- in_header = False; 107- 108- default: 109- *q = (char)NULL; 110- if((q = strrchr(p, '\n'))) { 111- *q = (char)NULL; 112- } 113- header_save(p); 114- 115- q = p; 116- len = 0; 117- } 118+ if(in_header && l == '\n') { 119+ /* Got EOF while reading the header */ 120+ if((q = strrchr(p, '\n'))) { 121+ *q = (char)NULL; 122 } 123+ header_save(p); 124 } 125 (void)free(p); 126 } 127