|
Packit Service |
c6b9b0 |
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
|
Packit Service |
c6b9b0 |
/*
|
|
Packit Service |
c6b9b0 |
* Copyright © 2011 – 2017 Red Hat, Inc.
|
|
Packit Service |
c6b9b0 |
*
|
|
Packit Service |
c6b9b0 |
* This library is free software; you can redistribute it and/or
|
|
Packit Service |
c6b9b0 |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit Service |
c6b9b0 |
* License as published by the Free Software Foundation; either
|
|
Packit Service |
c6b9b0 |
* version 2 of the License, or (at your option) any later version.
|
|
Packit Service |
c6b9b0 |
*
|
|
Packit Service |
c6b9b0 |
* This library is distributed in the hope that it will be useful,
|
|
Packit Service |
c6b9b0 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
c6b9b0 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit Service |
c6b9b0 |
* Lesser General Public License for more details.
|
|
Packit Service |
c6b9b0 |
*
|
|
Packit Service |
c6b9b0 |
* You should have received a copy of the GNU Lesser General
|
|
Packit Service |
c6b9b0 |
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
Packit Service |
c6b9b0 |
*/
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
#include "config.h"
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
#include <string.h>
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
#include <glib/gi18n-lib.h>
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
#include "goasmtpauth.h"
|
|
Packit Service |
c6b9b0 |
#include "goautils.h"
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
/*
|
|
Packit Service |
c6b9b0 |
* SECTION:goasmtpauth
|
|
Packit Service |
c6b9b0 |
* @title: GoaSmtpAuth
|
|
Packit Service |
c6b9b0 |
* @short_description: Authentication mechanisms for SMTP
|
|
Packit Service |
c6b9b0 |
*
|
|
Packit Service |
c6b9b0 |
* #GoaSmtpAuth implements the
|
|
Packit Service |
c6b9b0 |
* url="http://tools.ietf.org/html/rfc4616">PLAIN</ulink> and
|
|
Packit Service |
c6b9b0 |
* url="http://msdn.microsoft.com/en-us/library/cc433484(v=EXCHG.80).aspx">LOGIN</ulink>
|
|
Packit Service |
c6b9b0 |
* SASL mechanisms (e.g. using usernames / passwords) for SMTP.
|
|
Packit Service |
c6b9b0 |
*/
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
/*
|
|
Packit Service |
c6b9b0 |
* GoaSmtpAuth:
|
|
Packit Service |
c6b9b0 |
*
|
|
Packit Service |
c6b9b0 |
* The #GoaSmtpAuth structure contains only private data and should
|
|
Packit Service |
c6b9b0 |
* only be accessed using the provided API.
|
|
Packit Service |
c6b9b0 |
*/
|
|
Packit Service |
c6b9b0 |
struct _GoaSmtpAuth
|
|
Packit Service |
c6b9b0 |
{
|
|
Packit Service |
c6b9b0 |
GoaMailAuth parent_instance;
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
gboolean auth_supported;
|
|
Packit Service |
c6b9b0 |
gboolean greeting_absent;
|
|
Packit Service |
c6b9b0 |
gboolean login_supported;
|
|
Packit Service |
c6b9b0 |
gboolean plain_supported;
|
|
Packit Service |
c6b9b0 |
gchar *domain;
|
|
Packit Service |
c6b9b0 |
gchar *username;
|
|
Packit Service |
c6b9b0 |
gchar *password;
|
|
Packit Service |
c6b9b0 |
};
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
typedef struct
|
|
Packit Service |
c6b9b0 |
{
|
|
Packit Service |
c6b9b0 |
GoaMailAuthClass parent_class;
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
} GoaSmtpAuthClass;
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
enum
|
|
Packit Service |
c6b9b0 |
{
|
|
Packit Service |
c6b9b0 |
PROP_0,
|
|
Packit Service |
c6b9b0 |
PROP_DOMAIN,
|
|
Packit Service |
c6b9b0 |
PROP_USERNAME,
|
|
Packit Service |
c6b9b0 |
PROP_PASSWORD
|
|
Packit Service |
c6b9b0 |
};
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
static gboolean goa_smtp_auth_is_needed (GoaMailAuth *auth);
|
|
Packit Service |
c6b9b0 |
static gboolean goa_smtp_auth_run_sync (GoaMailAuth *auth,
|
|
Packit Service |
c6b9b0 |
GCancellable *cancellable,
|
|
Packit Service |
c6b9b0 |
GError **error);
|
|
Packit Service |
c6b9b0 |
static gboolean goa_smtp_auth_starttls_sync (GoaMailAuth *auth,
|
|
Packit Service |
c6b9b0 |
GCancellable *cancellable,
|
|
Packit Service |
c6b9b0 |
GError **error);
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
G_DEFINE_TYPE (GoaSmtpAuth, goa_smtp_auth, GOA_TYPE_MAIL_AUTH);
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
/* ---------------------------------------------------------------------------------------------------- */
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
static gboolean
|
|
Packit Service |
c6b9b0 |
smtp_auth_check_not_220 (const gchar *response, GError **error)
|
|
Packit Service |
c6b9b0 |
{
|
|
Packit Service |
c6b9b0 |
if (!g_str_has_prefix (response, "220"))
|
|
Packit Service |
c6b9b0 |
{
|
|
Packit Service |
c6b9b0 |
g_set_error (error,
|
|
Packit Service |
c6b9b0 |
GOA_ERROR,
|
|
Packit Service |
c6b9b0 |
GOA_ERROR_FAILED, /* TODO: more specific */
|
|
Packit Service |
c6b9b0 |
"Unexpected response `%s'",
|
|
Packit Service |
c6b9b0 |
response);
|
|
Packit Service |
c6b9b0 |
return TRUE;
|
|
Packit Service |
c6b9b0 |
}
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
return FALSE;
|
|
Packit Service |
c6b9b0 |
}
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
static gboolean
|
|
Packit Service |
c6b9b0 |
smtp_auth_check_not_235 (const gchar *response, GError **error)
|
|
Packit Service |
c6b9b0 |
{
|
|
Packit Service |
c6b9b0 |
if (!g_str_has_prefix (response, "235"))
|
|
Packit Service |
c6b9b0 |
{
|
|
Packit Service |
c6b9b0 |
g_set_error (error,
|
|
Packit Service |
c6b9b0 |
GOA_ERROR,
|
|
Packit Service |
c6b9b0 |
GOA_ERROR_FAILED, /* TODO: more specific */
|
|
Packit Service |
c6b9b0 |
_("Authentication failed"));
|
|
Packit Service |
c6b9b0 |
return TRUE;
|
|
Packit Service |
c6b9b0 |
}
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
return FALSE;
|
|
Packit Service |
c6b9b0 |
}
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
static gboolean
|
|
Packit Service |
c6b9b0 |
smtp_auth_check_not_250 (const gchar *response, GError **error)
|
|
Packit Service |
c6b9b0 |
{
|
|
Packit Service |
c6b9b0 |
if (!g_str_has_prefix (response, "250") || strlen (response) < 4)
|
|
Packit Service |
c6b9b0 |
{
|
|
Packit Service |
c6b9b0 |
g_set_error (error,
|
|
Packit Service |
c6b9b0 |
GOA_ERROR,
|
|
Packit Service |
c6b9b0 |
GOA_ERROR_FAILED, /* TODO: more specific */
|
|
Packit Service |
c6b9b0 |
"Unexpected response `%s'",
|
|
Packit Service |
c6b9b0 |
response);
|
|
Packit Service |
c6b9b0 |
return TRUE;
|
|
Packit Service |
c6b9b0 |
}
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
return FALSE;
|
|
Packit Service |
c6b9b0 |
}
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
static gboolean
|
|
Packit Service |
c6b9b0 |
smtp_auth_check_not_334_login_password (const gchar *response, GError **error)
|
|
Packit Service |
c6b9b0 |
{
|
|
Packit Service |
c6b9b0 |
if (!g_str_has_prefix (response, "334 UGFzc3dvcmQ6"))
|
|
Packit Service |
c6b9b0 |
{
|
|
Packit Service |
c6b9b0 |
g_set_error (error,
|
|
Packit Service |
c6b9b0 |
GOA_ERROR,
|
|
Packit Service |
c6b9b0 |
GOA_ERROR_FAILED, /* TODO: more specific */
|
|
Packit Service |
c6b9b0 |
"Unexpected response `%s'",
|
|
Packit Service |
c6b9b0 |
response);
|
|
Packit Service |
c6b9b0 |
return TRUE;
|
|
Packit Service |
c6b9b0 |
}
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
return FALSE;
|
|
Packit Service |
c6b9b0 |
}
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
static gboolean
|
|
Packit Service |
c6b9b0 |
smtp_auth_check_421 (const gchar *response, GError **error)
|
|
Packit Service |
c6b9b0 |
{
|
|
Packit Service |
c6b9b0 |
if (g_str_has_prefix (response, "421"))
|
|
Packit Service |
c6b9b0 |
{
|
|
Packit Service |
c6b9b0 |
g_set_error (error,
|
|
Packit Service |
c6b9b0 |
GOA_ERROR,
|
|
Packit Service |
c6b9b0 |
GOA_ERROR_FAILED, /* TODO: more specific */
|
|
Packit Service |
c6b9b0 |
_("Service not available"));
|
|
Packit Service |
c6b9b0 |
return TRUE;
|
|
Packit Service |
c6b9b0 |
}
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
return FALSE;
|
|
Packit Service |
c6b9b0 |
}
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
static gboolean
|
|
Packit Service |
c6b9b0 |
smtp_auth_check_454 (const gchar *response, GError **error)
|
|
Packit Service |
c6b9b0 |
{
|
|
Packit Service |
c6b9b0 |
if (g_str_has_prefix (response, "454"))
|
|
Packit Service |
c6b9b0 |
{
|
|
Packit Service |
c6b9b0 |
g_set_error (error,
|
|
Packit Service |
c6b9b0 |
GOA_ERROR,
|
|
Packit Service |
c6b9b0 |
GOA_ERROR_FAILED, /* TODO: more specific */
|
|
Packit Service |
c6b9b0 |
_("TLS not available"));
|
|
Packit Service |
c6b9b0 |
return TRUE;
|
|
Packit Service |
c6b9b0 |
}
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
return FALSE;
|
|
Packit Service |
c6b9b0 |
}
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
/* ---------------------------------------------------------------------------------------------------- */
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
static gboolean
|
|
Packit Service |
c6b9b0 |
smtp_auth_check_greeting (GDataInputStream *input, GCancellable *cancellable, GError **error)
|
|
Packit Service |
c6b9b0 |
{
|
|
Packit Service |
c6b9b0 |
gboolean ret = FALSE;
|
|
Packit Service |
c6b9b0 |
gchar *response = NULL;
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
greeting_again:
|
|
Packit Service |
c6b9b0 |
response = goa_utils_data_input_stream_read_line (input, NULL, cancellable, error);
|
|
Packit Service |
c6b9b0 |
if (response == NULL)
|
|
Packit Service |
c6b9b0 |
goto out;
|
|
Packit Service |
c6b9b0 |
g_debug ("< %s", response);
|
|
Packit Service |
c6b9b0 |
if (smtp_auth_check_421 (response, error))
|
|
Packit Service |
c6b9b0 |
goto out;
|
|
Packit Service |
c6b9b0 |
if (smtp_auth_check_not_220 (response, error))
|
|
Packit Service |
c6b9b0 |
goto out;
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
if (response[3] == '-')
|
|
Packit Service |
c6b9b0 |
{
|
|
Packit Service |
c6b9b0 |
g_clear_pointer (&response, g_free);
|
|
Packit Service |
c6b9b0 |
goto greeting_again;
|
|
Packit Service |
c6b9b0 |
}
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
ret = TRUE;
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
out:
|
|
Packit Service |
c6b9b0 |
g_free (response);
|
|
Packit Service |
c6b9b0 |
return ret;
|
|
Packit Service |
c6b9b0 |
}
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
/* ---------------------------------------------------------------------------------------------------- */
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
static void
|
|
Packit Service |
c6b9b0 |
goa_smtp_auth_finalize (GObject *object)
|
|
Packit Service |
c6b9b0 |
{
|
|
Packit Service |
c6b9b0 |
GoaSmtpAuth *self = GOA_SMTP_AUTH (object);
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
g_free (self->domain);
|
|
Packit Service |
c6b9b0 |
g_free (self->username);
|
|
Packit Service |
c6b9b0 |
g_free (self->password);
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
G_OBJECT_CLASS (goa_smtp_auth_parent_class)->finalize (object);
|
|
Packit Service |
c6b9b0 |
}
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
static void
|
|
Packit Service |
c6b9b0 |
goa_smtp_auth_get_property (GObject *object,
|
|
Packit Service |
c6b9b0 |
guint prop_id,
|
|
Packit Service |
c6b9b0 |
GValue *value,
|
|
Packit Service |
c6b9b0 |
GParamSpec *pspec)
|
|
Packit Service |
c6b9b0 |
{
|
|
Packit Service |
c6b9b0 |
GoaSmtpAuth *self = GOA_SMTP_AUTH (object);
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
switch (prop_id)
|
|
Packit Service |
c6b9b0 |
{
|
|
Packit Service |
c6b9b0 |
case PROP_DOMAIN:
|
|
Packit Service |
c6b9b0 |
g_value_set_string (value, self->domain);
|
|
Packit Service |
c6b9b0 |
break;
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
case PROP_USERNAME:
|
|
Packit Service |
c6b9b0 |
g_value_set_string (value, self->username);
|
|
Packit Service |
c6b9b0 |
break;
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
case PROP_PASSWORD:
|
|
Packit Service |
c6b9b0 |
g_value_set_string (value, self->password);
|
|
Packit Service |
c6b9b0 |
break;
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
default:
|
|
Packit Service |
c6b9b0 |
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
Packit Service |
c6b9b0 |
break;
|
|
Packit Service |
c6b9b0 |
}
|
|
Packit Service |
c6b9b0 |
}
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
static void
|
|
Packit Service |
c6b9b0 |
goa_smtp_auth_set_property (GObject *object,
|
|
Packit Service |
c6b9b0 |
guint prop_id,
|
|
Packit Service |
c6b9b0 |
const GValue *value,
|
|
Packit Service |
c6b9b0 |
GParamSpec *pspec)
|
|
Packit Service |
c6b9b0 |
{
|
|
Packit Service |
c6b9b0 |
GoaSmtpAuth *self = GOA_SMTP_AUTH (object);
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
switch (prop_id)
|
|
Packit Service |
c6b9b0 |
{
|
|
Packit Service |
c6b9b0 |
case PROP_DOMAIN:
|
|
Packit Service |
c6b9b0 |
self->domain = g_value_dup_string (value);
|
|
Packit Service |
c6b9b0 |
break;
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
case PROP_USERNAME:
|
|
Packit Service |
c6b9b0 |
self->username = g_value_dup_string (value);
|
|
Packit Service |
c6b9b0 |
break;
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
case PROP_PASSWORD:
|
|
Packit Service |
c6b9b0 |
self->password = g_value_dup_string (value);
|
|
Packit Service |
c6b9b0 |
break;
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
default:
|
|
Packit Service |
c6b9b0 |
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
Packit Service |
c6b9b0 |
break;
|
|
Packit Service |
c6b9b0 |
}
|
|
Packit Service |
c6b9b0 |
}
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
/* ---------------------------------------------------------------------------------------------------- */
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
static void
|
|
Packit Service |
c6b9b0 |
goa_smtp_auth_init (GoaSmtpAuth *self)
|
|
Packit Service |
c6b9b0 |
{
|
|
Packit Service |
c6b9b0 |
}
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
static void
|
|
Packit Service |
c6b9b0 |
goa_smtp_auth_class_init (GoaSmtpAuthClass *klass)
|
|
Packit Service |
c6b9b0 |
{
|
|
Packit Service |
c6b9b0 |
GObjectClass *gobject_class;
|
|
Packit Service |
c6b9b0 |
GoaMailAuthClass *auth_class;
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
gobject_class = G_OBJECT_CLASS (klass);
|
|
Packit Service |
c6b9b0 |
gobject_class->finalize = goa_smtp_auth_finalize;
|
|
Packit Service |
c6b9b0 |
gobject_class->get_property = goa_smtp_auth_get_property;
|
|
Packit Service |
c6b9b0 |
gobject_class->set_property = goa_smtp_auth_set_property;
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
auth_class = GOA_MAIL_AUTH_CLASS (klass);
|
|
Packit Service |
c6b9b0 |
auth_class->is_needed = goa_smtp_auth_is_needed;
|
|
Packit Service |
c6b9b0 |
auth_class->run_sync = goa_smtp_auth_run_sync;
|
|
Packit Service |
c6b9b0 |
auth_class->starttls_sync = goa_smtp_auth_starttls_sync;
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
/**
|
|
Packit Service |
c6b9b0 |
* GoaSmtpAuth:domain:
|
|
Packit Service |
c6b9b0 |
*
|
|
Packit Service |
c6b9b0 |
* The domain.
|
|
Packit Service |
c6b9b0 |
*/
|
|
Packit Service |
c6b9b0 |
g_object_class_install_property (gobject_class,
|
|
Packit Service |
c6b9b0 |
PROP_DOMAIN,
|
|
Packit Service |
c6b9b0 |
g_param_spec_string ("domain",
|
|
Packit Service |
c6b9b0 |
"domain",
|
|
Packit Service |
c6b9b0 |
"domain",
|
|
Packit Service |
c6b9b0 |
NULL,
|
|
Packit Service |
c6b9b0 |
G_PARAM_READABLE |
|
|
Packit Service |
c6b9b0 |
G_PARAM_WRITABLE |
|
|
Packit Service |
c6b9b0 |
G_PARAM_CONSTRUCT_ONLY |
|
|
Packit Service |
c6b9b0 |
G_PARAM_STATIC_STRINGS));
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
/**
|
|
Packit Service |
c6b9b0 |
* GoaSmtpAuth:user-name:
|
|
Packit Service |
c6b9b0 |
*
|
|
Packit Service |
c6b9b0 |
* The user name.
|
|
Packit Service |
c6b9b0 |
*/
|
|
Packit Service |
c6b9b0 |
g_object_class_install_property (gobject_class,
|
|
Packit Service |
c6b9b0 |
PROP_USERNAME,
|
|
Packit Service |
c6b9b0 |
g_param_spec_string ("user-name",
|
|
Packit Service |
c6b9b0 |
"user-name",
|
|
Packit Service |
c6b9b0 |
"user-name",
|
|
Packit Service |
c6b9b0 |
NULL,
|
|
Packit Service |
c6b9b0 |
G_PARAM_READABLE |
|
|
Packit Service |
c6b9b0 |
G_PARAM_WRITABLE |
|
|
Packit Service |
c6b9b0 |
G_PARAM_CONSTRUCT_ONLY |
|
|
Packit Service |
c6b9b0 |
G_PARAM_STATIC_STRINGS));
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
/**
|
|
Packit Service |
c6b9b0 |
* GoaSmtpAuth:password:
|
|
Packit Service |
c6b9b0 |
*
|
|
Packit Service |
c6b9b0 |
* The password.
|
|
Packit Service |
c6b9b0 |
*/
|
|
Packit Service |
c6b9b0 |
g_object_class_install_property (gobject_class,
|
|
Packit Service |
c6b9b0 |
PROP_PASSWORD,
|
|
Packit Service |
c6b9b0 |
g_param_spec_string ("password",
|
|
Packit Service |
c6b9b0 |
"password",
|
|
Packit Service |
c6b9b0 |
"password",
|
|
Packit Service |
c6b9b0 |
NULL,
|
|
Packit Service |
c6b9b0 |
G_PARAM_READABLE |
|
|
Packit Service |
c6b9b0 |
G_PARAM_WRITABLE |
|
|
Packit Service |
c6b9b0 |
G_PARAM_CONSTRUCT_ONLY |
|
|
Packit Service |
c6b9b0 |
G_PARAM_STATIC_STRINGS));
|
|
Packit Service |
c6b9b0 |
}
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
/* ---------------------------------------------------------------------------------------------------- */
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
/**
|
|
Packit Service |
c6b9b0 |
* goa_smtp_auth_new:
|
|
Packit Service |
c6b9b0 |
* @domain: The domain to use.
|
|
Packit Service |
c6b9b0 |
* @username: The user name to use.
|
|
Packit Service |
c6b9b0 |
* @password: The password to use.
|
|
Packit Service |
c6b9b0 |
*
|
|
Packit Service |
c6b9b0 |
* Creates a new #GoaMailAuth to be used for username/password
|
|
Packit Service |
c6b9b0 |
* authentication using LOGIN or PLAIN over SMTP.
|
|
Packit Service |
c6b9b0 |
*
|
|
Packit Service |
c6b9b0 |
* Returns: (type GoaSmtpAuth): A #GoaSmtpAuth. Free with
|
|
Packit Service |
c6b9b0 |
* g_object_unref().
|
|
Packit Service |
c6b9b0 |
*/
|
|
Packit Service |
c6b9b0 |
GoaMailAuth *
|
|
Packit Service |
c6b9b0 |
goa_smtp_auth_new (const gchar *domain,
|
|
Packit Service |
c6b9b0 |
const gchar *username,
|
|
Packit Service |
c6b9b0 |
const gchar *password)
|
|
Packit Service |
c6b9b0 |
{
|
|
Packit Service |
c6b9b0 |
g_return_val_if_fail (domain != NULL && domain[0] != '\0', NULL);
|
|
Packit Service |
c6b9b0 |
g_return_val_if_fail (username != NULL, NULL);
|
|
Packit Service |
c6b9b0 |
g_return_val_if_fail (password != NULL && password[0] != '\0', NULL);
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
return GOA_MAIL_AUTH (g_object_new (GOA_TYPE_SMTP_AUTH,
|
|
Packit Service |
c6b9b0 |
"domain", domain,
|
|
Packit Service |
c6b9b0 |
"user-name", username,
|
|
Packit Service |
c6b9b0 |
"password", password,
|
|
Packit Service |
c6b9b0 |
NULL));
|
|
Packit Service |
c6b9b0 |
}
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
/* ---------------------------------------------------------------------------------------------------- */
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
gboolean
|
|
Packit Service |
c6b9b0 |
goa_smtp_auth_is_login (GoaSmtpAuth *self)
|
|
Packit Service |
c6b9b0 |
{
|
|
Packit Service |
c6b9b0 |
return self->login_supported;
|
|
Packit Service |
c6b9b0 |
}
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
gboolean
|
|
Packit Service |
c6b9b0 |
goa_smtp_auth_is_plain (GoaSmtpAuth *self)
|
|
Packit Service |
c6b9b0 |
{
|
|
Packit Service |
c6b9b0 |
return self->plain_supported;
|
|
Packit Service |
c6b9b0 |
}
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
/* ---------------------------------------------------------------------------------------------------- */
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
static gboolean
|
|
Packit Service |
c6b9b0 |
goa_smtp_auth_is_needed (GoaMailAuth *auth)
|
|
Packit Service |
c6b9b0 |
{
|
|
Packit Service |
c6b9b0 |
GoaSmtpAuth *self = GOA_SMTP_AUTH (auth);
|
|
Packit Service |
c6b9b0 |
return self->auth_supported;
|
|
Packit Service |
c6b9b0 |
}
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
/* ---------------------------------------------------------------------------------------------------- */
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
static gboolean
|
|
Packit Service |
c6b9b0 |
goa_smtp_auth_run_sync (GoaMailAuth *auth,
|
|
Packit Service |
c6b9b0 |
GCancellable *cancellable,
|
|
Packit Service |
c6b9b0 |
GError **error)
|
|
Packit Service |
c6b9b0 |
{
|
|
Packit Service |
c6b9b0 |
GoaSmtpAuth *self = GOA_SMTP_AUTH (auth);
|
|
Packit Service |
c6b9b0 |
GDataInputStream *input;
|
|
Packit Service |
c6b9b0 |
GDataOutputStream *output;
|
|
Packit Service |
c6b9b0 |
gboolean ret = FALSE;
|
|
Packit Service |
c6b9b0 |
gchar *auth_arg_base64 = NULL;
|
|
Packit Service |
c6b9b0 |
gchar *auth_arg_plain = NULL;
|
|
Packit Service |
c6b9b0 |
gchar *request = NULL;
|
|
Packit Service |
c6b9b0 |
gchar *response = NULL;
|
|
Packit Service |
c6b9b0 |
gsize auth_arg_plain_len;
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
input = goa_mail_auth_get_input (auth);
|
|
Packit Service |
c6b9b0 |
output = goa_mail_auth_get_output (auth);
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
/* Check the greeting, if there is one */
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
if (!self->greeting_absent)
|
|
Packit Service |
c6b9b0 |
{
|
|
Packit Service |
c6b9b0 |
if (!smtp_auth_check_greeting (input, cancellable, error))
|
|
Packit Service |
c6b9b0 |
goto out;
|
|
Packit Service |
c6b9b0 |
}
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
/* Send EHLO */
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
request = g_strdup_printf ("EHLO %s\r\n", self->domain);
|
|
Packit Service |
c6b9b0 |
g_debug ("> %s", request);
|
|
Packit Service |
c6b9b0 |
if (!g_data_output_stream_put_string (output, request, cancellable, error))
|
|
Packit Service |
c6b9b0 |
goto out;
|
|
Packit Service |
c6b9b0 |
g_clear_pointer (&request, g_free);
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
/* Check which SASL mechanisms are supported */
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
ehlo_again:
|
|
Packit Service |
c6b9b0 |
response = goa_utils_data_input_stream_read_line (input, NULL, cancellable, error);
|
|
Packit Service |
c6b9b0 |
if (response == NULL)
|
|
Packit Service |
c6b9b0 |
goto out;
|
|
Packit Service |
c6b9b0 |
g_debug ("< %s", response);
|
|
Packit Service |
c6b9b0 |
if (smtp_auth_check_421 (response, error))
|
|
Packit Service |
c6b9b0 |
goto out;
|
|
Packit Service |
c6b9b0 |
if (smtp_auth_check_not_250 (response, error))
|
|
Packit Service |
c6b9b0 |
goto out;
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
if (g_str_has_prefix (response + 4, "AUTH"))
|
|
Packit Service |
c6b9b0 |
{
|
|
Packit Service |
c6b9b0 |
self->auth_supported = TRUE;
|
|
Packit Service |
c6b9b0 |
if (strstr (response, "PLAIN") != NULL)
|
|
Packit Service |
c6b9b0 |
self->plain_supported = TRUE;
|
|
Packit Service |
c6b9b0 |
else if (strstr (response, "LOGIN") != NULL)
|
|
Packit Service |
c6b9b0 |
self->login_supported = TRUE;
|
|
Packit Service |
c6b9b0 |
}
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
if (response[3] == '-')
|
|
Packit Service |
c6b9b0 |
{
|
|
Packit Service |
c6b9b0 |
g_free (response);
|
|
Packit Service |
c6b9b0 |
goto ehlo_again;
|
|
Packit Service |
c6b9b0 |
}
|
|
Packit Service |
c6b9b0 |
else if (!self->auth_supported)
|
|
Packit Service |
c6b9b0 |
{
|
|
Packit Service |
c6b9b0 |
ret = TRUE;
|
|
Packit Service |
c6b9b0 |
goto out;
|
|
Packit Service |
c6b9b0 |
}
|
|
Packit Service |
c6b9b0 |
else if (!self->login_supported && !self->plain_supported)
|
|
Packit Service |
c6b9b0 |
{
|
|
Packit Service |
c6b9b0 |
g_set_error (error,
|
|
Packit Service |
c6b9b0 |
GOA_ERROR,
|
|
Packit Service |
c6b9b0 |
GOA_ERROR_NOT_SUPPORTED,
|
|
Packit Service |
c6b9b0 |
_("Unknown authentication mechanism"));
|
|
Packit Service |
c6b9b0 |
goto out;
|
|
Packit Service |
c6b9b0 |
}
|
|
Packit Service |
c6b9b0 |
g_clear_pointer (&response, g_free);
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
/* Try different SASL mechanisms */
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
if (self->plain_supported)
|
|
Packit Service |
c6b9b0 |
{
|
|
Packit Service |
c6b9b0 |
/* AUTH PLAIN */
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
auth_arg_plain = g_strdup_printf ("%s%c%s%c%s", self->username, '\0', self->username, '\0', self->password);
|
|
Packit Service |
c6b9b0 |
auth_arg_plain_len = 2 * strlen (self->username) + 2 + strlen (self->password);
|
|
Packit Service |
c6b9b0 |
auth_arg_base64 = g_base64_encode ((guchar *) auth_arg_plain, auth_arg_plain_len);
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
request = g_strdup_printf ("AUTH PLAIN %s\r\n", auth_arg_base64);
|
|
Packit Service |
c6b9b0 |
g_debug ("> AUTH PLAIN ********************");
|
|
Packit Service |
c6b9b0 |
if (!g_data_output_stream_put_string (output, request, cancellable, error))
|
|
Packit Service |
c6b9b0 |
goto out;
|
|
Packit Service |
c6b9b0 |
g_clear_pointer (&request, g_free);
|
|
Packit Service |
c6b9b0 |
}
|
|
Packit Service |
c6b9b0 |
else
|
|
Packit Service |
c6b9b0 |
{
|
|
Packit Service |
c6b9b0 |
/* AUTH LOGIN */
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
auth_arg_plain = g_strdup (self->username);
|
|
Packit Service |
c6b9b0 |
auth_arg_plain_len = strlen (self->username);
|
|
Packit Service |
c6b9b0 |
auth_arg_base64 = g_base64_encode ((guchar *) auth_arg_plain, auth_arg_plain_len);
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
request = g_strdup_printf ("AUTH LOGIN %s\r\n", auth_arg_base64);
|
|
Packit Service |
c6b9b0 |
g_debug ("> AUTH LOGIN ********************");
|
|
Packit Service |
c6b9b0 |
if (!g_data_output_stream_put_string (output, request, cancellable, error))
|
|
Packit Service |
c6b9b0 |
goto out;
|
|
Packit Service |
c6b9b0 |
g_clear_pointer (&request, g_free);
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
response = goa_utils_data_input_stream_read_line (input, NULL, cancellable, error);
|
|
Packit Service |
c6b9b0 |
if (response == NULL)
|
|
Packit Service |
c6b9b0 |
goto out;
|
|
Packit Service |
c6b9b0 |
g_debug ("< %s", response);
|
|
Packit Service |
c6b9b0 |
if (smtp_auth_check_not_334_login_password (response, error))
|
|
Packit Service |
c6b9b0 |
goto out;
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
g_free (auth_arg_plain);
|
|
Packit Service |
c6b9b0 |
g_free (auth_arg_base64);
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
auth_arg_plain = g_strdup (self->password);
|
|
Packit Service |
c6b9b0 |
auth_arg_plain_len = strlen (self->password);
|
|
Packit Service |
c6b9b0 |
auth_arg_base64 = g_base64_encode ((guchar *) auth_arg_plain, auth_arg_plain_len);
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
request = g_strdup_printf ("%s\r\n", auth_arg_base64);
|
|
Packit Service |
c6b9b0 |
g_debug ("> ********************");
|
|
Packit Service |
c6b9b0 |
if (!g_data_output_stream_put_string (output, request, cancellable, error))
|
|
Packit Service |
c6b9b0 |
goto out;
|
|
Packit Service |
c6b9b0 |
g_clear_pointer (&request, g_free);
|
|
Packit Service |
c6b9b0 |
}
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
response = goa_utils_data_input_stream_read_line (input, NULL, cancellable, error);
|
|
Packit Service |
c6b9b0 |
if (response == NULL)
|
|
Packit Service |
c6b9b0 |
goto out;
|
|
Packit Service |
c6b9b0 |
g_debug ("< %s", response);
|
|
Packit Service |
c6b9b0 |
if (smtp_auth_check_not_235 (response, error))
|
|
Packit Service |
c6b9b0 |
goto out;
|
|
Packit Service |
c6b9b0 |
g_clear_pointer (&response, g_free);
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
ret = TRUE;
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
out:
|
|
Packit Service |
c6b9b0 |
g_free (auth_arg_base64);
|
|
Packit Service |
c6b9b0 |
g_free (auth_arg_plain);
|
|
Packit Service |
c6b9b0 |
g_free (response);
|
|
Packit Service |
c6b9b0 |
g_free (request);
|
|
Packit Service |
c6b9b0 |
return ret;
|
|
Packit Service |
c6b9b0 |
}
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
/* ---------------------------------------------------------------------------------------------------- */
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
static gboolean
|
|
Packit Service |
c6b9b0 |
goa_smtp_auth_starttls_sync (GoaMailAuth *auth,
|
|
Packit Service |
c6b9b0 |
GCancellable *cancellable,
|
|
Packit Service |
c6b9b0 |
GError **error)
|
|
Packit Service |
c6b9b0 |
{
|
|
Packit Service |
c6b9b0 |
GoaSmtpAuth *self = GOA_SMTP_AUTH (auth);
|
|
Packit Service |
c6b9b0 |
GDataInputStream *input;
|
|
Packit Service |
c6b9b0 |
GDataOutputStream *output;
|
|
Packit Service |
c6b9b0 |
gboolean ret = FALSE;
|
|
Packit Service |
c6b9b0 |
gboolean starttls_supported = FALSE;
|
|
Packit Service |
c6b9b0 |
gchar *request = NULL;
|
|
Packit Service |
c6b9b0 |
gchar *response = NULL;
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
input = goa_mail_auth_get_input (auth);
|
|
Packit Service |
c6b9b0 |
output = goa_mail_auth_get_output (auth);
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
/* Check the greeting */
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
if (!smtp_auth_check_greeting (input, cancellable, error))
|
|
Packit Service |
c6b9b0 |
goto out;
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
/* Send EHLO */
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
request = g_strdup_printf ("EHLO %s\r\n", self->domain);
|
|
Packit Service |
c6b9b0 |
g_debug ("> %s", request);
|
|
Packit Service |
c6b9b0 |
if (!g_data_output_stream_put_string (output, request, cancellable, error))
|
|
Packit Service |
c6b9b0 |
goto out;
|
|
Packit Service |
c6b9b0 |
g_clear_pointer (&request, g_free);
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
/* Check if STARTTLS is supported or not */
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
ehlo_again:
|
|
Packit Service |
c6b9b0 |
response = goa_utils_data_input_stream_read_line (input, NULL, cancellable, error);
|
|
Packit Service |
c6b9b0 |
if (response == NULL)
|
|
Packit Service |
c6b9b0 |
goto out;
|
|
Packit Service |
c6b9b0 |
g_debug ("< %s", response);
|
|
Packit Service |
c6b9b0 |
if (smtp_auth_check_421 (response, error))
|
|
Packit Service |
c6b9b0 |
goto out;
|
|
Packit Service |
c6b9b0 |
if (smtp_auth_check_not_250 (response, error))
|
|
Packit Service |
c6b9b0 |
goto out;
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
if (g_str_has_prefix (response + 4, "STARTTLS"))
|
|
Packit Service |
c6b9b0 |
starttls_supported = TRUE;
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
if (response[3] == '-')
|
|
Packit Service |
c6b9b0 |
{
|
|
Packit Service |
c6b9b0 |
g_free (response);
|
|
Packit Service |
c6b9b0 |
goto ehlo_again;
|
|
Packit Service |
c6b9b0 |
}
|
|
Packit Service |
c6b9b0 |
else if (!starttls_supported)
|
|
Packit Service |
c6b9b0 |
{
|
|
Packit Service |
c6b9b0 |
g_set_error (error,
|
|
Packit Service |
c6b9b0 |
GOA_ERROR,
|
|
Packit Service |
c6b9b0 |
GOA_ERROR_NOT_SUPPORTED,
|
|
Packit Service |
c6b9b0 |
_("Server does not support STARTTLS"));
|
|
Packit Service |
c6b9b0 |
goto out;
|
|
Packit Service |
c6b9b0 |
}
|
|
Packit Service |
c6b9b0 |
g_clear_pointer (&response, g_free);
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
/* Send STARTTLS */
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
request = g_strdup ("STARTTLS\r\n");
|
|
Packit Service |
c6b9b0 |
g_debug ("> %s", request);
|
|
Packit Service |
c6b9b0 |
if (!g_data_output_stream_put_string (output, request, cancellable, error))
|
|
Packit Service |
c6b9b0 |
goto out;
|
|
Packit Service |
c6b9b0 |
g_clear_pointer (&request, g_free);
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
response = goa_utils_data_input_stream_read_line (input, NULL, cancellable, error);
|
|
Packit Service |
c6b9b0 |
if (response == NULL)
|
|
Packit Service |
c6b9b0 |
goto out;
|
|
Packit Service |
c6b9b0 |
g_debug ("< %s", response);
|
|
Packit Service |
c6b9b0 |
if (smtp_auth_check_454 (response, error))
|
|
Packit Service |
c6b9b0 |
goto out;
|
|
Packit Service |
c6b9b0 |
if (smtp_auth_check_not_220 (response, error))
|
|
Packit Service |
c6b9b0 |
goto out;
|
|
Packit Service |
c6b9b0 |
g_clear_pointer (&response, g_free);
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
/* There won't be a greeting after this */
|
|
Packit Service |
c6b9b0 |
self->greeting_absent = TRUE;
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
ret = TRUE;
|
|
Packit Service |
c6b9b0 |
|
|
Packit Service |
c6b9b0 |
out:
|
|
Packit Service |
c6b9b0 |
g_free (response);
|
|
Packit Service |
c6b9b0 |
g_free (request);
|
|
Packit Service |
c6b9b0 |
return ret;
|
|
Packit Service |
c6b9b0 |
}
|