[Commits] [SCM] claws branch, master, updated. 3.10.0-9-g78965aa

colin at claws-mail.org colin at claws-mail.org
Wed May 28 21:19:42 CEST 2014


The branch master of project "claws" (Claws Mail) has been updated
       via  78965aa3b773324d9c1102d686e533379debd149 (commit)
      from  7c1bb13b902e8974b364a6e92d88e48c3a2fdcd0 (commit)


- Log -----------------------------------------------------------------
commit 78965aa3b773324d9c1102d686e533379debd149
Author: Colin Leroy <colin at colino.net>
Date:   Wed May 28 21:18:34 2014 +0200

    Add a per-account preference to allow automatically accepting unknown
    and changed SSL certificates, if they're valid (that is, if the root CA
    is trusted by the distro).

diff --git a/src/common/session.c b/src/common/session.c
index 25038c9..f1af55b 100644
--- a/src/common/session.c
+++ b/src/common/session.c
@@ -165,6 +165,8 @@ static gint session_connect_cb(SockInfo *sock, gpointer data)
 	session->sock = sock;
 	sock->account = session->account;
 	sock->is_smtp = session->is_smtp;
+	sock->ssl_cert_auto_accept = session->ssl_cert_auto_accept;
+
 #ifdef USE_GNUTLS
 	sock->gnutls_priority = session->gnutls_priority;
 
@@ -373,6 +375,8 @@ gint session_start_tls(Session *session)
 
 	nb_mode = sock_is_nonblocking_mode(session->sock);
 
+	session->sock->ssl_cert_auto_accept = session->ssl_cert_auto_accept;
+
 	if (nb_mode)
 		sock_set_nonblocking_mode(session->sock, FALSE);
 
diff --git a/src/common/session.h b/src/common/session.h
index 00675c4..98ae50e 100644
--- a/src/common/session.h
+++ b/src/common/session.h
@@ -150,10 +150,10 @@ struct _Session
 	gpointer recv_data_notify_data;
 	gpointer send_data_progressive_notify_data;
 	gpointer send_data_notify_data;
-	
+
 	const void *account;
 	gboolean is_smtp;
-
+	gboolean ssl_cert_auto_accept;
 	gint ping_tag;
 
 #ifdef USE_GNUTLS
diff --git a/src/common/socket.h b/src/common/socket.h
index 39c6e2e..59cb230 100644
--- a/src/common/socket.h
+++ b/src/common/socket.h
@@ -76,9 +76,10 @@ struct _SockInfo
 	SockFunc callback;
 	GIOCondition condition;
 	gchar *canonical_name;
-	
+
 	const void *account;
 	gboolean is_smtp;
+	gboolean ssl_cert_auto_accept;
 };
 
 void refresh_resolvers			(void);
diff --git a/src/common/ssl.c b/src/common/ssl.c
index b1812f9..1c7c335 100644
--- a/src/common/ssl.c
+++ b/src/common/ssl.c
@@ -371,7 +371,8 @@ gboolean ssl_init_socket_with_method(SockInfo *sockinfo, SSLMethod method)
 		return FALSE;
 	}
 
