[PATCH 2/4] git-imap-send: Add support for SSL.

Subsystems: documentation, kernel build + files below scripts/ (unless maintained elsewhere), the rest

DORMANTno replies

2 messages, 2 authors, 2016-06-15 · open the first message on its own page

[PATCH 2/4] git-imap-send: Add support for SSL.

From: Robert Shearman <hidden>
Date: 2016-06-15 22:44:55

From: Robert Shearman <redacted>

Allow SSL to be used when a imaps:// URL is used for the host name.

Also, automatically use TLS when not using imaps:// by using the IMAP STARTTLS command, if the server supports it.

Tested with Courier and Gimap IMAP servers.

Signed-off-by: Robert Shearman <redacted>
---
 Documentation/git-imap-send.txt |    3 +-
 Makefile                        |    4 +-
 imap-send.c                     |  166 +++++++++++++++++++++++++++++++++++----
 3 files changed, 156 insertions(+), 17 deletions(-)
diff --git a/Documentation/git-imap-send.txt b/Documentation/git-imap-send.txt
index b3d8da3..136c82b 100644
--- a/Documentation/git-imap-send.txt
+++ b/Documentation/git-imap-send.txt
@@ -37,10 +37,11 @@ configuration file (shown with examples):
     Tunnel = "ssh -q user@server.com /usr/bin/imapd ./Maildir 2> /dev/null"
 
 [imap]
-    Host = imap.server.com
+    Host = imap://imap.example.com
     User = bob
     Pass = pwd
     Port = 143
+    sslverify = false
 ..........................
 
 
diff --git a/Makefile b/Makefile
index 4796565..55ec6ee 100644
--- a/Makefile
+++ b/Makefile
@@ -1193,7 +1193,9 @@ endif
 git-%$X: %.o $(GITLIBS)
 	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
 
-git-imap-send$X: imap-send.o $(LIB_FILE)
+git-imap-send$X: imap-send.o $(GITLIBS)
+	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
+		$(LIBS) $(OPENSSL_LINK) $(OPENSSL_LIBSSL)
 
 http.o http-walker.o http-push.o transport.o: http.h
 
diff --git a/imap-send.c b/imap-send.c
index 24d76a7..26d1dba 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -23,6 +23,12 @@
  */
 
 #include "cache.h"
