[evolution-data-server] Introduce CamelSession::trust_prompt()



commit f58f4faca264ae98a3ff1d97df09b14c828cfcf1
Author: Milan Crha <mcrha redhat com>
Date:   Fri Dec 14 15:25:55 2012 +0100

    Introduce CamelSession::trust_prompt()
    
    This way a trust-prompt dialog from EUserPrompter service can be used
    with all its features and a view consistency between components.

 camel/camel-disco-diary.c                 |    4 +-
 camel/camel-session.c                     |   45 +++++-
 camel/camel-session.h                     |   19 ++-
 camel/camel-tcp-stream-ssl.c              |  256 ++++++-----------------------
 camel/providers/imap/camel-imap-command.c |    2 +-
 camel/providers/imap/camel-imap-journal.c |    2 +-
 configure.ac                              |    2 +-
 7 files changed, 115 insertions(+), 215 deletions(-)
---
diff --git a/camel/camel-disco-diary.c b/camel/camel-disco-diary.c
index 47202ef..2be544c 100644
--- a/camel/camel-disco-diary.c
+++ b/camel/camel-disco-diary.c
@@ -210,7 +210,7 @@ camel_disco_diary_log (CamelDiscoDiary *diary,
 			"reconnect to the network."),
 			g_strerror (errno));
 		camel_session_alert_user (
-			session, CAMEL_SESSION_ALERT_ERROR, msg, NULL);
+			session, CAMEL_SESSION_ALERT_ERROR, msg, NULL, NULL);
 		g_free (msg);
 
 		fclose (diary->file);
@@ -276,7 +276,7 @@ diary_decode_folder (CamelDiscoDiary *diary,
 			camel_session_alert_user (
 				camel_service_get_session (CAMEL_SERVICE (diary->store)),
 				CAMEL_SESSION_ALERT_WARNING,
-				msg, NULL);
+				msg, NULL, cancellable);
 			g_free (msg);
 			g_free (name);
 		}
