[prev in list] [next in list] [prev in thread] [next in thread] 

List:       busybox
Subject:    Re: New applet: sendmail
From:       "Vladimir Dronnikov" <dronnikov () gmail ! com>
Date:       2008-01-29 9:39:02
Message-ID: 6784529b0801290139w7f38719eob98e222019b45b62 () mail ! gmail ! com
[Download RAW message or body]

[Attachment #2 (multipart/alternative)]


Hello, list!

>Vladimir, folks are right - patches should normally be sent
> >to the list too, not only to personal addresses. Please
> >do so in the future.


Right you are!

Attached is the patch against current svn.

It now sanitizes possible malicious user input.
And works with Lotus Notes which requires \r\n EOLs.

Comments are always welcome.

--
Vladimir

[Attachment #5 (text/html)]

Hello, list!<br><br><div><span class="gmail_quote"></span><blockquote \
class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt \
0pt 0.8ex; padding-left: 1ex;">&gt;Vladimir, folks are right - patches should \
normally be sent<br> &gt;to the list too, not only to personal addresses. \
Please<br>&gt;do so in the future.</blockquote><div><br>Right you are! \
<br></div></div><br>Attached is the patch against current svn.<br><br>It now \
sanitizes possible malicious user input.<br> And works with Lotus Notes which \
requires \r\n EOLs.<br><br>Comments are always welcome.<br><br>--<br>Vladimir<br><br>


["dvv.patch" (text/x-patch)]

diff -Naur busybox.0/include/usage.h busybox/include/usage.h
--- busybox.0/include/usage.h	2008-01-29 01:18:08.000000000 -0700
+++ busybox/include/usage.h	2008-01-29 01:41:02.000000000 -0700
@@ -3135,26 +3135,28 @@
 #define selinuxenabled_full_usage
 
 #define sendmail_trivial_usage \
-       "[-d] {-t to}+ [-f from] [-n[notify]] [-s subject] [-b file]*\n" \
-       "[-a attachment]* [-c charset] [-w timeout] [-h server] [-p port] [-U user] [-P password]"
+       "{-t to}+ {-f from} [-n[notify]] [-s subject] [-b file]*\n" \
+       "[-a attachment]* [-c charset]" \
+       USE_FEATURE_SENDMAIL_NETWORK("\n" \
+       " [-d] [-w timeout] [-h server] [-p port] [-U user] [-P password]" \
+       )
 #define sendmail_full_usage \
-       "Send an email from to with subject and optional attachments.\n" \
-       "Body is read from stdin or from optional files" \
+       "Send an email <from> <to> with <subject> and optional attachments." \
        "\n\nArguments:\n" \
-       "	-d		Just dump composed message\n" \
        "	-t to		Recipient email. May be multiple\n" \
-       "	-f from		Sender email\n" \
+       "	-f from		Sender address\n" \
        "	-n[notify]	Optional notification address. If just -n given then notifies the sender\n" \
        "	-s subject	Optional subject\n" \
        "	-b filename	Optional body content file. May be multiple\n" \
        "	-a filename	Optional file attachment. May be multiple\n" \
        "	-c charset	Assumed charset for body and subject [koi8-r]" \
        USE_FEATURE_SENDMAIL_NETWORK("\n" \
+       "	-d		Just dump composed message\n" \
        "	-w timeout	Set timeout on network operations\n" \
        "	-h server	Optional mail server name or IP [127.0.0.1]\n" \
        "	-p port		Optional mail server port [25]\n" \
        "	-U username	Authenticate using AUTH LOGIN with specified username\n" \
-       "	-P password	Authenticate using AUTH LOGIN with specified password"\
+       "	-P password	Authenticate using AUTH LOGIN with specified password" \
        )
 
 #define seq_trivial_usage \
diff -Naur busybox.0/networking/sendmail.c busybox/networking/sendmail.c
--- busybox.0/networking/sendmail.c	2008-01-29 01:13:45.000000000 -0700
+++ busybox/networking/sendmail.c	2008-01-29 01:19:21.000000000 -0700
@@ -16,45 +16,46 @@
 	DST_BUF_SIZE = 4 * ((SRC_BUF_SIZE + 2) / 3),
 };
 
-static void uuencode(const char *fname)
+static void uuencode(char *fname, const char *text)
 {
+#define src_buf text
 	int fd;
-	char src_buf[SRC_BUF_SIZE];
-	char dst_buf[1 + DST_BUF_SIZE + 1];
+#define len fd
+	char dst_buf[DST_BUF_SIZE + 1];
 
-	fd = xopen(fname, O_RDONLY);
-	fflush(stdout);
-	dst_buf[0] = '\n';
+	if (fname) {
+		fd = xopen(fname, O_RDONLY);
+		src_buf = bb_common_bufsiz1;
+	} else {
+		len = strlen(text);
+	}
+
+	fflush(stdout); // sync stdio and unistd output
 	while (1) {
-		size_t size = full_read(fd, src_buf, SRC_BUF_SIZE);
+		size_t size;
+		if (fname) {
+			size = full_read(fd, (char *)src_buf, SRC_BUF_SIZE);
+			if ((ssize_t)size < 0)
+				bb_perror_msg_and_die(bb_msg_read_error);
+		} else {
+			size = len;
+			if (len > SRC_BUF_SIZE)
+				size = SRC_BUF_SIZE;
+		}
 		if (!size)
 			break;
-		if ((ssize_t)size < 0)
-			bb_perror_msg_and_die(bb_msg_read_error);
-		/* Encode the buffer we just read in */
-		bb_uuencode(dst_buf + 1, src_buf, size, bb_uuenc_tbl_base64);
-		xwrite(STDOUT_FILENO, dst_buf, 1 + 4 * ((size + 2) / 3));
-	}
-	close(fd);
-}
-
-// "inline" version
-// encodes content of given buffer instead of fd
-// used to encode subject and authentication terms
-static void uuencode_inline(const char *src_buf)
-{
-	size_t len;
-	char dst_buf[DST_BUF_SIZE + 1];
-
-	len = strlen(src_buf);
-	fflush(stdout);
-	while (len > 0) {
-		size_t chunk = (len <= SRC_BUF_SIZE) ? len : SRC_BUF_SIZE;
-		bb_uuencode(dst_buf, src_buf, chunk, bb_uuenc_tbl_base64);
-		xwrite(STDOUT_FILENO, dst_buf, 4 * ((chunk + 2) / 3));
-		src_buf += chunk;
-		len -= chunk;
+		// Encode the buffer we just read in
+		bb_uuencode(dst_buf, src_buf, size, bb_uuenc_tbl_base64);
+		if (fname) {
+			xwrite(STDOUT_FILENO, "\n", 1);
+		} else {
+			src_buf += size;
+			len -= size;
+		}
+		xwrite(STDOUT_FILENO, dst_buf, 4 * ((size + 2) / 3));
 	}
+	if (ENABLE_FEATURE_CLEAN_UP && fname)
+		close(fd);
 }
 
 #if ENABLE_FEATURE_SENDMAIL_NETWORK
@@ -72,7 +73,7 @@
 			bb_error_msg_and_die("child exited (%d)", WEXITSTATUS(err));
 }
 
