shithub: riscv

Download patch

ref: cb1dc365c292e82a17b2e0a231b248b84773a14c
parent: efddf485006559bef5e8791b637e742d865df434
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Wed Mar 15 20:05:08 EDT 2017

upas/fs: fix memory leaks in tls code, handle tls in a common wraptls() function

--- a/sys/src/cmd/upas/fs/dat.h
+++ b/sys/src/cmd/upas/fs/dat.h
@@ -216,6 +216,8 @@
 char		*flagmessages(int, char**);
 void		digestmessage(Mailbox*, Message*);
 
+int		wraptls(int);
+
 void		eprint(char*, ...);
 void		iprint(char *, ...);
 int		newid(void);
--- a/sys/src/cmd/upas/fs/imap.c
+++ b/sys/src/cmd/upas/fs/imap.c
@@ -60,8 +60,6 @@
 	int	nuid;
 	int	muid;
 
-	Thumbprint *thumb;
-
 	/* open network connection */
 	Biobuf	bin;
 	Biobuf	bout;
@@ -760,44 +758,6 @@
 	return buf;
 }
 
-static int
-starttls(Imap *imap, TLSconn *tls)
-{
-	char buf[Pathlen];
-	uchar digest[SHA1dlen];
-	int sfd, fd;
-
-	memset(tls, 0, sizeof *tls);
-	sfd = tlsClient(imap->fd, tls);
-	if(sfd < 0){
-		werrstr("tlsClient: %r");
-		return -1;
-	}
-	if(tls->cert == nil || tls->certlen <= 0){
-		close(sfd);
-		werrstr("server did not provide TLS certificate");
-		return -1;
-	}
-	sha1(tls->cert, tls->certlen, digest, nil);
-	if(!imap->thumb || !okThumbprint(digest, imap->thumb)){
-		close(sfd);
-		werrstr("server certificate %.*H not recognized",
-			SHA1dlen, digest);
-		return -1;
-	}
-	close(imap->fd);
-	imap->fd = sfd;
-
-	if(imap->flags & Fdebug){
-		snprint(buf, sizeof buf, "%s/ctl", tls->dir);
-		fd = open(buf, OWRITE);
-		fprint(fd, "debug");
-		close(fd);
-	}
-
-	return 1;
-}
-
 static void
 imap4disconnect(Imap *imap)
 {
@@ -806,8 +766,10 @@
 		Bterm(&imap->bout);
 		imap->binit = 0;
 	}
-	close(imap->fd);
-	imap->fd = -1;
+	if(imap->fd >= 0){
+		close(imap->fd);
+		imap->fd = -1;
+	}
 }
 
 char*
@@ -827,7 +789,6 @@
 imap4dial(Imap *imap)
 {
 	char *err, *port;
-	TLSconn conn;
 
 	if(imap->fd >= 0){
 		imap4cmd(imap, "noop");
@@ -841,9 +802,8 @@
 		port = "imap";
 	if((imap->fd = dial(netmkaddr(imap->host, "net", port), 0, 0, 0)) < 0)
 		return imaperrstr(imap->host, port);
-	if(imap->flags & Fssl && starttls(imap, &conn) == -1){
+	if(imap->flags & Fssl && (imap->fd = wraptls(imap->fd)) < 0){
 		err = imaperrstr(imap->host, port);
-		free(conn.cert);
 		imap4disconnect(imap);
 		return err;
 	}
@@ -1074,7 +1034,6 @@
 static char*
 imap4ctl(Mailbox *mb, int argc, char **argv)
 {
-	char *a, *b;
 	Imap *imap;
 
 	imap = mb->aux;
@@ -1085,26 +1044,6 @@
 		imap->flags ^= Fdebug;
 		return nil;
 	}
-	if(strcmp(argv[0], "thumbprint") == 0){
-		if(imap->thumb){
-			freeThumbprints(imap->thumb);
-			imap->thumb = 0;
-		}
-		a = "/sys/lib/tls/mail";
-		b = "/sys/lib/tls/mail.exclude";
-		switch(argc){
-		default:
-			return Eimap4ctl;
-		case 4:
-			b = argv[2];
-		case 3:
-			a = argv[1];
-		case 2:
-			break;
-		}
-		imap->thumb = initThumbprints(a, b);
-		return nil;
-	}
 	if(argc == 2 && strcmp(argv[0], "uid") == 0){
 		uvlong l;
 		Message *m;
@@ -1253,9 +1192,6 @@
 	else
 		imap->mbox = strdup(f[4]);
 	mkmbox(imap, mb->path, mb->path + sizeof mb->path);
-	if(imap->flags & Fssl)
-		imap->thumb = initThumbprints("/sys/lib/tls/mail", "/sys/lib/tls/mail.exclude");
-
 	mb->aux = imap;
 	mb->sync = imap4sync;
 	mb->close = imap4close;
--- a/sys/src/cmd/upas/fs/mkfile
+++ b/sys/src/cmd/upas/fs/mkfile
@@ -18,6 +18,7 @@
 	remove.$O\
 	rename.$O\
 	strtotm.$O\
+	tls.$O\
 
 LIB=../common/libcommon.a$O\
 
--- a/sys/src/cmd/upas/fs/pop3.c
+++ b/sys/src/cmd/upas/fs/pop3.c
@@ -32,7 +32,6 @@
 	Biobuf	bout;
 	int	fd;
 	char	*lastline;		/* from Brdstr */
-	Thumbprint *thumb;
 };
 
 static int
@@ -120,38 +119,6 @@
 	return 0;
 }
 
-static char*
-pop3pushtls(Pop *pop)
-{
-	int fd;
-	uchar digest[SHA1dlen];
-	TLSconn conn;
-
-	memset(&conn, 0, sizeof conn);
-	// conn.trace = pop3log;
-	fd = tlsClient(pop->fd, &conn);
-	if(fd < 0)
-		return "tls error";
-	if(conn.cert==nil || conn.certlen <= 0){
-		close(fd);
-		return "server did not provide TLS certificate";
-	}
-	sha1(conn.cert, conn.certlen, digest, nil);
-	if(!pop->thumb || !okThumbprint(digest, pop->thumb)){
-		close(fd);
-		free(conn.cert);
-		eprint("pop3: server certificate %.*H not recognized\n", SHA1dlen, digest);
-		return "bad server certificate";
-	}
-	free(conn.cert);
-	close(pop->fd);
-	pop->fd = fd;
-	pop->encrypted = 1;
-	Binit(&pop->bin, pop->fd, OREAD);
-	Binit(&pop->bout, pop->fd, OWRITE);
-	return nil;
-}
-
 /*
  *  get capability list, possibly start tls
  */
@@ -182,8 +149,13 @@
 		pop3cmd(pop, "STLS");
 		if(!isokay(s = pop3resp(pop)))
 			return s;
-		if((s = pop3pushtls(pop)) != nil)
-			return s;
+		Bterm(&pop->bin);
+		Bterm(&pop->bout);
+		if((pop->fd = wraptls(pop->fd)) < 0)
+			return geterrstr();
+		pop->encrypted = 1;
+		Binit(&pop->bin, pop->fd, OREAD);
+		Binit(&pop->bout, pop->fd, OWRITE);
 	}
 	return nil;
 }
