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); 
 | 
 } 
 |