1
0
Fork 0
mirror of https://github.com/git/git.git synced 2024-05-11 14:46:08 +02:00

git-imap-send: Support SSL

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 <robertshearman@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Robert Shearman 2008-07-09 22:29:00 +01:00 committed by Junio C Hamano
parent a0406b94d5
commit 684ec6c63c
4 changed files with 156 additions and 16 deletions

View File

@ -37,10 +37,11 @@ configuration file (shown with examples):
Tunnel = "ssh -q user@server.com /usr/bin/imapd ./Maildir 2> /dev/null" Tunnel = "ssh -q user@server.com /usr/bin/imapd ./Maildir 2> /dev/null"
[imap] [imap]
Host = imap.server.com Host = imap://imap.example.com
User = bob User = bob
Pass = pwd Pass = pwd
Port = 143 Port = 143
sslverify = false
.......................... ..........................

View File

@ -1208,7 +1208,9 @@ endif
git-%$X: %.o $(GITLIBS) git-%$X: %.o $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) $(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 http.o http-walker.o http-push.o transport.o: http.h

View File

@ -99,6 +99,11 @@
#include <iconv.h> #include <iconv.h>
#endif #endif
#ifndef NO_OPENSSL
#include <openssl/ssl.h>
#include <openssl/err.h>
#endif
/* On most systems <limits.h> would have given us this, but /* On most systems <limits.h> would have given us this, but
* not on some systems (e.g. GNU/Hurd). * not on some systems (e.g. GNU/Hurd).
*/ */

View File

@ -23,6 +23,9 @@
*/ */
#include "cache.h" #include "cache.h"
#ifdef NO_OPENSSL
typedef void *SSL;
#endif
typedef struct store_conf { typedef struct store_conf {
char *name; char *name;
@ -129,6 +132,8 @@ typedef struct imap_server_conf {
int port; int port;
char *user; char *user;
char *pass; char *pass;
int use_ssl;
int ssl_verify;
} imap_server_conf_t; } imap_server_conf_t;
typedef struct imap_store_conf { typedef struct imap_store_conf {
@ -148,6 +153,7 @@ typedef struct _list {
typedef struct { typedef struct {
int fd; int fd;
SSL *ssl;
} Socket_t; } Socket_t;
typedef struct { typedef struct {
@ -201,6 +207,7 @@ enum CAPABILITY {
UIDPLUS, UIDPLUS,
LITERALPLUS, LITERALPLUS,
NAMESPACE, NAMESPACE,
STARTTLS,
}; };
static const char *cap_list[] = { static const char *cap_list[] = {
@ -208,6 +215,7 @@ static const char *cap_list[] = {
"UIDPLUS", "UIDPLUS",
"LITERAL+", "LITERAL+",
"NAMESPACE", "NAMESPACE",
"STARTTLS",
}; };
#define RESP_OK 0 #define RESP_OK 0
@ -225,19 +233,101 @@ static const char *Flags[] = {
"Deleted", "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 static void
socket_perror( const char *func, Socket_t *sock, int ret ) socket_perror( const char *func, Socket_t *sock, int ret )
{ {
if (ret < 0) #ifndef NO_OPENSSL
perror( func ); 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 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 static int
socket_read( Socket_t *sock, char *buf, int len ) 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) { if (n <= 0) {
socket_perror( "read", sock, n ); socket_perror( "read", sock, n );
close( sock->fd ); close( sock->fd );
@ -249,7 +339,13 @@ socket_read( Socket_t *sock, char *buf, int len )
static int static int
socket_write( Socket_t *sock, const char *buf, int len ) 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) { if (n != len) {
socket_perror( "write", sock, n ); socket_perror( "write", sock, n );
close( sock->fd ); close( sock->fd );
@ -258,6 +354,17 @@ socket_write( Socket_t *sock, const char *buf, int len )
return n; 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 */ /* simple line buffering */
static int static int
buffer_gets( buffer_t * b, char **s ) buffer_gets( buffer_t * b, char **s )
@ -875,7 +982,7 @@ imap_close_server( imap_store_t *ictx )
if (imap->buf.sock.fd != -1) { if (imap->buf.sock.fd != -1) {
imap_exec( ictx, NULL, "LOGOUT" ); imap_exec( ictx, NULL, "LOGOUT" );
close( imap->buf.sock.fd ); socket_shutdown( &imap->buf.sock );
} }
free_list( imap->ns_personal ); free_list( imap->ns_personal );
free_list( imap->ns_other ); free_list( imap->ns_other );
@ -958,10 +1065,15 @@ imap_open_store( imap_server_conf_t *srvc )
perror( "connect" ); perror( "connect" );
goto bail; goto bail;
} }
imap_info( "ok\n" );
imap->buf.sock.fd = s; 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 */ /* read the greeting string */
@ -986,7 +1098,18 @@ imap_open_store( imap_server_conf_t *srvc )
goto bail; goto bail;
if (!preauth) { 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"); imap_info ("Logging in...\n");
if (!srvc->user) { if (!srvc->user) {
fprintf( stderr, "Skipping server %s, no user\n", srvc->host ); fprintf( stderr, "Skipping server %s, no user\n", srvc->host );
@ -1014,7 +1137,9 @@ imap_open_store( imap_server_conf_t *srvc )
fprintf( stderr, "Skipping account %s@%s, server forbids LOGIN\n", srvc->user, srvc->host ); fprintf( stderr, "Skipping account %s@%s, server forbids LOGIN\n", srvc->user, srvc->host );
goto bail; 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) { if (imap_exec( ctx, NULL, "LOGIN \"%s\" \"%s\"", srvc->user, srvc->pass ) != RESP_OK) {
fprintf( stderr, "IMAP error: LOGIN failed\n" ); fprintf( stderr, "IMAP error: LOGIN failed\n" );
goto bail; goto bail;
@ -1242,6 +1367,8 @@ static imap_server_conf_t server =
0, /* port */ 0, /* port */
NULL, /* user */ NULL, /* user */
NULL, /* pass */ NULL, /* pass */
0, /* use_ssl */
1, /* ssl_verify */
}; };
static char *imap_folder; static char *imap_folder;
@ -1262,11 +1389,11 @@ git_imap_config(const char *key, const char *val, void *cb)
if (!strcmp( "folder", key )) { if (!strcmp( "folder", key )) {
imap_folder = xstrdup( val ); imap_folder = xstrdup( val );
} else if (!strcmp( "host", key )) { } else if (!strcmp( "host", key )) {
{ if (!prefixcmp(val, "imap:"))
if (!prefixcmp(val, "imap:")) val += 5;
val += 5; else if (!prefixcmp(val, "imaps:")) {
if (!server.port) val += 6;
server.port = 143; server.use_ssl = 1;
} }
if (!prefixcmp(val, "//")) if (!prefixcmp(val, "//"))
val += 2; val += 2;
@ -1280,6 +1407,8 @@ git_imap_config(const char *key, const char *val, void *cb)
server.port = git_config_int( key, val ); server.port = git_config_int( key, val );
else if (!strcmp( "tunnel", key )) else if (!strcmp( "tunnel", key ))
server.tunnel = xstrdup( val ); server.tunnel = xstrdup( val );
else if (!strcmp( "sslverify", key ))
server.ssl_verify = git_config_bool( key, val );
return 0; return 0;
} }
@ -1300,6 +1429,9 @@ main(int argc, char **argv)
setup_git_directory_gently(&nongit_ok); setup_git_directory_gently(&nongit_ok);
git_config(git_imap_config, NULL); git_config(git_imap_config, NULL);
if (!server.port)
server.port = server.use_ssl ? 993 : 143;
if (!imap_folder) { if (!imap_folder) {
fprintf( stderr, "no imap store specified\n" ); fprintf( stderr, "no imap store specified\n" );
return 1; return 1;