-	if (!ssl_certificate_check_chain(certs, cert_list_length, sockinfo->hostname, sockinfo->port)) {
+	if (!ssl_certificate_check_chain(certs, cert_list_length, sockinfo->hostname, sockinfo->port,
+					 sockinfo->ssl_cert_auto_accept)) {
 		for (i = 0; i < cert_list_length; i++)
 			gnutls_x509_crt_deinit(certs[i]);
 		g_free(certs);
diff --git a/src/common/ssl_certificate.c b/src/common/ssl_certificate.c
index b48d4d4..870ceb0 100644
--- a/src/common/ssl_certificate.c
+++ b/src/common/ssl_certificate.c
@@ -603,6 +603,17 @@ static guint check_cert(SSLCertificate *cert)
 
 }
 
+static gboolean ssl_certificate_is_valid(SSLCertificate *cert, guint status)
+{
+	gchar *str_status = ssl_certificate_check_signer(cert, status);
+
+	if (str_status != NULL) {
+		g_free(str_status);
+		return FALSE;
+	}
+	return ssl_certificate_check_subject_cn(cert);
+}
+
 char *ssl_certificate_check_signer (SSLCertificate *cert, guint status) 
 {
 	gnutls_x509_crt_t x509_cert = cert ? cert->x509_cert : NULL;
@@ -667,17 +678,20 @@ static void ssl_certificate_save_chain(gnutls_x509_crt_t *certs, gint len, const
 		fclose(fp);
 }
 
-gboolean ssl_certificate_check (gnutls_x509_crt_t x509_cert, guint status, const gchar *host, gushort port)
+gboolean ssl_certificate_check (gnutls_x509_crt_t x509_cert, guint status, 
+				const gchar *host, gushort port,
+				gboolean accept_if_valid)
 {
 	SSLCertificate *current_cert = NULL;
 	SSLCertificate *known_cert;
 	SSLCertHookData cert_hook_data;
 	gchar *fingerprint;
 	size_t n;
-	unsigned char md[128];	
+	unsigned char md[128];
+	gboolean valid = FALSE;
 
 	current_cert = ssl_certificate_new(x509_cert, host, port);
-	
+
 	if (current_cert == NULL) {
 		debug_print("Buggy certificate !\n");
 		return FALSE;
@@ -693,14 +707,25 @@ gboolean ssl_certificate_check (gnutls_x509_crt_t x509_cert, guint status, const
 
 	g_free(fingerprint);
 
+	if (accept_if_valid)
+		valid = ssl_certificate_is_valid(current_cert, status);
+	else
+		valid = FALSE; /* Force check */
+
 	if (known_cert == NULL) {
+		if (valid) {
+			ssl_certificate_save(current_cert);
+			ssl_certificate_destroy(current_cert);
+			return TRUE;
+		}
+
 		cert_hook_data.cert = current_cert;
 		cert_hook_data.old_cert = NULL;
 		cert_hook_data.expired = FALSE;
 		cert_hook_data.accept = FALSE;
-		
+
 		hooks_invoke(SSLCERT_ASK_HOOKLIST, &cert_hook_data);
-		
+
 		if (!cert_hook_data.accept) {
 			ssl_certificate_destroy(current_cert);
 			return FALSE;
@@ -710,11 +735,18 @@ gboolean ssl_certificate_check (gnutls_x509_crt_t x509_cert, guint status, const
 			return TRUE;
 		}
 	} else if (!ssl_certificate_compare (current_cert, known_cert)) {
+		if (valid) {
+			ssl_certificate_save(current_cert);
+			ssl_certificate_destroy(current_cert);
+			ssl_certificate_destroy(known_cert);
+			return TRUE;
+		}
+
 		cert_hook_data.cert = current_cert;
 		cert_hook_data.old_cert = known_cert;
 		cert_hook_data.expired = FALSE;
 		cert_hook_data.accept = FALSE;
-		
+
 		hooks_invoke(SSLCERT_ASK_HOOKLIST, &cert_hook_data);
 
 		if (!cert_hook_data.accept) {
@@ -729,22 +761,22 @@ gboolean ssl_certificate_check (gnutls_x509_crt_t x509_cert, guint status, const
 		}
 	} else if (gnutls_x509_crt_get_expiration_time(current_cert->x509_cert) < time(NULL)) {
 		gchar *tmp = g_strdup_printf("%s:%d", current_cert->host, current_cert->port);
-		
+
 		if (warned_expired == NULL)
 			warned_expired = g_hash_table_new(g_str_hash, g_str_equal);
-		
+
 		if (g_hash_table_lookup(warned_expired, tmp)) {
 			g_free(tmp);
 			ssl_certificate_destroy(current_cert);
 			ssl_certificate_destroy(known_cert);
 			return TRUE;
 		}
-			
+
 		cert_hook_data.cert = current_cert;
 		cert_hook_data.old_cert = NULL;
 		cert_hook_data.expired = TRUE;
 		cert_hook_data.accept = FALSE;
-		
+
 		hooks_invoke(SSLCERT_ASK_HOOKLIST, &cert_hook_data);
 
 		if (!cert_hook_data.accept) {
@@ -765,7 +797,9 @@ gboolean ssl_certificate_check (gnutls_x509_crt_t x509_cert, guint status, const
 	return TRUE;
 }
 
-gboolean ssl_certificate_check_chain(gnutls_x509_crt_t *certs, gint chain_len, const gchar *host, gushort port)
+gboolean ssl_certificate_check_chain(gnutls_x509_crt_t *certs, gint chain_len,
+				     const gchar *host, gushort port,
+				     gboolean accept_if_valid)
 {
 	int ncas = 0;
 	gnutls_x509_crt_t *cas = NULL;
@@ -798,7 +832,8 @@ gboolean ssl_certificate_check_chain(gnutls_x509_crt_t *certs, gint chain_len, c
                              GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT,
                              &status);
 
-	result = ssl_certificate_check(certs[0], status, host, port);
+	result = ssl_certificate_check(certs[0], status, host, port,
+					accept_if_valid);
 
 	if (result == TRUE) {
 		ssl_certificate_save_chain(certs, chain_len, host, port);
diff --git a/src/common/ssl_certificate.h b/src/common/ssl_certificate.h
index 9f4ecf0..7089472 100644
--- a/src/common/ssl_certificate.h
+++ b/src/common/ssl_certificate.h
@@ -57,8 +57,8 @@ struct _SSLCertHookData
 };
 
 SSLCertificate *ssl_certificate_find (const gchar *host, gushort port, const gchar *fingerprint);
-gboolean ssl_certificate_check (gnutls_x509_crt_t x509_cert, guint status, const gchar *host, gushort port);
-gboolean ssl_certificate_check_chain(gnutls_x509_crt_t *certs, gint chain_len, const gchar *host, gushort port);
+gboolean ssl_certificate_check (gnutls_x509_crt_t x509_cert, guint status, const gchar *host, gushort port, gboolean accept_if_valid);
+gboolean ssl_certificate_check_chain(gnutls_x509_crt_t *certs, gint chain_len, const gchar *host, gushort port, gboolean accept_if_valid);
 void ssl_certificate_destroy(SSLCertificate *cert);
 void ssl_certificate_delete_from_disk(SSLCertificate *cert);
 char * readable_fingerprint(unsigned char *src, int len);
diff --git a/src/compose.c b/src/compose.c
index a13e4ea..7833804 100644
--- a/src/compose.c
+++ b/src/compose.c
@@ -11565,7 +11565,7 @@ gboolean compose_close(Compose *compose)
 		}
 		return TRUE;
 	}
-	
+
 	if (compose->draft_timeout_tag >= 0) {
 		g_source_remove(compose->draft_timeout_tag);
 		compose->draft_timeout_tag = COMPOSE_DRAFT_TIMEOUT_FORBIDDEN;
diff --git a/src/etpan/etpan-ssl.c b/src/etpan/etpan-ssl.c
index f99955b..529bc30 100644
--- a/src/etpan/etpan-ssl.c
+++ b/src/etpan/etpan-ssl.c
@@ -40,7 +40,8 @@
 #include "log.h"
 #include "prefs_account.h"
 
-gboolean etpan_certificate_check(mailstream *stream, const char *host, gint port)
+gboolean etpan_certificate_check(mailstream *stream, const char *host, gint port,
+				 gboolean accept_if_valid)
 {
 #if (!defined LIBETPAN_API_CURRENT || LIBETPAN_API_CURRENT < 18)
 	unsigned char *cert_der = NULL;
@@ -69,7 +70,7 @@ gboolean etpan_certificate_check(mailstream *stream, const char *host, gint port
 		free(tmp.data);
 		g_warning("IMAP: can't get cert\n");
 		return FALSE;
-	} else if (ssl_certificate_check(cert, (guint)-1, host, port) == TRUE) {
+	} else if (ssl_certificate_check(cert, (guint)-1, host, port, accept_if_valid) == TRUE) {
 		free(tmp.data);
 		gnutls_x509_crt_deinit(cert);
 		return TRUE;
@@ -121,7 +122,8 @@ gboolean etpan_certificate_check(mailstream *stream, const char *host, gint port
 	carray_free(certs_der);
 
 	if (result == TRUE)
-		result = ssl_certificate_check_chain(certs, chain_len, host, port);
+		result = ssl_certificate_check_chain(certs, chain_len, host, port,
+						     accept_if_valid);
 
 	for (i = 0; i < chain_len; i++)
 		gnutls_x509_crt_deinit(certs[i]);
diff --git a/src/etpan/etpan-ssl.h b/src/etpan/etpan-ssl.h
index 5607d1a..adb8f9d 100644
--- a/src/etpan/etpan-ssl.h
+++ b/src/etpan/etpan-ssl.h
@@ -31,7 +31,7 @@
 
 #include <libetpan/libetpan.h>
 
-gboolean etpan_certificate_check(mailstream *imap_stream, const char *host, gint port);
+gboolean etpan_certificate_check(mailstream *imap_stream, const char *host, gint port, gboolean accept_if_valid);
 void etpan_connect_ssl_context_cb(struct mailstream_ssl_context * ssl_context, void * data);
 
 #endif /* USE_GNUTLS */
diff --git a/src/etpan/imap-thread.c b/src/etpan/imap-thread.c
index 179f352..be7dca5 100644
--- a/src/etpan/imap-thread.c
+++ b/src/etpan/imap-thread.c
@@ -544,11 +544,12 @@ int imap_threaded_connect_ssl(Folder * folder, const char * server, int port)
 	chashdatum key;
 	chashdatum value;
 	mailimap * imap, * oldimap;
-	
+	gboolean accept_if_valid = FALSE;
+
 	oldimap = get_imap(folder);
 
 	imap = mailimap_new(0, NULL);
-	
+
 	if (oldimap) {
 		debug_print("deleting old imap %p\n", oldimap);
 		delete_imap(folder, oldimap);
@@ -559,22 +560,26 @@ int imap_threaded_connect_ssl(Folder * folder, const char * server, int port)
 	value.data = imap;
 	value.len = 0;
 	chash_set(session_hash, &key, &value, NULL);
-	
+
 	param.imap = imap;
 	param.server = server;
 	param.port = port;
 	param.account = folder->account;
 
+	if (folder->account)
+		accept_if_valid = folder->account->ssl_certs_auto_accept;
+
 	refresh_resolvers();
 	threaded_run(folder, &param, &result, connect_ssl_run);
 
 	if ((result.error == MAILIMAP_NO_ERROR_AUTHENTICATED ||
 	     result.error == MAILIMAP_NO_ERROR_NON_AUTHENTICATED) && !etpan_skip_ssl_cert_check) {
-		if (etpan_certificate_check(imap->imap_stream, server, port) != TRUE)
+		if (etpan_certificate_check(imap->imap_stream, server, port,
+					    accept_if_valid) != TRUE)
 			result.error = MAILIMAP_ERROR_SSL;
 	}
 	debug_print("connect %d with imap %p\n", result.error, imap);
-	
+
 	return result.error;
 }
 
@@ -1094,20 +1099,25 @@ int imap_threaded_starttls(Folder * folder, const gchar *host, int port)
 {
 	struct connect_param param;
 	struct starttls_result result;
-	
+	gboolean accept_if_valid = FALSE;
+
 	debug_print("imap starttls - begin\n");
-	
+
 	param.imap = get_imap(folder);
 	param.server = host;
 	param.port = port;
 	param.account = folder->account;
 
+	if (folder->account)
+		accept_if_valid = folder->account->ssl_certs_auto_accept;
+
 	threaded_run(folder, &param, &result, starttls_run);
-	
+
 	debug_print("imap starttls - end\n");
 
 	if (result.error == 0 && param.imap && !etpan_skip_ssl_cert_check) {
-		if (etpan_certificate_check(param.imap->imap_stream, host, port) != TRUE)
+		if (etpan_certificate_check(param.imap->imap_stream, host, port,
+					    accept_if_valid) != TRUE)
 			return MAILIMAP_ERROR_SSL;
 	}	
 	return result.error;
diff --git a/src/etpan/nntp-thread.c b/src/etpan/nntp-thread.c
index 7708d31..b721e61 100644
--- a/src/etpan/nntp-thread.c
+++ b/src/etpan/nntp-thread.c
@@ -398,11 +398,12 @@ int nntp_threaded_connect_ssl(Folder * folder, const char * server, int port)
 	chashdatum key;
 	chashdatum value;
 	newsnntp * nntp, * oldnntp;
-	
+	gboolean accept_if_valid = FALSE;
+
 	oldnntp = get_nntp(folder);
 
 	nntp = newsnntp_new(0, NULL);
-	
+
 	if (oldnntp) {
 		debug_print("deleting old nntp %p\n", oldnntp);
 		delete_nntp(folder, oldnntp);
@@ -413,17 +414,21 @@ int nntp_threaded_connect_ssl(Folder * folder, const char * server, int port)
 	value.data = nntp;
 	value.len = 0;
 	chash_set(session_hash, &key, &value, NULL);
-	
+
 	param.nntp = nntp;
 	param.server = server;
 	param.port = port;
 	param.account = folder->account;
 
+	if (folder->account)
+		accept_if_valid = folder->account->ssl_certs_auto_accept;
+
 	refresh_resolvers();
 	threaded_run(folder, &param, &result, connect_ssl_run);
 
 	if (result.error == NEWSNNTP_NO_ERROR && !etpan_skip_ssl_cert_check) {
-		if (etpan_certificate_check(nntp->nntp_stream, server, port) != TRUE)
+		if (etpan_certificate_check(nntp->nntp_stream, server, port,
+					    accept_if_valid) != TRUE)
 			return -1;
 	}
 	debug_print("connect %d with nntp %p\n", result.error, nntp);
diff --git a/src/pop.c b/src/pop.c
index a9a0472..2f7eed7 100644
--- a/src/pop.c
+++ b/src/pop.c
@@ -530,7 +530,7 @@ Session *pop3_session_new(PrefsAccount *account)
 	SESSION(session)->recv_msg = pop3_session_recv_msg;
 	SESSION(session)->recv_data_finished = pop3_session_recv_data_finished;
 	SESSION(session)->send_data_finished = NULL;
-
+	SESSION(session)->ssl_cert_auto_accept = account->ssl_certs_auto_accept;
 	SESSION(session)->destroy = pop3_session_destroy;
 
 	session->state = POP3_READY;
diff --git a/src/prefs_account.c b/src/prefs_account.c
index 9163800..a03f500 100644
--- a/src/prefs_account.c
+++ b/src/prefs_account.c
@@ -269,6 +269,7 @@ typedef struct SSLPage
 	GtkWidget *entry_out_cert_file;
 	GtkWidget *entry_out_cert_pass;
 
+	GtkWidget *ssl_certs_auto_accept_checkbtn;
 	GtkWidget *use_nonblocking_ssl_checkbtn;
 } SSLPage;
 
@@ -729,6 +730,10 @@ static PrefParam ssl_param[] = {
 	 prefs_account_enum_set_data_from_radiobtn,
 	 prefs_account_enum_set_radiobtn},
 
+	{"ssl_certs_auto_accept", "0", &tmp_ac_prefs.ssl_certs_auto_accept, P_BOOL,
+	 &ssl_page.ssl_certs_auto_accept_checkbtn,
+	 prefs_set_data_from_toggle, prefs_set_toggle},
+
 	{"use_nonblocking_ssl", "1", &tmp_ac_prefs.use_nonblocking_ssl, P_BOOL,
 	 &ssl_page.use_nonblocking_ssl_checkbtn,
 	 prefs_set_data_from_toggle, prefs_set_toggle},
@@ -769,6 +774,9 @@ static PrefParam ssl_param[] = {
 	{"out_ssl_client_cert_pass", "", &tmp_ac_prefs.out_ssl_client_cert_pass, P_PASSWORD,
 	 NULL, NULL, NULL},
 
+	{"ssl_certs_auto_accept", "0", &tmp_ac_prefs.ssl_certs_auto_accept, P_BOOL,
+	 NULL, NULL, NULL},
+
 	{"use_nonblocking_ssl", "1", &tmp_ac_prefs.use_nonblocking_ssl, P_BOOL,
 	 NULL, NULL, NULL},
 #endif /* USE_GNUTLS */
@@ -2413,6 +2421,7 @@ static void ssl_create_widget_func(PrefsPage * _page,
 	GtkWidget *entry_out_cert_pass;
 
 	GtkWidget *vbox7;
+	GtkWidget *ssl_certs_auto_accept_checkbtn;
 	GtkWidget *use_nonblocking_ssl_checkbtn;
 	GtkWidget *hbox;
 	GtkWidget *hbox_spc;
@@ -2545,6 +2554,9 @@ static void ssl_create_widget_func(PrefsPage * _page,
 	gtk_widget_show (vbox7);
 	gtk_box_pack_start (GTK_BOX (vbox1), vbox7, FALSE, FALSE, 0);
 
+	PACK_CHECK_BUTTON(vbox7, ssl_certs_auto_accept_checkbtn,
+			  _("Automatically accept unknown valid SSL certificates"));
+
 	PACK_CHECK_BUTTON(vbox7, use_nonblocking_ssl_checkbtn,
 			  _("Use non-blocking SSL"));
 
@@ -2587,6 +2599,7 @@ static void ssl_create_widget_func(PrefsPage * _page,
 	page->entry_out_cert_file     = entry_out_cert_file;
 	page->entry_out_cert_pass     = entry_out_cert_pass;
 
+	page->ssl_certs_auto_accept_checkbtn = ssl_certs_auto_accept_checkbtn;
 	page->use_nonblocking_ssl_checkbtn = use_nonblocking_ssl_checkbtn;
 
 	tmp_ac_prefs = *ac_prefs;
diff --git a/src/prefs_account.h b/src/prefs_account.h
index 40b9301..dd118c4 100644
--- a/src/prefs_account.h
+++ b/src/prefs_account.h
@@ -86,6 +86,7 @@ struct _PrefsAccount
 	gchar *in_ssl_client_cert_file;
 	gchar *in_ssl_client_cert_pass;
 
+	gboolean ssl_certs_auto_accept;
 	gboolean use_nonblocking_ssl;
 
 	/* Receive */
diff --git a/src/send_message.c b/src/send_message.c
index d51994d..80c0fb7 100644
--- a/src/send_message.c
+++ b/src/send_message.c
@@ -250,6 +250,8 @@ gint send_message_smtp_full(PrefsAccount *ac_prefs, GSList *to_list, FILE *fp, g
 	if (!ac_prefs->session) {
 		/* we can't reuse a previously initialised session */
 		session = smtp_session_new(ac_prefs);
+		session->ssl_cert_auto_accept = ac_prefs->ssl_certs_auto_accept;
+
 		smtp_session = SMTP_SESSION(session);
 
 		if (ac_prefs->set_domain && ac_prefs->domain && strlen(ac_prefs->domain)) {

-----------------------------------------------------------------------

Summary of changes:
 src/common/session.c         |    4 +++
 src/common/session.h         |    4 +--
 src/common/socket.h          |    3 ++-
 src/common/ssl.c             |    3 ++-
 src/common/ssl_certificate.c |   59 +++++++++++++++++++++++++++++++++---------
 src/common/ssl_certificate.h |    4 +--
 src/compose.c                |    2 +-
 src/etpan/etpan-ssl.c        |    8 +++---
 src/etpan/etpan-ssl.h        |    2 +-
 src/etpan/imap-thread.c      |   28 +++++++++++++-------
 src/etpan/nntp-thread.c      |   13 +++++++---
 src/pop.c                    |    2 +-
 src/prefs_account.c          |   13 ++++++++++
 src/prefs_account.h          |    1 +
 src/send_message.c           |    2 ++
 15 files changed, 111 insertions(+), 37 deletions(-)


hooks/post-receive
-- 
Claws Mail


More information about the Commits mailing list