-static pid_t helper_pid = -1;
+static pid_t helper_pid;
 
 // read stdin, parses first bytes to a number, i.e. server response
 // if code = -1 then just return this number
@@ -107,6 +108,23 @@
 	puts(msg);
 	return check(code, errmsg);
 }
+
+// strip argument of bad chars
+static char *sane(const char *str)
+{
+	if (str) {
+		char *s = (char *)str;
+		char *p = s;
+		while (*s) {
+			if (isalnum(*s) || '_' == *s || '-' == *s || '.' == *s || '@' == *s) {
+				*p++ = *s;
+			}
+			s++;
+		}
+		*p = '\0';
+	}
+	return (char *)str;
+}
 #endif
 
 int sendmail_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
@@ -116,15 +134,15 @@
 	llist_t *bodies = NULL;
 	llist_t *attachments = NULL;
 	const char *from;
-	const char *notify;
+	const char *notify = NULL;
 	const char *subject;
-	const char *charset = "utf-8";
+	const char *charset = NULL;
 #if ENABLE_FEATURE_SENDMAIL_NETWORK
 	const char *wsecs = "10";
 	const char *server = "127.0.0.1";
 	const char *port = NULL;
-	const char *opt_user;
-	const char *opt_pass;
+	const char *opt_user = NULL;
+	const char *opt_pass = NULL;
 	unsigned timeout;
 #endif
 	char *boundary;
