--- gnubiff-2.2.9.orig/src/gnubiff_options.cc 2007-09-08 17:57:56 +0300 +++ gnubiff-2.2.9.orig/src/gnubiff_options.cc 2008-02-09 15:37:44 +0200 @@ -427,9 +427,9 @@ "address_entry")); // AUTHENTICATION const static guint i4[] = {AUTH_AUTODETECT, AUTH_USER_PASS, AUTH_APOP, - AUTH_SSL, AUTH_CERTIFICATE, AUTH_NONE, 0}; + AUTH_SSL, AUTH_CERTIFICATE, AUTH_TLS, AUTH_NONE, 0}; const static gchar *s4[] = {"autodetect", "user_pass", "apop", "ssl", - "certificate", "-", NULL}; + "certificate", "tls", "-", NULL}; add_option (new Option_UInt ("authentication", OPTGRP_MAILBOX, "Authentication to be used when connecting to the server via the " "internet.\n" --- gnubiff-2.2.9.orig/src/gnubiff_options.h 2007-09-08 21:06:30 +0300 +++ gnubiff-2.2.9.orig/src/gnubiff_options.h 2008-02-09 15:37:59 +0200 @@ -63,6 +63,7 @@ const guint AUTH_APOP = 2; const guint AUTH_SSL = 3; const guint AUTH_CERTIFICATE = 4; +const guint AUTH_TLS = 5; const guint AUTH_NONE = (guint)-1; const guint MAILBOX_ERROR = 0; --- gnubiff-2.2.9.orig/src/imap4.cc 2008-01-06 22:12:48 +0200 +++ gnubiff-2.2.9.orig/src/imap4.cc 2008-02-09 15:40:30 +0200 @@ -263,6 +263,22 @@ // CAPABILITY command_capability (true); + +#ifdef HAVE_LIBSSL + // Negotiate TLS encryption + if (authentication() == AUTH_TLS) { + if (can_starttls_) { + sendline ("STARTTLS"); + readline (line); + if (!socket_->starttls (certificate())) { + throw imap_command_err(); + } + } else { + command_logout(); + throw imap_nologin_err(); + } + } +#endif // LOGIN command_login(); @@ -369,6 +385,7 @@ * The command "CAPABILITY" is sent to the server to get the supported * capabilities. Currently gnubiff recognizes the following capabilities: * \begin{itemize} + * \item STARTTLS: Server supports TLS encryption. * \item IDLE: If the server has the IDLE capability, gnubiff uses the * IDLE command instead of polling. * \item LOGINDISABLED: The server wants us not to login. @@ -418,7 +435,8 @@ // Looking for supported capabilities idleable_ = use_idle () && (line.find (" IDLE ") != std::string::npos); - if (line.find (" LOGINDISABLED ") != std::string::npos) { + // Some sites advertise LOGINDISABLED until STARTTLS is used + if (line.find (" LOGINDISABLED ") != std::string::npos && line.find (" STARTTLS ") == std::string::npos) { command_logout(); throw imap_nologin_err(); } @@ -428,6 +446,9 @@ // CAPABILITY command, maybe the server sends additional capabilities if (((idleable_ == false) && use_idle()) && check_rc && !command_sent) command_capability (false); + + // Check for STARTTLS support + can_starttls_ = (line.find (" STARTTLS ") != std::string::npos); } /** --- gnubiff-2.2.9.orig/src/imap4.h 2007-09-08 21:06:30 +0300 +++ gnubiff-2.2.9.orig/src/imap4.h 2008-02-09 15:41:00 +0200 @@ -47,6 +47,9 @@ /// Does the server support the IDLE capability? gboolean idleable_; + /// Does the server support STARTTLS? + gboolean can_starttls_; + /// Is the server currently idled? gboolean idled_; --- gnubiff-2.2.9.orig/src/mailbox.cc 2007-09-08 17:57:57 +0300 +++ gnubiff-2.2.9.orig/src/mailbox.cc 2008-02-09 15:41:25 +0200 @@ -231,6 +231,7 @@ return 993; return ((protocol == PROTOCOL_POP3) ? 995 : 0); case AUTH_USER_PASS: + case AUTH_TLS: if (protocol == PROTOCOL_IMAP4) return 143; return ((protocol == PROTOCOL_POP3) ? 110 : 0); --- gnubiff-2.2.9.orig/src/socket.cc 2007-09-08 17:57:58 +0300 +++ gnubiff-2.2.9.orig/src/socket.cc 2008-02-09 15:46:04 +0200 @@ -267,6 +267,72 @@ return 1; } +gint +Socket::starttls (std::string certificate) +{ +#ifdef HAVE_LIBSSL + char *err_buf; + + err_buf = (char*) malloc (120); + + context_ = SSL_CTX_new (TLSv1_client_method()); + + if (certificate_.size() > 0) { + const gchar *capath = mailbox_->biff()->value_gchar ("dir_certificates"); + if (*capath == '\0') + capath = NULL; + if (!SSL_CTX_load_verify_locations (context_, certificate_.c_str(), + capath)) { + g_warning(_("[%d] Failed to load certificate (%s) for %s"), + uin_, certificate_.c_str(), hostname_.c_str()); + ::close (sd_); + sd_ = SD_CLOSE; + return 0; + } + SSL_CTX_set_verify (context_, SSL_VERIFY_PEER, NULL); + } + else + SSL_CTX_set_verify (context_, SSL_VERIFY_NONE, NULL); + + ssl_ = SSL_new (context_); + if ((!ssl_) || (SSL_set_fd (ssl_, sd_) == 0)) { + ::close (sd_); + sd_ = SD_CLOSE; + g_warning (_("[%d] Unable to set file descriptor: %s"), uin_, + hostname_.c_str()); + return 0; + } + + if (SSL_connect (ssl_) != 1) { + ERR_error_string(ERR_get_error(), err_buf); + SSL_free (ssl_); + ssl_ = NULL; + ::close (sd_); + sd_ = SD_CLOSE; + g_warning (_("[%d] Unable to negotiate TLS connection: %s"), uin_, err_buf); + return 0; + } + + if ((certificate_.size() > 0) && (SSL_get_verify_result(ssl_) != X509_V_OK)) { + g_static_mutex_lock (&ui_cert_mutex_); + ui_cert_->select (this); + g_static_mutex_unlock (&ui_cert_mutex_); + if (!bypass_certificate_) { + SSL_free (ssl_); + ssl_ = NULL; + ::close (sd_); + sd_ = SD_CLOSE; + g_warning (_("[%d] Cannot identify remote host (%s on port %d)"), uin_, hostname_.c_str(), port_); + } + } + + use_ssl_ = true; + +#endif + status_ = SOCKET_STATUS_OK; + return 1; +} + /** * Close the socket. */ --- gnubiff-2.2.9.orig/src/socket.h 2007-09-08 21:06:30 +0300 +++ gnubiff-2.2.9.orig/src/socket.h 2008-02-09 15:46:23 +0200 @@ -91,6 +91,7 @@ guint authentication = AUTH_SSL, std::string certificate = "", guint timeout = 5); + gint starttls (std::string certificate = ""); void close (void); gint write (std::string line, gboolean print = true); gint read (std::string &line, --- gnubiff-2.2.9.orig/src/ui-properties.cc 2007-09-08 17:57:59 +0300 +++ gnubiff-2.2.9.orig/src/ui-properties.cc 2008-02-09 15:49:15 +0200 @@ -156,6 +156,8 @@ { "SSL", GTK_STOCK_DIALOG_AUTHENTICATION, "SSL", 0, 0, G_CALLBACK(PROPERTIES_on_auth_changed)}, { "Certificate", GTK_STOCK_DIALOG_AUTHENTICATION, _("SSL with certificate"), + 0, 0, G_CALLBACK(PROPERTIES_on_auth_changed)}, + { "TLS", GTK_STOCK_DIALOG_AUTHENTICATION, "TLS", 0, 0, G_CALLBACK(PROPERTIES_on_auth_changed)} }; static const char *auth_ui_description = @@ -166,6 +168,7 @@ " " " " " " + " " " " ""; action_group = gtk_action_group_new ("actions"); @@ -302,6 +305,10 @@ selected_auth_ = AUTH_CERTIFICATE; certificate_view (true); } + else if (auth == "TLS") { + selected_auth_ = AUTH_TLS; + certificate_view (false); + } else { selected_auth_ = AUTH_AUTODETECT; certificate_view (false);