+#ifdef NO_OPENSSL
+typedef void *SSL;
+#else
+# include <openssl/ssl.h>
+# include <openssl/err.h>
+#endif
 
 typedef struct store_conf {
 	char *name;
@@ -129,6 +135,8 @@ typedef struct imap_server_conf {
 	int port;
 	char *user;
 	char *pass;
+	int use_ssl;
+	int ssl_verify;
 } imap_server_conf_t;
 
 typedef struct imap_store_conf {
@@ -148,6 +156,7 @@ typedef struct _list {
 
 typedef struct {
 	int fd;
+	SSL *ssl;
 } Socket_t;
 
 typedef struct {
@@ -201,6 +210,7 @@ enum CAPABILITY {
 	UIDPLUS,
 	LITERALPLUS,
 	NAMESPACE,
+	STARTTLS,
 };
 
 static const char *cap_list[] = {
@@ -208,6 +218,7 @@ static const char *cap_list[] = {
 	"UIDPLUS",
 	"LITERAL+",
 	"NAMESPACE",
+	"STARTTLS",
 };
 
 #define RESP_OK    0
@@ -225,19 +236,101 @@ static const char *Flags[] = {
 	"Deleted",
 };
 
+#ifndef NO_OPENSSL
+static void ssl_socket_perror(const char *func)
+{
+	fprintf(stderr, "%s: %s\n", func, ERR_error_string(ERR_get_error(), 0));
+}
+#endif
+
 static void
 socket_perror( const char *func, Socket_t *sock, int ret )
 {
-	if (ret < 0)
-		perror( func );
+#ifndef NO_OPENSSL
+	if (sock->ssl) {
+		int sslerr = SSL_get_error(sock->ssl, ret);
+		switch (sslerr) {
+		case SSL_ERROR_NONE:
+			break;
+		case SSL_ERROR_SYSCALL:
+			perror("SSL_connect");
+			break;
+		default:
+			ssl_socket_perror("SSL_connect");
+			break;
+		}
+	} else
+#endif
+	{
+		if (ret < 0)
+			perror(func);
+		else
+			fprintf(stderr, "%s: unexpected EOF\n", func);
+	}
+}
+
+static int ssl_socket_connect(Socket_t *sock, int use_tls_only, int verify)
+{
+#ifdef NO_OPENSSL
+	fprintf(stderr, "SSL requested but SSL support not compiled in\n");
+	return -1;
+#else
+	SSL_METHOD *meth;
+	SSL_CTX *ctx;
+	int ret;
+
+	SSL_library_init();
+	SSL_load_error_strings();
+
+	if (use_tls_only)
+		meth = TLSv1_method();
 	else
-		fprintf( stderr, "%s: unexpected EOF\n", func );
+		meth = SSLv23_method();
+
+	if (!meth) {
+		ssl_socket_perror("SSLv23_method");
+		return -1;
+	}
+
+	ctx = SSL_CTX_new(meth);
+
+	if (verify)
+		SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
+
+	if (!SSL_CTX_set_default_verify_paths(ctx)) {
+		ssl_socket_perror("SSL_CTX_set_default_verify_paths");
+		return -1;
+	}
+	sock->ssl = SSL_new(ctx);
+	if (!sock->ssl) {
+		ssl_socket_perror("SSL_new");
+		return -1;
+	}
+	if (!SSL_set_fd(sock->ssl, sock->fd)) {
+		ssl_socket_perror("SSL_set_fd");
+		return -1;
+	}
+
+	ret = SSL_connect(sock->ssl);
+	if (ret <= 0) {
+		socket_perror("SSL_connect", sock, ret);
+		return -1;
+	}
+
+	return 0;
+#endif
 }
 
 static int
 socket_read( Socket_t *sock, char *buf, int len )
 {
-	ssize_t n = xread( sock->fd, buf, len );
+	ssize_t n;
+#ifndef NO_OPENSSL
+	if (sock->ssl)
+		n = SSL_read(sock->ssl, buf, len);
+	else
+#endif
+		n = xread( sock->fd, buf, len );
 	if (n <= 0) {
 		socket_perror( "read", sock, n );
 		close( sock->fd );
@@ -249,7 +342,13 @@ socket_read( Socket_t *sock, char *buf, int len )
 static int
 socket_write( Socket_t *sock, const char *buf, int len )
 {
-	int n = write_in_full( sock->fd, buf, len );
+	int n;
+#ifndef NO_OPENSSL
+	if (sock->ssl)
+		n = SSL_write(sock->ssl, buf, len);
+	else
+#endif
+		n = write_in_full( sock->fd, buf, len );
 	if (n != len) {
 		socket_perror( "write", sock, n );
 		close( sock->fd );
@@ -258,6 +357,17 @@ socket_write( Socket_t *sock, const char *buf, int len )
 	return n;
 }
 
+static void socket_shutdown(Socket_t *sock)
+{
+#ifndef NO_OPENSSL
+	if (sock->ssl) {
+		SSL_shutdown(sock->ssl);
+		SSL_free(sock->ssl);
+	}
+#endif
+	close(sock->fd);
+}
+
 /* simple line buffering */
 static int
 buffer_gets( buffer_t * b, char **s )
@@ -875,7 +985,7 @@ imap_close_server( imap_store_t *ictx )
 
 	if (imap->buf.sock.fd != -1) {
 		imap_exec( ictx, NULL, "LOGOUT" );
-		close( imap->buf.sock.fd );
+		socket_shutdown( &imap->buf.sock );
 	}
 	free_list( imap->ns_personal );
 	free_list( imap->ns_other );
@@ -906,6 +1016,7 @@ imap_open_store( imap_server_conf_t *srvc )
 
 	ctx->imap = imap = xcalloc( sizeof(*imap), 1 );
 	imap->buf.sock.fd = -1;
+	imap->buf.sock.ssl = NULL;
 	imap->in_progress_append = &imap->in_progress;
 
 	/* open connection to IMAP server */
@@ -958,10 +1069,15 @@ imap_open_store( imap_server_conf_t *srvc )
 			perror( "connect" );
 			goto bail;
 		}
-		imap_info( "ok\n" );
-
+		
 		imap->buf.sock.fd = s;
 
+		if (srvc->use_ssl &&
+		    ssl_socket_connect(&imap->buf.sock, 0, srvc->ssl_verify)) {
+			close(s);
+			goto bail;
+		}
+		imap_info( "ok\n" );
 	}
 
 	/* read the greeting string */
@@ -986,7 +1102,18 @@ imap_open_store( imap_server_conf_t *srvc )
 		goto bail;
 
 	if (!preauth) {
-
+#ifndef NO_OPENSSL
+		if (!srvc->use_ssl && CAP(STARTTLS)) {
+			if (imap_exec(ctx, 0, "STARTTLS") != RESP_OK)
+				goto bail;
+			if (ssl_socket_connect(&imap->buf.sock, 1,
+					       srvc->ssl_verify))
+				goto bail;
+			/* capabilities may have changed, so get the new capabilities */
+			if (imap_exec(ctx, 0, "CAPABILITY") != RESP_OK)
+				goto bail;
+		}
+#endif
 		imap_info ("Logging in...\n");
 		if (!srvc->user) {
 			fprintf( stderr, "Skipping server %s, no user\n", srvc->host );
@@ -1014,7 +1141,9 @@ imap_open_store( imap_server_conf_t *srvc )
 			fprintf( stderr, "Skipping account %s@%s, server forbids LOGIN\n", srvc->user, srvc->host );
 			goto bail;
 		}
-		imap_warn( "*** IMAP Warning *** Password is being sent in the clear\n" );
+		if (!imap->buf.sock.ssl)
+			imap_warn( "*** IMAP Warning *** Password is being "
+				   "sent in the clear\n" );
 		if (imap_exec( ctx, NULL, "LOGIN \"%s\" \"%s\"", srvc->user, srvc->pass ) != RESP_OK) {
 			fprintf( stderr, "IMAP error: LOGIN failed\n" );
 			goto bail;
@@ -1242,6 +1371,8 @@ static imap_server_conf_t server =
 	0,	/* port */
 	NULL,	/* user */
 	NULL,	/* pass */
+	0,   	/* use_ssl */
+	1,   	/* ssl_verify */
 };
 
 static char *imap_folder;
@@ -1262,11 +1393,11 @@ git_imap_config(const char *key, const char *val, void *cb)
 	if (!strcmp( "folder", key )) {
 		imap_folder = xstrdup( val );
 	} else if (!strcmp( "host", key )) {
-		{
-			if (!prefixcmp(val, "imap:"))
-				val += 5;
-			if (!server.port)
-				server.port = 143;
+		if (!prefixcmp(val, "imap:"))
+			val += 5;
+		else if (!prefixcmp(val, "imaps:")) {
+			val += 6;
+			server.use_ssl = 1;
 		}
 		if (!prefixcmp(val, "//"))
 			val += 2;
@@ -1280,6 +1411,8 @@ git_imap_config(const char *key, const char *val, void *cb)
 		server.port = git_config_int( key, val );
 	else if (!strcmp( "tunnel", key ))
 		server.tunnel = xstrdup( val );
+	else if (!strcmp( "ssl_verify", key ))
+		server.ssl_verify = git_config_bool( key, val );
 	return 0;
 }
 
@@ -1300,6 +1433,9 @@ main(int argc, char **argv)
 	setup_git_directory_gently(&nongit_ok);
 	git_config(git_imap_config, NULL);
 
+	if (!server.port)
+		server.port = server.use_ssl ? 993 : 143;
+
 	if (!imap_folder) {
 		fprintf( stderr, "no imap store specified\n" );
 		return 1;
-- 
1.5.6.2.224.g26efb.dirty

Re: [PATCH 2/4] git-imap-send: Add support for SSL.

From: Mike Hommey <hidden>
Date: 2016-06-15 22:44:55

On Wed, Jul 09, 2008 at 10:29:00PM +0100, Robert Shearman wrote:
From: Robert Shearman <redacted>

Allow SSL to be used when a imaps:// URL is used for the host name.

Also, automatically use TLS when not using imaps:// by using the IMAP STARTTLS command, if the server supports it.

Tested with Courier and Gimap IMAP servers.
Please do an alternative implementation using GnuTLS. Why ? Because curl
can be built against openssl or gnutls, and it would be sad if git
ended up depending on both indirectly.

Mike
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help