[gnome-online-accounts/gnome-3-8] mail-auth: Support STARTTLS for IMAP and SMTP
- From: Debarshi Ray <debarshir src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-online-accounts/gnome-3-8] mail-auth: Support STARTTLS for IMAP and SMTP
- Date: Tue, 12 Mar 2013 10:49:44 +0000 (UTC)
commit ca44a61b925b74d18fd3d757639fd0d4280b3bad
Author: Debarshi Ray <debarshir gnome org>
Date: Fri Mar 8 23:58:00 2013 +0100
mail-auth: Support STARTTLS for IMAP and SMTP
Add a starttls_sync virtual method which GoaImapAuthLogin and
GoaSmtpAuthPlain should implement for STARTTLS.
Fixes: https://bugzilla.gnome.org/695355
src/goabackend/goaimapauthlogin.c | 57 ++++++++++++++
src/goabackend/goamailauth.c | 77 +++++++++++++++++++
src/goabackend/goamailauth.h | 13 +++
src/goabackend/goasmtpauthplain.c | 153 ++++++++++++++++++++++++++++++++++---
4 files changed, 290 insertions(+), 10 deletions(-)
---
diff --git a/src/goabackend/goaimapauthlogin.c b/src/goabackend/goaimapauthlogin.c
index c35a8a2..8b3ba72 100644
--- a/src/goabackend/goaimapauthlogin.c
+++ b/src/goabackend/goaimapauthlogin.c
@@ -74,6 +74,9 @@ static gboolean goa_imap_auth_login_is_needed (GoaMailAuth *auth);
static gboolean goa_imap_auth_login_run_sync (GoaMailAuth *_auth,
GCancellable *cancellable,
GError **error);
+static gboolean goa_imap_auth_login_starttls_sync (GoaMailAuth *_auth,
+ GCancellable *cancellable,
+ GError **error);
G_DEFINE_TYPE (GoaImapAuthLogin, goa_imap_auth_login, GOA_TYPE_MAIL_AUTH);
@@ -178,6 +181,7 @@ goa_imap_auth_login_class_init (GoaImapAuthLoginClass *klass)
auth_class = GOA_MAIL_AUTH_CLASS (klass);
auth_class->is_needed = goa_imap_auth_login_is_needed;
auth_class->run_sync = goa_imap_auth_login_run_sync;
+ auth_class->starttls_sync = goa_imap_auth_login_starttls_sync;
/**
* GoaImapAuthLogin:provider:
@@ -384,3 +388,56 @@ goa_imap_auth_login_run_sync (GoaMailAuth *_auth,
g_free (password);
return ret;
}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gboolean
+goa_imap_auth_login_starttls_sync (GoaMailAuth *_auth,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GDataInputStream *input;
+ GDataOutputStream *output;
+ gchar *request;
+ gchar *response;
+ gboolean ret;
+
+ request = NULL;
+ response = NULL;
+
+ ret = FALSE;
+
+ input = goa_mail_auth_get_input (_auth);
+ output = goa_mail_auth_get_output (_auth);
+
+ request = g_strdup ("A001 STARTTLS\r\n");
+ if (!g_data_output_stream_put_string (output, request, cancellable, error))
+ goto out;
+
+ again:
+ response = g_data_input_stream_read_line (input, NULL, cancellable, error);
+ if (response == NULL)
+ goto out;
+ /* ignore untagged responses */
+ if (g_str_has_prefix (response, "*"))
+ {
+ g_free (response);
+ goto again;
+ }
+ if (!g_str_has_prefix (response, "A001 OK"))
+ {
+ g_set_error (error,
+ GOA_ERROR,
+ GOA_ERROR_FAILED,
+ "Unexpected response `%s' while doing LOGIN authentication",
+ response);
+ goto out;
+ }
+
+ ret = TRUE;
+
+ out:
+ g_free (response);
+ g_free (request);
+ return ret;
+}
diff --git a/src/goabackend/goamailauth.c b/src/goabackend/goamailauth.c
index 4984b03..6585f66 100644
--- a/src/goabackend/goamailauth.c
+++ b/src/goabackend/goamailauth.c
@@ -68,6 +68,29 @@ mail_auth_run_in_thread_func (GSimpleAsyncResult *res, GObject *object, GCancell
/* ---------------------------------------------------------------------------------------------------- */
static void
+mail_auth_starttls_in_thread_func (GSimpleAsyncResult *res, GObject *object, GCancellable *cancellable)
+{
+ GError *error;
+ gboolean op_res;
+
+ op_res = FALSE;
+
+ error = NULL;
+ if (!goa_mail_auth_starttls_sync (GOA_MAIL_AUTH (object), cancellable, &error))
+ {
+ g_simple_async_result_take_error (res, error);
+ goto out;
+ }
+
+ op_res = TRUE;
+
+ out:
+ g_simple_async_result_set_op_res_gboolean (res, op_res);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
goa_mail_auth_dispose (GObject *object)
{
GoaMailAuth *auth = GOA_MAIL_AUTH (object);
@@ -229,6 +252,60 @@ goa_mail_auth_run_finish (GoaMailAuth *auth,
/* ---------------------------------------------------------------------------------------------------- */
+gboolean
+goa_mail_auth_starttls_sync (GoaMailAuth *auth,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_return_val_if_fail (GOA_IS_MAIL_AUTH (auth), FALSE);
+ g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
+ return GOA_MAIL_AUTH_GET_CLASS (auth)->starttls_sync (auth, cancellable, error);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+void
+goa_mail_auth_starttls (GoaMailAuth *auth,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_if_fail (GOA_IS_MAIL_AUTH (auth));
+ g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+ simple = g_simple_async_result_new (G_OBJECT (auth), callback, user_data, goa_mail_auth_starttls);
+ g_simple_async_result_set_handle_cancellation (simple, TRUE);
+
+ g_simple_async_result_run_in_thread (simple,
+ mail_auth_starttls_in_thread_func,
+ G_PRIORITY_DEFAULT,
+ cancellable);
+
+ g_object_unref (simple);
+}
+
+gboolean
+goa_mail_auth_starttls_finish (GoaMailAuth *auth,
+ GAsyncResult *res,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (res, G_OBJECT (auth), goa_mail_auth_starttls),
FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (res);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ return g_simple_async_result_get_op_res_gboolean (simple);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
GDataInputStream *
goa_mail_auth_get_input (GoaMailAuth *auth)
{
diff --git a/src/goabackend/goamailauth.h b/src/goabackend/goamailauth.h
index 6cdff1d..d5f9d81 100644
--- a/src/goabackend/goamailauth.h
+++ b/src/goabackend/goamailauth.h
@@ -59,6 +59,9 @@ struct _GoaMailAuthClass
gboolean (*run_sync) (GoaMailAuth *auth,
GCancellable *cancellable,
GError **error);
+ gboolean (*starttls_sync) (GoaMailAuth *auth,
+ GCancellable *cancellable,
+ GError **error);
};
GType goa_mail_auth_get_type (void) G_GNUC_CONST;
@@ -73,6 +76,16 @@ gboolean goa_mail_auth_run_finish (GoaMailAuth *auth,
gboolean goa_mail_auth_run_sync (GoaMailAuth *auth,
GCancellable *cancellable,
GError **error);
+void goa_mail_auth_starttls (GoaMailAuth *auth,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean goa_mail_auth_starttls_finish (GoaMailAuth *auth,
+ GAsyncResult *res,
+ GError **error);
+gboolean goa_mail_auth_starttls_sync (GoaMailAuth *auth,
+ GCancellable *cancellable,
+ GError **error);
GDataInputStream *goa_mail_auth_get_input (GoaMailAuth *auth);
void goa_mail_auth_set_input (GoaMailAuth *auth,
GDataInputStream *input);
diff --git a/src/goabackend/goasmtpauthplain.c b/src/goabackend/goasmtpauthplain.c
index fc34cbe..9a37d77 100644
--- a/src/goabackend/goasmtpauthplain.c
+++ b/src/goabackend/goasmtpauthplain.c
@@ -54,6 +54,7 @@ struct _GoaSmtpAuthPlain
GoaProvider *provider;
GoaObject *object;
gboolean auth_supported;
+ gboolean greeting_absent;
gchar *domain;
gchar *username;
gchar *password;
@@ -79,6 +80,9 @@ static gboolean goa_smtp_auth_plain_is_needed (GoaMailAuth *_auth);
static gboolean goa_smtp_auth_plain_run_sync (GoaMailAuth *_auth,
GCancellable *cancellable,
GError **error);
+static gboolean goa_smtp_auth_plain_starttls_sync (GoaMailAuth *_auth,
+ GCancellable *cancellable,
+ GError **error);
G_DEFINE_TYPE (GoaSmtpAuthPlain, goa_smtp_auth_plain, GOA_TYPE_MAIL_AUTH);
@@ -146,6 +150,21 @@ smtp_auth_plain_check_421 (const gchar *response, GError **error)
return FALSE;
}
+static gboolean
+smtp_auth_plain_check_454 (const gchar *response, GError **error)
+{
+ if (g_str_has_prefix (response, "454"))
+ {
+ g_set_error (error,
+ GOA_ERROR,
+ GOA_ERROR_FAILED, /* TODO: more specific */
+ _("TLS not available"));
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
/* ---------------------------------------------------------------------------------------------------- */
static gchar *
@@ -360,6 +379,7 @@ goa_smtp_auth_plain_class_init (GoaSmtpAuthPlainClass *klass)
auth_class = GOA_MAIL_AUTH_CLASS (klass);
auth_class->is_needed = goa_smtp_auth_plain_is_needed;
auth_class->run_sync = goa_smtp_auth_plain_run_sync;
+ auth_class->starttls_sync = goa_smtp_auth_plain_starttls_sync;
/**
* GoaSmtpAuthPlain:provider:
@@ -539,17 +559,20 @@ goa_smtp_auth_plain_run_sync (GoaMailAuth *_auth,
input = goa_mail_auth_get_input (_auth);
output = goa_mail_auth_get_output (_auth);
- /* Check the greeting */
+ /* Check the greeting, if there is one */
- response = g_data_input_stream_read_line (input, NULL, cancellable, error);
- if (response == NULL)
- goto out;
- g_debug ("< %s", response);
- if (smtp_auth_plain_check_421 (response, error))
- goto out;
- if (smtp_auth_plain_check_not_220 (response, error))
- goto out;
- g_clear_pointer (&response, g_free);
+ if (!auth->greeting_absent)
+ {
+ response = g_data_input_stream_read_line (input, NULL, cancellable, error);
+ if (response == NULL)
+ goto out;
+ g_debug ("< %s", response);
+ if (smtp_auth_plain_check_421 (response, error))
+ goto out;
+ if (smtp_auth_plain_check_not_220 (response, error))
+ goto out;
+ g_clear_pointer (&response, g_free);
+ }
/* Send EHLO */
@@ -629,3 +652,113 @@ goa_smtp_auth_plain_run_sync (GoaMailAuth *_auth,
g_free (request);
return ret;
}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gboolean
+goa_smtp_auth_plain_starttls_sync (GoaMailAuth *_auth,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GoaSmtpAuthPlain *auth = GOA_SMTP_AUTH_PLAIN (_auth);
+ GDataInputStream *input;
+ GDataOutputStream *output;
+ gboolean ret;
+ gboolean starttls_supported;
+ gchar *domain;
+ gchar *request;
+ gchar *response;
+
+ starttls_supported = FALSE;
+ domain = NULL;
+ request = NULL;
+ response = NULL;
+
+ ret = FALSE;
+
+ domain = smtp_auth_plain_get_domain (auth, error);
+ if (domain == NULL)
+ goto out;
+
+ input = goa_mail_auth_get_input (_auth);
+ output = goa_mail_auth_get_output (_auth);
+
+ /* Check the greeting */
+
+ response = g_data_input_stream_read_line (input, NULL, cancellable, error);
+ if (response == NULL)
+ goto out;
+ g_debug ("< %s", response);
+ if (smtp_auth_plain_check_421 (response, error))
+ goto out;
+ if (smtp_auth_plain_check_not_220 (response, error))
+ goto out;
+ g_clear_pointer (&response, g_free);
+
+ /* Send EHLO */
+
+ request = g_strdup_printf ("EHLO %s\r\n", domain);
+ g_debug ("> %s", request);
+ if (!g_data_output_stream_put_string (output, request, cancellable, error))
+ goto out;
+ g_clear_pointer (&request, g_free);
+
+ /* Check if STARTTLS is supported or not */
+
+ ehlo_again:
+ response = g_data_input_stream_read_line (input, NULL, cancellable, error);
+ if (response == NULL)
+ goto out;
+ g_debug ("< %s", response);
+ if (smtp_auth_plain_check_421 (response, error))
+ goto out;
+ if (smtp_auth_plain_check_not_250 (response, error))
+ goto out;
+
+ if (g_str_has_prefix (response + 4, "STARTTLS"))
+ starttls_supported = TRUE;
+
+ if (response[3] == '-')
+ {
+ g_free (response);
+ goto ehlo_again;
+ }
+ else if (!starttls_supported)
+ {
+ g_set_error (error,
+ GOA_ERROR,
+ GOA_ERROR_NOT_SUPPORTED,
+ _("Server does not support STARTTLS"));
+ goto out;
+ }
+ g_clear_pointer (&response, g_free);
+
+ /* Send STARTTLS */
+
+ request = g_strdup ("STARTTLS\r\n");
+ g_debug ("> %s", request);
+ if (!g_data_output_stream_put_string (output, request, cancellable, error))
+ goto out;
+ g_clear_pointer (&request, g_free);
+
+ response = g_data_input_stream_read_line (input, NULL, cancellable, error);
+ if (response == NULL)
+ goto out;
+ g_debug ("< %s", response);
+ if (smtp_auth_plain_check_454 (response, error))
+ goto out;
+ if (smtp_auth_plain_check_not_220 (response, error))
+ goto out;
+ g_clear_pointer (&response, g_free);
+
+ /* There won't be a greeting after this */
+ auth->greeting_absent = TRUE;
+
+ ret = TRUE;
+
+ out:
+ g_free (domain);
+ g_free (response);
+ g_free (request);
+ return ret;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]