diff --git a/camel/camel-session.c b/camel/camel-session.c
index 94fce5b..302f14e 100644
--- a/camel/camel-session.c
+++ b/camel/camel-session.c
@@ -1278,6 +1278,7 @@ camel_session_forget_password (CamelSession *session,
  * @type: the type of alert (info, warning, or error)
  * @prompt: the message for the user
  * @button_captions: List of button captions to use. If NULL, only "Dismiss" button is shown.
+ * @cancellable: (allow-non): optional #GCancellable object, or %NULL
  *
  * Presents the given @prompt to the user, in the style indicated by
  * @type. If @cancel is %TRUE, the user will be able to accept or
@@ -1289,7 +1290,8 @@ gint
 camel_session_alert_user (CamelSession *session,
                           CamelSessionAlertType type,
                           const gchar *prompt,
-                          GSList *button_captions)
+                          GSList *button_captions,
+			  GCancellable *cancellable)
 {
 	CamelSessionClass *class;
 
@@ -1299,7 +1301,46 @@ camel_session_alert_user (CamelSession *session,
 	class = CAMEL_SESSION_GET_CLASS (session);
 	g_return_val_if_fail (class->alert_user != NULL, -1);
 
-	return class->alert_user (session, type, prompt, button_captions);
+	return class->alert_user (session, type, prompt, button_captions, cancellable);
+}
+
+/**
+ * camel_session_trust_prompt:
+ * @session: a #CamelSession
+ * @host: host name, to which the @certificate belongs
+ * @certificate: base64-encoded DER certificate on which to ask
+ * @certificate_errors: errors found with the certificate; a bit-OR of a #GTlsCertificateFlags
+ * @issuers: (allow-none): chain of issuers, or %NULL
+ * @cancellable: (allow-non): optional #GCancellable object, or %NULL
+ *
+ * Prompts user about trust of a certificate. The @certificate is not
+ * considered trusted, due to reasons set in @certificate_errors.
+ * There can be passed a list of @issuers, which has as items also base64-encoded
+ * DER certificates. The first item in the list is an issuer of the @certificate,
+ * the second item is an issuer of the first item, and so on.
+ *
+ * Returns: What trust level should be used for this certificate. It returns
+ *   #CAMEL_CERT_TRUST_UNKNOWN on error or if user cancelled the dialog prompt.
+ *
+ * Since: 3.8
+ **/
+CamelCertTrust
+camel_session_trust_prompt (CamelSession *session,
+			    const gchar *host,
+			    const gchar *certificate,
+			    guint32 certificate_errors,
+			    const GSList *issuers,
+			    GCancellable *cancellable)
+{
+	CamelSessionClass *class;
+
+	g_return_val_if_fail (CAMEL_IS_SESSION (session), CAMEL_CERT_TRUST_UNKNOWN);
+	g_return_val_if_fail (certificate != NULL, CAMEL_CERT_TRUST_UNKNOWN);
+
+	class = CAMEL_SESSION_GET_CLASS (session);
+	g_return_val_if_fail (class->trust_prompt != NULL, CAMEL_CERT_TRUST_UNKNOWN);
+
+	return class->trust_prompt (session, host, certificate, certificate_errors, issuers, cancellable);
 }
 
 /**
diff --git a/camel/camel-session.h b/camel/camel-session.h
index 93b5150..0c7a338 100644
--- a/camel/camel-session.h
+++ b/camel/camel-session.h
@@ -36,6 +36,7 @@
 #include <camel/camel-msgport.h>
 #include <camel/camel-provider.h>
 #include <camel/camel-service.h>
+#include <camel/camel-certdb.h>
 
 /* Standard GObject macros */
 #define CAMEL_TYPE_SESSION \
@@ -115,7 +116,14 @@ struct _CamelSessionClass {
 	gint		(*alert_user)		(CamelSession *session,
 						 CamelSessionAlertType type,
 						 const gchar *prompt,
-						 GSList *button_captions);
+						 GSList *button_captions,
+						 GCancellable *cancellable);
+	CamelCertTrust	(*trust_prompt)		(CamelSession *session,
+						 const gchar *host,
+						 const gchar *certificate,
+						 guint32 certificate_errors,
+						 const GSList *issuers,
+						 GCancellable *cancellable);
 	CamelFilterDriver *
 			(*get_filter_driver)	(CamelSession *session,
 						 const gchar *type,
@@ -208,7 +216,14 @@ gboolean	camel_session_forget_password	(CamelSession *session,
 gint		camel_session_alert_user	(CamelSession *session,
 						 CamelSessionAlertType type,
 						 const gchar *prompt,
-						 GSList *button_captions);
+						 GSList *button_captions,
+						 GCancellable *cancellable);
+CamelCertTrust	camel_session_trust_prompt	(CamelSession *session,
+						 const gchar *host,
+						 const gchar *certificate,
+						 guint32 certificate_errors,
+						 const GSList *issuers,
+						 GCancellable *cancellable);
 gchar *		camel_session_build_password_prompt
 						(const gchar *type,
 						 const gchar *user,
diff --git a/camel/camel-tcp-stream-ssl.c b/camel/camel-tcp-stream-ssl.c
index d1f1bb7..cd3cbc7 100644
--- a/camel/camel-tcp-stream-ssl.c
+++ b/camel/camel-tcp-stream-ssl.c
@@ -425,33 +425,6 @@ camel_certdb_nss_cert_set (CamelCertDB *certdb,
 	g_free (filename);
 }
 
-#if 0
-/* used by the mozilla-like code below */
-static gchar *
-get_nickname (CERTCertificate *cert)
-{
-	gchar *server, *nick = NULL;
-	gint i;
-	PRBool status = PR_TRUE;
-
-	server = CERT_GetCommonName (&cert->subject);
-	if (server == NULL)
-		return NULL;
-
-	for (i = 1; status == PR_TRUE; i++) {
-		if (nick) {
-			g_free (nick);
-			nick = g_strdup_printf ("%s #%d", server, i);
-		} else {
-			nick = g_strdup (server);
-		}
-		status = SEC_CertNicknameConflict (server, &cert->derSubject, cert->dbhandle);
-	}
-
-	return nick;
-}
-#endif
-
 static void
 tcp_stream_cancelled (GCancellable *cancellable,
                       PRThread *thread)
@@ -467,10 +440,8 @@ ssl_bad_cert (gpointer data,
 	CamelCertDB *certdb = NULL;
 	CamelCert *ccert = NULL;
 	gboolean ccert_is_new = FALSE;
-	gchar *prompt, *cert_str, *fingerprint;
 	CamelTcpStreamSSL *ssl;
 	CERTCertificate *cert;
-	SECStatus status = SECFailure;
 
 	g_return_val_if_fail (data != NULL, SECFailure);
 	g_return_val_if_fail (CAMEL_IS_TCP_STREAM_SSL (data), SECFailure);
@@ -493,59 +464,66 @@ ssl_bad_cert (gpointer data,
 	}
 
 	if (ccert->trust == CAMEL_CERT_TRUST_UNKNOWN) {
-		GSList *button_captions = NULL;
-		gint button_id;
-
-		status = CERT_VerifyCertNow (cert->dbhandle, cert, TRUE, certUsageSSLClient, NULL);
-		fingerprint = cert_fingerprint (cert);
-		cert_str = g_strdup_printf (_(
-			"   Issuer:       %s\n"
-			"   Subject:      %s\n"
-			"   Fingerprint:  %s\n"
-			"   Signature:    %s"),
-			CERT_NameToAscii (&cert->issuer),
-			CERT_NameToAscii (&cert->subject),
-			fingerprint,
-			status == SECSuccess ? _("GOOD") : _("BAD"));
-		g_free (fingerprint);
+		CERTCertificate *issuer;
+		CamelCertTrust trust_response;
+		gchar *base64;
+		guint32 certificate_errors = 0;
+		GSList *issuers = NULL;
+
+		if (CERT_VerifyCertNow (cert->dbhandle, cert, TRUE, certUsageSSLClient, NULL) != SECSuccess) {
+			gint pr_error;
+
+			pr_error = PR_GetError ();
+
+			switch (pr_error) {
+			case SEC_ERROR_UNKNOWN_ISSUER:
+				certificate_errors |= G_TLS_CERTIFICATE_UNKNOWN_CA;
+				break;
+			case SSL_ERROR_BAD_CERT_DOMAIN:
+				certificate_errors |= G_TLS_CERTIFICATE_BAD_IDENTITY;
+				break;
+			case SEC_ERROR_EXPIRED_CERTIFICATE:
+			case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
+				certificate_errors |= G_TLS_CERTIFICATE_EXPIRED;
+				break;
+			}
+		}
 
-		/* construct our user prompt */
-		prompt = g_strdup_printf (
-			_("SSL Certificate for '%s' is not trusted. "
-			"Do you wish to accept it?\n\n"
-			"Detailed information about the certificate:\n%s"),
-			ssl->priv->expected_host, cert_str);
-		g_free (cert_str);
+		issuer = cert;
+		while (issuer) {
+			if (SECITEM_CompareItem (&issuer->derIssuer, &issuer->derSubject) == SECEqual)
+				break;
 
-		button_captions = g_slist_append (button_captions, _("_Reject"));
-		button_captions = g_slist_append (button_captions, _("Accept _Temporarily"));
-		button_captions = g_slist_append (button_captions, _("_Accept Permanently"));
+			issuer = CERT_FindCertIssuer (issuer, PR_Now (), certUsageSSLClient);
+			if (!issuer)
+				break;
+
+			base64 = g_base64_encode (issuer->derIssuer.data, issuer->derIssuer.len);
+			if (!base64)
+				break;
+
+			issuers = g_slist_append (issuers, base64);
+		}
+
+		base64 = g_base64_encode (cert->derCert.data, cert->derCert.len);
 
 		/* query the user to find out if we want to accept this certificate */
-		button_id = camel_session_alert_user (ssl->priv->session, CAMEL_SESSION_ALERT_WARNING, prompt, button_captions);
-		g_slist_free (button_captions);
-		g_free (prompt);
+		trust_response = camel_session_trust_prompt (ssl->priv->session, ssl->priv->expected_host, base64, certificate_errors, issuers, NULL);
+
+		g_free (base64);
+		g_slist_free_full (issuers, g_free);
+
+		accept = trust_response != CAMEL_CERT_TRUST_UNKNOWN &&
+			 trust_response != CAMEL_CERT_TRUST_NEVER;
 
-		accept = button_id != 0;
 		if (ccert_is_new) {
 			camel_certdb_nss_cert_set (certdb, ccert, cert);
 			camel_certdb_put (certdb, ccert);
 		}
 
-		switch (button_id) {
-		case 0: /* Reject */
-			camel_cert_set_trust (certdb, ccert, CAMEL_CERT_TRUST_NEVER);
-			break;
-		case 1: /* Accept temporarily */
-			camel_cert_set_trust (certdb, ccert, CAMEL_CERT_TRUST_TEMPORARY);
-			break;
-		case 2: /* Accept permanently */
-			camel_cert_set_trust (certdb, ccert, CAMEL_CERT_TRUST_FULLY);
-			break;
-		default: /* anything else means failure and will ask again */
-			accept = FALSE;
-			break;
-		}
+		if (trust_response != CAMEL_CERT_TRUST_UNKNOWN)
+			camel_cert_set_trust (certdb, ccert, trust_response);
+
 		camel_certdb_touch (certdb);
 	} else {
 		accept = ccert->trust != CAMEL_CERT_TRUST_NEVER;
@@ -556,140 +534,6 @@ ssl_bad_cert (gpointer data,
 	g_object_unref (certdb);
 
 	return accept ? SECSuccess : SECFailure;
-
-#if 0
-	gint i, error;
-	CERTCertTrust trust;
-	SECItem *certs[1];
-	gint go = 1;
-	gchar *host, *nick;
-
-	error = PR_GetError ();
-
-	/* This code is basically what mozilla does - however it doesn't seem to work here
-	 * very reliably :-/ */
-	while (go && status != SECSuccess) {
-		gchar *prompt = NULL;
-
-		printf ("looping, error '%d'\n", error);
-
-		switch (error) {
-		case SEC_ERROR_UNKNOWN_ISSUER:
-		case SEC_ERROR_CA_CERT_INVALID:
-		case SEC_ERROR_UNTRUSTED_ISSUER:
-		case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
-			/* add certificate */
-			printf ("unknown issuer, adding ... \n");
-			prompt = g_strdup_printf (_("Certificate problem: %s\nIssuer: %s"), cert->subjectName, cert->issuerName);
-
-			if (camel_session_alert_user (ssl->priv->session, CAMEL_SESSION_ALERT_WARNING, prompt, TRUE)) {
-
-				nick = get_nickname (cert);
-				if (NULL == nick) {
-					g_free (prompt);
-					status = SECFailure;
-					break;
-				}
-
-				printf ("adding cert '%s'\n", nick);
-
-				if (!cert->trust) {
-					cert->trust = (CERTCertTrust *) PORT_ArenaZAlloc (cert->arena, sizeof (CERTCertTrust));
-					CERT_DecodeTrustString (cert->trust, "P");
-				}
-
-				certs[0] = &cert->derCert;
-				/*CERT_ImportCerts (cert->dbhandle, certUsageSSLServer, 1, certs, NULL, TRUE, FALSE, nick);*/
-				CERT_ImportCerts (cert->dbhandle, certUsageUserCertImport, 1, certs, NULL, TRUE, FALSE, nick);
-				g_free (nick);
-
-				printf (" cert type %08x\n", cert->nsCertType);
-
-				memset ((gpointer) &trust, 0, sizeof (trust));
-				if (CERT_GetCertTrust (cert, &trust) != SECSuccess) {
-					CERT_DecodeTrustString (&trust, "P");
-				}
-				trust.sslFlags |= CERTDB_VALID_PEER | CERTDB_TRUSTED;
-				if (CERT_ChangeCertTrust (cert->dbhandle, cert, &trust) != SECSuccess) {
-					printf ("couldn't change cert trust?\n");
-				}
-
-				/*status = SECSuccess;*/
-#if 1
-				/* re-verify? */
-				status = CERT_VerifyCertNow (cert->dbhandle, cert, TRUE, certUsageSSLServer, NULL);
-				error = PR_GetError ();
-				printf ("re-verify status %d, error %d\n", status, error);
-#endif
-
-				printf (" cert type %08x\n", cert->nsCertType);
-			} else {
-				printf ("failed/cancelled\n");
-				go = 0;
-			}
-
-			break;
-		case SSL_ERROR_BAD_CERT_DOMAIN:
-			printf ("bad domain\n");
-
-			prompt = g_strdup_printf (_("Bad certificate domain: %s\nIssuer: %s"), cert->subjectName, cert->issuerName);
-
-			if (camel_session_alert_user (ssl->priv->session, CAMEL_SESSION_ALERT_WARNING, prompt, TRUE)) {
-				host = SSL_RevealURL (sockfd);
-				status = CERT_AddOKDomainName (cert, host);
-				printf ("add ok domain name : %s\n", status == SECFailure?"fail":"ok");
-				error = PR_GetError ();
-				if (status == SECFailure)
-					go = 0;
-			} else {
-				go = 0;
-			}
-
-			break;
-
-		case SEC_ERROR_EXPIRED_CERTIFICATE:
-			printf ("expired\n");
-
-			prompt = g_strdup_printf (_("Certificate expired: %s\nIssuer: %s"), cert->subjectName, cert->issuerName);
-
-			if (camel_session_alert_user (ssl->priv->session, CAMEL_SESSION_ALERT_WARNING, prompt, TRUE)) {
-				cert->timeOK = PR_TRUE;
-				status = CERT_VerifyCertNow (cert->dbhandle, cert, TRUE, certUsageSSLClient, NULL);
-				error = PR_GetError ();
-				if (status == SECFailure)
-					go = 0;
-			} else {
-				go = 0;
-			}
-
-			break;
-
-		case SEC_ERROR_CRL_EXPIRED:
-			printf ("crl expired\n");
-
-			prompt = g_strdup_printf (_("Certificate revocation list expired: %s\nIssuer: %s"), cert->subjectName, cert->issuerName);
-
-			if (camel_session_alert_user (ssl->priv->session, CAMEL_SESSION_ALERT_WARNING, prompt, TRUE)) {
-				host = SSL_RevealURL (sockfd);
-				status = CERT_AddOKDomainName (cert, host);
-			}
-
-			go = 0;
-			break;
-
-		default:
-			printf ("generic error\n");
-			go = 0;
-			break;
-		}
-
-		g_free (prompt);
-	}
-
-	CERT_DestroyCertificate (cert);
-
-	return status;
-#endif
 }
 
 static PRFileDesc *
diff --git a/camel/providers/imap/camel-imap-command.c b/camel/providers/imap/camel-imap-command.c
index 4584413..bbe1e69 100644
--- a/camel/providers/imap/camel-imap-command.c
+++ b/camel/providers/imap/camel-imap-command.c
@@ -430,7 +430,7 @@ camel_imap_command_response (CamelImapStore *store,
 						user, host, alert);
 				camel_session_alert_user (
 					session, CAMEL_SESSION_ALERT_WARNING,
-					msg, NULL);
+					msg, NULL, cancellable);
 				g_free (msg);
 			}
 		}
diff --git a/camel/providers/imap/camel-imap-journal.c b/camel/providers/imap/camel-imap-journal.c
index e743253..6491c80 100644
--- a/camel/providers/imap/camel-imap-journal.c
+++ b/camel/providers/imap/camel-imap-journal.c
@@ -318,7 +318,7 @@ journal_decode_folder (CamelIMAPJournal *journal,
 				camel_service_get_session (
 				CAMEL_SERVICE (parent_store)),
 				CAMEL_SESSION_ALERT_WARNING,
-				msg, NULL);
+				msg, NULL, cancellable);
 			g_free (msg);
 		}
 	}
diff --git a/configure.ac b/configure.ac
index 31995d4..212736c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -125,7 +125,7 @@ LIBEBOOK_CURRENT=17
 LIBEBOOK_REVISION=1
 LIBEBOOK_AGE=3
 
-LIBCAMEL_CURRENT=42
+LIBCAMEL_CURRENT=43
 LIBCAMEL_REVISION=0
 LIBCAMEL_AGE=0
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]