git: 9front

Download patch

ref: 2ae6e9d9c1c8c3cfd0a0b4c4e728ad714e182d92
parent: b5f879f15341b07141b71c601f95a9093196f349
author: cinap_lenrek <cinap_lenrek@gmx.de>
date: Wed Jun 12 19:39:41 EDT 2013

smtp: add SMTPS support (-t)

--- a/sys/man/8/smtp
+++ b/sys/man/8/smtp
@@ -6,7 +6,7 @@
 .ti -0.5i
 .B upas/smtp
 [
-.B -aAdfips
+.B -aAdfipst
 ] [
 .B -b
 .I busted-mx
@@ -118,6 +118,9 @@
 .B -s
 if the server supports the ESMTP extension to use TLS encryption, turn it on for
 this session.  See RFC3207 for details.
+.TP
+.B -t
+preemtively establish TLS connection before SMTP handshake (SMTPS).
 .TP
 .B -u
 specify a user name to be used in authentication.  The default name is
--- a/sys/src/cmd/upas/smtp/smtp.c
+++ b/sys/src/cmd/upas/smtp/smtp.c
@@ -6,6 +6,7 @@
 #include <auth.h>
 
 static	char*	connect(char*);
+static	char*	wraptls(void);
 static	char*	dotls(char*);
 static	char*	doauth(char*);
 
@@ -26,7 +27,7 @@
 void	putcrnl(char*, int);
 void	quit(char*);
 char*	rcptto(char*);
-char	*rewritezone(char *);
+char*	rewritezone(char *);
 
 #define Retry	"Retry, Temporary Failure"
 #define Giveup	"Permanent Failure"
@@ -151,6 +152,9 @@
 	case 's':
 		trysecure = 1;
 		break;
+	case 't':
+		trysecure = 2;
+		break;
 	case 'u':
 		user = EARGF(usage());
 		break;
@@ -217,8 +221,10 @@
 	/* 10 minutes to get through the initial handshake */
 	atnotify(timeout, 1);
 	alarm(10*alarmscale);
-	if((rv = hello(hellodomain, 0)) != 0)
+	if(trysecure > 1 && (rv = wraptls()) != nil)
 		goto error;
+	if((rv = hello(hellodomain, trysecure > 1)) != 0)
+		goto error;
 	alarm(10*alarmscale);
 	if((rv = mailfrom(s_to_c(from))) != 0)
 		goto error;
@@ -313,13 +319,8 @@
 static char smtpthumbs[] =	"/sys/lib/tls/smtp";
 static char smtpexclthumbs[] =	"/sys/lib/tls/smtp.exclude";
 
-/*
- *  exchange names with remote host, attempt to
- *  enable encryption and optionally authenticate.
- *  not fatal if we can't.
- */
 static char *
-dotls(char *me)
+wraptls(void)
 {
 	TLSconn *c;
 	Thumbprint *goodcerts;
@@ -327,33 +328,27 @@
 	int fd;
 	uchar hash[SHA1dlen];
 
-	c = mallocz(sizeof(*c), 1);	/* Note: not freed on success */
+	c = mallocz(sizeof(*c), 1);
 	if (c == nil)
 		return Giveup;
 
-	dBprint("STARTTLS\r\n");
-	if (getreply() != 2)
-		return Giveup;
-
 	fd = tlsClient(Bfildes(&bout), c);
 	if (fd < 0) {
 		syslog(0, "smtp", "tlsClient to %q: %r", ddomain);
+		free(c);
 		return Giveup;
 	}
 	goodcerts = initThumbprints(smtpthumbs, smtpexclthumbs);
 	if (goodcerts == nil) {
-		free(c);
-		close(fd);
 		syslog(0, "smtp", "bad thumbprints in %s", smtpthumbs);
+		close(fd);
+		free(c);
 		return Giveup;		/* how to recover? TLS is started */
 	}
-
 	/* compute sha1 hash of remote's certificate, see if we know it */
 	sha1(c->cert, c->certlen, hash, nil);
 	if (!okThumbprint(hash, goodcerts)) {
 		/* TODO? if not excluded, add hash to thumb list */
-		free(c);
-		close(fd);
 		h = malloc(2*sizeof hash + 1);
 		if (h != nil) {
 			enc16(h, 2*sizeof hash + 1, hash, sizeof hash);
@@ -363,9 +358,12 @@
 				h, ddomain);
 			free(h);
 		}
+		close(fd);
+		free(c);
 		return Giveup;		/* how to recover? TLS is started */
 	}
 	freeThumbprints(goodcerts);
+	free(c);
 	Bterm(&bin);
 	Bterm(&bout);
 
@@ -378,6 +376,27 @@
 	Binit(&bout, fd, OWRITE);
 
 	syslog(0, "smtp", "started TLS to %q", ddomain);
+	return nil;
+}
+
+/*
+ *  exchange names with remote host, attempt to
+ *  enable encryption and optionally authenticate.
+ *  not fatal if we can't.
+ */
+static char *
+dotls(char *me)
+{
+	char *err;
+
+	dBprint("STARTTLS\r\n");
+	if (getreply() != 2)
+		return Giveup;
+
+	err = wraptls();
+	if (err != nil)
+		return err;
+
 	return(hello(me, 1));
 }
 
--