ssmtp (2.62-3) 345780-standardise-bufsize

Summary

 ssmtp.c |   80 ++++++++++++++++++++++++++++++++++++----------------------------
 1 file changed, 46 insertions(+), 34 deletions(-)

    
download this patch

Patch contents

Index: ssmtp-2.62/ssmtp.c
===================================================================
--- ssmtp-2.62.orig/ssmtp.c	2008-11-09 11:30:12.000000000 +0200
+++ ssmtp-2.62/ssmtp.c	2008-11-21 11:37:53.000000000 +0200
@@ -343,28 +343,26 @@
 /*
 standardise() -- Trim off '\n's and double leading dots
 */
-void standardise(char *str)
+bool_t standardise(char *str, bool_t *linestart)
 {
 	size_t sl;
 	char *p;
-
-	if((p = strchr(str, '\n'))) {
-		*p = (char)NULL;
-	}
+	bool_t leadingdot = False;
 
 	/* Any line beginning with a dot has an additional dot inserted;
-	not just a line consisting solely of a dot. Thus we have to slide
-	the buffer down one */
-	sl = strlen(str);
+	not just a line consisting solely of a dot. Thus we have to move
+	the buffer start up one */
 
-	if(*str == '.') {
-		if((sl + 2) > BUF_SZ) {
-			die("standardise() -- Buffer overflow");
-		}
-		(void)memmove((str + 1), str, (sl + 1));	/* Copy trailing \0 */
+	if(*linestart && *str == '.') {
+		leadingdot = True;
+	}
+	*linestart = False;
 
-		*str = '.';
+	if((p = strchr(str, '\n'))) {
+		*p = (char)NULL;
+		*linestart = True;
 	}
+	return(leadingdot);
 }
 
 /*
@@ -1359,12 +1357,12 @@
 */
 ssize_t smtp_write(int fd, char *format, ...)
 {
-	char buf[(BUF_SZ + 1)];
+	char buf[(BUF_SZ + 2)];
 	va_list ap;
 	ssize_t outbytes = 0;
 
 	va_start(ap, format);
-	if(vsnprintf(buf, (BUF_SZ - 2), format, ap) == -1) {
+	if(vsnprintf(buf, (BUF_SZ - 1), format, ap) == -1) {
 		die("smtp_write() -- vsnprintf() failed");
 	}
 	va_end(ap);
@@ -1402,16 +1400,18 @@
 */
 int ssmtp(char *argv[])
 {
-	char buf[(BUF_SZ + 1)], *p, *q;
+	char b[(BUF_SZ + 2)], *buf = b+1, *p, *q;
 #ifdef MD5AUTH
 	char challenge[(BUF_SZ + 1)];
 #endif
 	struct passwd *pw;
 	int i, sock;
 	uid_t uid;
-	bool_t minus_v_save;
+	bool_t minus_v_save, leadingdot, linestart = True;
 	int timeout = 0;
+	int bufsize = sizeof(b)-1;
 
+	b[0] = '.';
 	outbytes = 0;
 	ht = &headers;
 
@@ -1494,12 +1494,12 @@
 			}
 			strncpy(challenge, strchr(buf,' ') + 1, sizeof(challenge));
 
-			memset(buf, 0, sizeof(buf));
+			memset(buf, 0, bufsize);
 			crammd5(challenge, auth_user, auth_pass, buf);
 		}
 		else {
 #endif
-		memset(buf, 0, sizeof(buf));
+		memset(buf, 0, bufsize);
 		to64frombits(buf, auth_user, strlen(auth_user));
 		if (use_oldauth) {
 			outbytes += smtp_write(sock, "AUTH LOGIN %s", buf);
@@ -1511,7 +1511,7 @@
 				die("Server didn't like our AUTH LOGIN (%s)", buf);
 			}
 			/* we assume server asked us for Username */
-			memset(buf, 0, sizeof(buf));
+			memset(buf, 0, bufsize);
 			to64frombits(buf, auth_user, strlen(auth_user));
 			outbytes += smtp_write(sock, buf);
 		}
@@ -1520,7 +1520,7 @@
 		if(smtp_read(sock, buf) != 3) {
 			die("Server didn't accept AUTH LOGIN (%s)", buf);
 		}
-		memset(buf, 0, sizeof(buf));
+		memset(buf, 0, bufsize);
 
 		to64frombits(buf, auth_pass, strlen(auth_pass));
 #ifdef MD5AUTH
@@ -1629,28 +1629,40 @@
 	  stdio functions like fgets in the first place */
 	fcntl(STDIN_FILENO,F_SETFL,O_NONBLOCK);
 
-	/* don't hang forever when reading from stdin */
-	while(!feof(stdin) && timeout < MEDWAIT) {
-		if (!fgets(buf, sizeof(buf), stdin)) {
+	while(!feof(stdin)) {
+		if (!fgets(buf, bufsize, stdin)) {
 			/* if nothing was received, then no transmission
 			 * over smtp should be done */
 			sleep(1);
-			timeout++;
+			/* don't hang forever when reading from stdin */
+			if (++timeout >= MEDWAIT) {
+				log_event(LOG_ERR, "killed: timeout on stdin while reading body -- message saved to dead.letter.");
+				die("Timeout on stdin while reading body");
+			}
 			continue;
 		}
 		/* Trim off \n, double leading .'s */
-		standardise(buf);
-
-		outbytes += smtp_write(sock, "%s", buf);
+		leadingdot = standardise(buf, &linestart);
 
+		if (linestart || feof(stdin)) {
+			linestart = True;
+			outbytes += smtp_write(sock, "%s", leadingdot ? b : buf);
+		} else {
+			if (log_level > 0) {
+				log_event(LOG_INFO, "Sent a very long line in chunks");
+			}
+			if (leadingdot) {
+				outbytes += fd_puts(sock, b, sizeof(b));
+			} else {
+				outbytes += fd_puts(sock, buf, bufsize);
+			}
+		}
 		(void)alarm((unsigned) MEDWAIT);
 	}
-	/* End of body */
-
-	if (timeout >= MEDWAIT) {
-		log_event(LOG_ERR, "killed: timeout on stdin while reading body -- message saved to dead.letter.");
-		die("Timeout on stdin while reading body");
+	if(!linestart) {
+		smtp_write(sock, "");
 	}
+	/* End of body */
 
 	outbytes += smtp_write(sock, ".");
 	(void)alarm((unsigned) MAXWAIT);