@@ -265,15 +237,11 @@
 
 	if((pop->fd = dial(netmkaddr(pop->host, "net", pop->needssl ? "pop3s" : "pop3"), 0, 0, 0)) < 0)
 		return geterrstr();
-
-	if(pop->needssl){
-		if((err = pop3pushtls(pop)) != nil)
-			return err;
-	}else{
-		Binit(&pop->bin, pop->fd, OREAD);
-		Binit(&pop->bout, pop->fd, OWRITE);
-	}
-
+	if(pop->needssl && (pop->fd = wraptls(pop->fd)) < 0)
+		return geterrstr();
+	pop->encrypted = pop->needssl;
+	Binit(&pop->bin, pop->fd, OREAD);
+	Binit(&pop->bout, pop->fd, OWRITE);
 	if(err = pop3login(pop)) {
 		close(pop->fd);
 		return err;
@@ -607,11 +575,6 @@
 		return nil;
 	}
 
-	if(argc==1 && strcmp(argv[0], "thumbprint")==0){
-		if(pop->thumb)
-			freeThumbprints(pop->thumb);
-		pop->thumb = initThumbprints("/sys/lib/tls/mail", "/sys/lib/tls/mail.exclude");
-	}
 	if(strcmp(argv[0], "refresh")==0){
 		if(argc==1){
 			pop->refreshtime = 60;
@@ -693,8 +656,6 @@
 	pop->needtls = poptls || apoptls;
 	pop->refreshtime = 60;
 	pop->notls = popnotls || apopnotls;
-	pop->thumb = initThumbprints("/sys/lib/tls/mail", "/sys/lib/tls/mail.exclude");
-
 	mkmbox(pop, mb->path, mb->path + sizeof mb->path);
 	mb->aux = pop;
 	mb->sync = pop3sync;
@@ -704,4 +665,3 @@
 	mb->addfrom = 1;
 	return nil;
 }
-
--- /dev/null
+++ b/sys/src/cmd/upas/fs/tls.c
@@ -1,0 +1,39 @@
+#include "common.h"
+#include <libsec.h>
+#include <auth.h>
+#include "dat.h"
+
+int
+wraptls(int ofd)
+{
+	uchar digest[SHA1dlen];
+	Thumbprint *thumb;
+	TLSconn conn;
+	int fd;
+
+	memset(&conn, 0, sizeof conn);
+	fd = tlsClient(ofd, &conn);
+	if(fd < 0){
+		close(ofd);
+		return -1;
+	}
+	thumb = initThumbprints("/sys/lib/tls/mail", "/sys/lib/tls/mail.exclude");
+	if(thumb != nil){
+		if(conn.cert == nil || conn.certlen <= 0){
+			werrstr("server did not provide TLS certificate");
+			goto Err;
+		}
+		sha1(conn.cert, conn.certlen, digest, nil);
+		if(!okThumbprint(digest, thumb)){
+			werrstr("server certificate %.*H not recognized",
+				SHA1dlen, digest);
+		Err:
+			close(fd);
+			fd = -1;
+		}
+		freeThumbprints(thumb);
+	}
+	free(conn.cert);
+	free(conn.sessionID);
+	return fd;
+}