@@ -152,9 +170,10 @@
 	//argc -= optind;
 	argv += optind;
 
-//printf("OPTS[%4x]\n", opts);
-
-	// TODO!!!: strip recipients and sender from <>
+	// sanitize user input
+	sane(from);
+	if (!sane(charset))	
+		charset = "utf-8";
 
 	// establish connection
 #if ENABLE_FEATURE_SENDMAIL_NETWORK
@@ -167,25 +186,25 @@
 				bb_error_msg_and_die("no password");
 			}
 		}
-//printf("OPTS[%4x][%s][%s]\n", opts, opt_user, opt_pass);
-//exit(0);
 		// set chat timeout
 		alarm(timeout);
 		// connect to server
 		if (argv[0]) {
 			// if connection helper given
 			// setup vanilla unidirectional pipes interchange
+			int idx;
 			int pipes[4];
 			xpipe(pipes);
 			xpipe(pipes+2);
 			helper_pid = vfork();
 			if (helper_pid < 0)
 				bb_perror_msg_and_die("vfork");
-			xdup2(pipes[(helper_pid)?0:2], STDIN_FILENO);
-			xdup2(pipes[(helper_pid)?3:1], STDOUT_FILENO);
+			idx = (!helper_pid)*2;
+			xdup2(pipes[idx], STDIN_FILENO);
+			xdup2(pipes[3-idx], STDOUT_FILENO);
 			if (ENABLE_FEATURE_CLEAN_UP)
 				for (int i = 4; --i >= 0; )
-					if (pipes[i] > STDOUT_FILENO)
+					if (pipes[i] > STDERR_FILENO) // let us not touch stderr
 						close(pipes[i]);
 			// replace child with connection helper
 			if (!helper_pid) {
@@ -210,11 +229,11 @@
 			check(220, "INIT");
 		}
 		// mail user specified? try modern AUTHentication
-		if (opt_user && (334 == puts_and_check("auth login", -1, "auth login"))) {
-			uuencode_inline(opt_user);
-			puts_and_check("", 334, "AUTH");
-			uuencode_inline(opt_pass);
-			puts_and_check("", 235, "AUTH");
+		if (opt_user && (334 == puts_and_check("auth login\r", -1, "auth login"))) {
+			uuencode(NULL, opt_user);
+			puts_and_check("\r", 334, "AUTH");
+			uuencode(NULL, opt_pass);
+			puts_and_check("\r", 235, "AUTH");
 		// no mail user specified or modern AUTHentication is not supported?
 		} else {
 			// fallback to simple HELO authentication
@@ -224,18 +243,18 @@
 				domain++;
 			else
 				domain = "local";
-			printf("helo %s\n", domain);
+			printf("helo %s\r\n", domain);
 			check(250, "HELO");
 		}
 
 		// set addresses
-		printf("mail from:<%s>\n", from);
+		printf("mail from:<%s>\r\n", from);
 		check(250, "MAIL FROM");
 		for (llist_t *to = recipients; to; to = to->link) {
-			printf("rcpt to:<%s>\n", to->data);
+			printf("rcpt to:<%s>\r\n", sane(to->data));
 			check(250, "RCPT TO");
 		}
-		puts_and_check("data", 354, "DATA");
+		puts_and_check("data\r", 354, "DATA");
 		// no timeout while sending message
 		alarm(0);
 	}
@@ -243,60 +262,64 @@
 
 	// now put message
 	// put address headers
-	printf("From: %s\n", from);
+	printf("From: %s\r\n", from);
 	for (llist_t *to = recipients; to; to = to->link) {
-		printf("To: %s\n", to->data);
+		printf("To: %s\r\n", sane(to->data));
 	}
 	// put encoded subject
 	if (opts & OPT_s) {
 		printf("Subject: =?%s?B?", charset);
-		uuencode_inline(subject);
-		puts("?=");
+		uuencode(NULL, subject);
+		puts("?=\r");
 	}
 	// put notification
 	if (opts & OPT_n) {
 		const char *s = notify;
 		if (!s[0])
 			s = from; // notify sender by default
-		printf("Disposition-Notification-To: %s\n", s);
+		printf("Disposition-Notification-To: %s\r\n", sane(s));
 	}
 	// put common headers and body start
 	//srand(?);
 	boundary = xasprintf("%d-%d-%d", rand(), rand(), rand());
 	printf(
-		"X-Mailer: busybox " BB_VER " sendmail\n"
-		"X-Priority: 3\n"
-		"Message-ID: <%s>\n"
-		"Mime-Version: 1.0\n"
-		"Content-Type: multipart/mixed; boundary=\"%s\"\n"
-		"\n"
-		"--%s\n"
-		"Content-Type: text/plain; charset=%s\n"
-		"%s\n%s"
-		, boundary, boundary, boundary, charset
+		"X-Mailer: busybox " BB_VER " sendmail\r\n"
+		"Message-ID: <%s>\r\n"
+		"Mime-Version: 1.0\r\n"
+		"%smultipart/mixed; boundary=\"%s\"\r\n"
+		"\r\n"
+		"--%s\r\n"
+		"%stext/plain; charset=%s\r\n"
+		"%s\r\n%s"
+		, boundary
+		, "Content-Type: "
+		, boundary, boundary
+		, "Content-Type: "
+		, charset
 		, "Content-Disposition: inline"
-		, "Content-Transfer-Encoding: base64\n"
+		, "Content-Transfer-Encoding: base64\r\n"
 	);
 	// put body(ies)
 	for (llist_t *f = bodies; f; f = f->link) {
-		uuencode(f->data);
+		uuencode(f->data, NULL);
 	}
 	// put attachment(s)
 	for (llist_t *f = attachments; f; f = f->link) {
 		printf(
-			"\n--%s\n"
-			"Content-Type: application/octet-stream\n"
-			"%s; filename=\"%s\"\n"
+			"\r\n--%s\r\n"
+			"%sapplication/octet-stream\r\n"
+			"%s; filename=\"%s\"\r\n"
 			"%s"
 			, boundary
+			, "Content-Type: "
 			, "Content-Disposition: inline"
 			, bb_get_last_path_component_strip(f->data)
-			, "Content-Transfer-Encoding: base64\n"
+			, "Content-Transfer-Encoding: base64\r\n"
 		);
-		uuencode(f->data);
+		uuencode(f->data, NULL);
 	}
 	// put terminator
-	printf("\n--%s--\n\n", boundary);
+	printf("\r\n--%s--\r\n\r\n", boundary);
 	if (ENABLE_FEATURE_CLEAN_UP)
 		free(boundary);
 
@@ -304,8 +327,8 @@
 	// end message and say goodbye
 	if (!(opts & OPT_d)) {
 		alarm(timeout);
-		puts_and_check(".", 250, "BODY");
-		puts_and_check("quit", 221, "QUIT");
+		puts_and_check(".\r", 250, "BODY");
+		puts_and_check("quit\r", 221, "QUIT");
 	}
 #endif
 


_______________________________________________
busybox mailing list
busybox@busybox.net
http://busybox.net/cgi-bin/mailman/listinfo/busybox

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic