summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEitan Isaacson <eitan@monotonous.org>2010-05-22 09:01:15 -0700
committerEitan Isaacson <eitan@monotonous.org>2010-06-02 22:32:09 -0700
commit689eea8705dc3050740b024403d383e02b347ac8 (patch)
tree0eea4613038556f266e2a0ecad156527f10df44d
parentbb23e7068b2f60478f715b4b6b3b6d88c8054766 (diff)
Added server SASL channel and auth manager.
-rw-r--r--src/Makefile.am4
-rw-r--r--src/auth-manager.c259
-rw-r--r--src/auth-manager.h67
-rw-r--r--src/connection-manager.c3
-rw-r--r--src/connection.c16
-rw-r--r--src/debug.c45
-rw-r--r--src/debug.h3
-rw-r--r--src/gabble.c2
-rw-r--r--src/server-sasl-channel.c1014
-rw-r--r--src/server-sasl-channel.h78
10 files changed, 1461 insertions, 30 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 216e88476..d0a6e7f4d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -9,6 +9,8 @@ libexec_PROGRAMS=telepathy-gabble
noinst_PROGRAMS = write-mgr-file
libgabble_convenience_la_SOURCES = \
+ auth-manager.h \
+ auth-manager.c \
base64.h \
base64.c \
base-channel.h \
@@ -152,6 +154,8 @@ libgabble_convenience_la_SOURCES = \
search-channel.c \
search-manager.h \
search-manager.c \
+ server-sasl-channel.h \
+ server-sasl-channel.c \
$(top_srcdir)/gabble/sidecar.h \
sidecar.c \
tube-iface.h \
diff --git a/src/auth-manager.c b/src/auth-manager.c
new file mode 100644
index 000000000..a3ebb9023
--- /dev/null
+++ b/src/auth-manager.c
@@ -0,0 +1,259 @@
+/*
+ * auth-manager.c - TpChannelManager implementation for auth channels
+ * Copyright (C) 2010 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+#include "auth-manager.h"
+
+#include <telepathy-glib/channel-manager.h>
+#include <telepathy-glib/dbus.h>
+#include <telepathy-glib/interfaces.h>
+
+#define DEBUG_FLAG GABBLE_DEBUG_AUTH
+
+#include "extensions/extensions.h"
+
+#include "caps-channel-manager.h"
+#include "server-sasl-channel.h"
+#include "connection.h"
+#include "debug.h"
+#include "util.h"
+
+static void channel_manager_iface_init (gpointer, gpointer);
+
+G_DEFINE_TYPE_WITH_CODE (GabbleAuthManager, gabble_auth_manager,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_MANAGER,
+ channel_manager_iface_init);
+ G_IMPLEMENT_INTERFACE (GABBLE_TYPE_CAPS_CHANNEL_MANAGER,
+ NULL));
+
+/* properties */
+enum
+{
+ PROP_CONNECTION = 1,
+ LAST_PROPERTY
+};
+
+struct _GabbleAuthManagerPrivate
+{
+ GabbleConnection *conn;
+
+ /* Used to represent a set of channels.
+ * Keys are GabbleCertificateChannel *, values are an arbitrary non-NULL pointer.
+ */
+ GabbleServerSaslChannel *server_sasl_channel;
+
+ GSimpleAsyncResult *result;
+
+ gboolean dispose_has_run;
+};
+
+static const gchar * const server_sasl_channel_fixed_properties[] = {
+ TP_IFACE_CHANNEL ".ChannelType",
+ NULL
+};
+
+static const gchar * const server_sasl_channel_allowed_properties[] = {
+ NULL
+};
+
+static void
+gabble_auth_manager_init (GabbleAuthManager *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GABBLE_TYPE_AUTH_MANAGER,
+ GabbleAuthManagerPrivate);
+}
+
+static void
+gabble_auth_manager_close_all (GabbleAuthManager *self)
+{
+ DEBUG ("called");
+ gabble_server_sasl_channel_close (self->priv->server_sasl_channel);
+}
+
+static void
+connection_status_changed_cb (GabbleConnection *conn,
+ guint status,
+ guint reason,
+ GabbleAuthManager *self)
+{
+ if (status == TP_CONNECTION_STATUS_DISCONNECTED)
+ gabble_auth_manager_close_all (self);
+}
+
+static void
+auth_channel_destroyed_cb (GObject *sender,
+ GParamSpec *pspec,
+ GabbleAuthManager *self)
+{
+ if (gabble_server_sasl_channel_is_open (GABBLE_SERVER_SASL_CHANNEL (sender)))
+ tp_channel_manager_emit_new_channel (self, TP_EXPORTABLE_CHANNEL (sender),
+ NULL);
+}
+
+static void
+auth_channel_closed_cb (GObject *sender,
+ GabbleAuthManager *self)
+{
+ tp_channel_manager_emit_channel_closed_for_object (self,
+ TP_EXPORTABLE_CHANNEL (sender));
+}
+
+static GObject *
+gabble_auth_manager_constructor (GType type,
+ guint n_props,
+ GObjectConstructParam *props)
+{
+ GObject *obj = G_OBJECT_CLASS (gabble_auth_manager_parent_class)->
+ constructor (type, n_props, props);
+ GabbleAuthManager *self = GABBLE_AUTH_MANAGER (obj);
+ GabbleServerSaslChannel *chan = gabble_server_sasl_channel_new (
+ self->priv->conn);
+
+ self->priv->dispose_has_run = FALSE;
+
+ gabble_signal_connect_weak (self->priv->conn, "status-changed",
+ G_CALLBACK (connection_status_changed_cb), obj);
+
+ self->priv->server_sasl_channel = chan;
+
+ g_signal_connect (G_OBJECT (chan), "closed",
+ G_CALLBACK (auth_channel_closed_cb), self);
+
+ g_signal_connect (G_OBJECT (chan), "notify::channel-destroyed",
+ G_CALLBACK (auth_channel_destroyed_cb), self);
+
+ return obj;
+}
+
+static void
+gabble_auth_manager_dispose (GObject *object)
+{
+ GabbleAuthManager *self = GABBLE_AUTH_MANAGER (object);
+ GabbleAuthManagerPrivate *priv = self->priv;
+
+ if (priv->dispose_has_run)
+ return;
+
+ DEBUG ("dispose called");
+ priv->dispose_has_run = TRUE;
+
+ gabble_auth_manager_close_all (self);
+
+ if (priv->server_sasl_channel)
+ g_object_unref (priv->server_sasl_channel);
+
+ if (G_OBJECT_CLASS (gabble_auth_manager_parent_class)->dispose)
+ G_OBJECT_CLASS (
+ gabble_auth_manager_parent_class)->dispose (object);
+}
+
+static void
+gabble_auth_manager_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GabbleAuthManager *self = GABBLE_AUTH_MANAGER (object);
+
+ switch (property_id) {
+ case PROP_CONNECTION:
+ g_value_set_object (value, self->priv->conn);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gabble_auth_manager_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GabbleAuthManager *self = GABBLE_AUTH_MANAGER (object);
+
+ switch (property_id) {
+ case PROP_CONNECTION:
+ self->priv->conn = g_value_get_object (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gabble_auth_manager_class_init (GabbleAuthManagerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ GParamSpec *param_spec;
+
+ g_type_class_add_private (klass,
+ sizeof (GabbleAuthManagerPrivate));
+
+ object_class->constructor = gabble_auth_manager_constructor;
+ object_class->dispose = gabble_auth_manager_dispose;
+
+ object_class->get_property = gabble_auth_manager_get_property;
+ object_class->set_property = gabble_auth_manager_set_property;
+
+ param_spec = g_param_spec_object ("connection", "GabbleConnection object",
+ "Gabble connection object that owns this manager.",
+ GABBLE_TYPE_CONNECTION,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_CONNECTION, param_spec);
+}
+
+static void
+gabble_auth_manager_foreach_channel (TpChannelManager *manager,
+ TpExportableChannelFunc func,
+ gpointer user_data)
+{
+ GabbleAuthManager *self = GABBLE_AUTH_MANAGER (manager);
+
+ if (gabble_server_sasl_channel_is_open (self->priv->server_sasl_channel))
+ func (TP_EXPORTABLE_CHANNEL (self->priv->server_sasl_channel), user_data);
+}
+
+static void
+channel_manager_iface_init (gpointer g_iface,
+ gpointer iface_data)
+{
+ TpChannelManagerIface *iface = g_iface;
+
+ iface->foreach_channel = gabble_auth_manager_foreach_channel;
+
+ /* These channels are not requestable. */
+ iface->ensure_channel = NULL;
+ iface->create_channel = NULL;
+ iface->request_channel = NULL;
+ iface->foreach_channel_class = NULL;
+}
+
+WockyAuthRegistry *
+gabble_auth_manager_get_auth_registry (GabbleAuthManager *self)
+{
+ g_return_val_if_fail (
+ WOCKY_IS_AUTH_REGISTRY (self->priv->server_sasl_channel), NULL);
+
+ return WOCKY_AUTH_REGISTRY (self->priv->server_sasl_channel);
+}
diff --git a/src/auth-manager.h b/src/auth-manager.h
new file mode 100644
index 000000000..114512fcd
--- /dev/null
+++ b/src/auth-manager.h
@@ -0,0 +1,67 @@
+/*
+ * auth-manager.h - Header for GabbleAuthManager
+ * Copyright (C) 2010 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __AUTH_MANAGER_H__
+#define __AUTH_MANAGER_H__
+
+#include <glib-object.h>
+#include <wocky/wocky-auth-registry.h>
+#include <telepathy-glib/handle.h>
+
+#include "extensions/extensions.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GabbleAuthManager GabbleAuthManager;
+typedef struct _GabbleAuthManagerClass GabbleAuthManagerClass;
+typedef struct _GabbleAuthManagerPrivate GabbleAuthManagerPrivate;
+
+struct _GabbleAuthManagerClass {
+ GObjectClass parent_class;
+};
+
+struct _GabbleAuthManager {
+ GObject parent;
+ GabbleAuthManagerPrivate *priv;
+};
+
+GType gabble_auth_manager_get_type (void);
+
+/* TYPE MACROS */
+#define GABBLE_TYPE_AUTH_MANAGER \
+ (gabble_auth_manager_get_type ())
+#define GABBLE_AUTH_MANAGER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), GABBLE_TYPE_AUTH_MANAGER, GabbleAuthManager))
+#define GABBLE_AUTH_MANAGER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), GABBLE_TYPE_AUTH_MANAGER,\
+ GabbleAuthManagerClass))
+#define GABBLE_IS_AUTH_MANAGER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), GABBLE_TYPE_AUTH_MANAGER))
+#define GABBLE_IS_AUTH_MANAGER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), GABBLE_TYPE_AUTH_MANAGER))
+#define GABBLE_AUTH_MANAGER_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), GABBLE_TYPE_AUTH_MANAGER,\
+ GabbleAuthManagerClass))
+
+WockyAuthRegistry *gabble_auth_manager_get_auth_registry (
+ GabbleAuthManager *self);
+
+G_END_DECLS
+
+#endif /* #ifndef __AUTH_MANAGER_H__ */
diff --git a/src/connection-manager.c b/src/connection-manager.c
index 9a8479ebe..4566355fa 100644
--- a/src/connection-manager.c
+++ b/src/connection-manager.c
@@ -134,8 +134,7 @@ static TpCMParamSpec jabber_params[] = {
/* FIXME: validate the JID according to the RFC */
tp_cm_param_filter_string_nonempty, NULL },
{ "password", DBUS_TYPE_STRING_AS_STRING, G_TYPE_STRING,
- TP_CONN_MGR_PARAM_FLAG_REQUIRED | TP_CONN_MGR_PARAM_FLAG_REGISTER |
- TP_CONN_MGR_PARAM_FLAG_SECRET,
+ TP_CONN_MGR_PARAM_FLAG_REGISTER | TP_CONN_MGR_PARAM_FLAG_SECRET,
NULL,
G_STRUCT_OFFSET(GabbleParams, password), NULL, NULL },
diff --git a/src/connection.c b/src/connection.c
index 2209e1dec..dad9017a6 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -51,6 +51,7 @@
#include "capabilities.h"
#include "caps-channel-manager.h"
#include "caps-hash.h"
+#include "auth-manager.h"
#include "conn-aliasing.h"
#include "conn-avatars.h"
#include "conn-contact-info.h"
@@ -230,6 +231,9 @@ struct _GabbleConnectionPrivate
/* the union of the above */
GabbleCapabilitySet *all_caps;
+ /* auth manager */
+ GabbleAuthManager *auth_manager;
+
/* stream id returned by the connector */
gchar *stream_id;
@@ -276,6 +280,10 @@ _gabble_connection_create_channel_managers (TpBaseConnection *conn)
"connection", self,
NULL));
+ self->priv->auth_manager = g_object_new (GABBLE_TYPE_AUTH_MANAGER,
+ "connection", self, NULL);
+ g_ptr_array_add (channel_managers, self->priv->auth_manager);
+
self->muc_factory = g_object_new (GABBLE_TYPE_MUC_FACTORY,
"connection", self,
NULL);
@@ -1036,6 +1044,7 @@ gabble_connection_dispose (GObject *object)
self->roster = NULL;
self->muc_factory = NULL;
self->private_tubes_factory = NULL;
+ priv->auth_manager = NULL;
if (self->self_presence != NULL)
g_object_unref (self->self_presence);
@@ -1546,8 +1555,6 @@ connector_error_disconnect (GabbleConnection *self,
case WOCKY_AUTH_ERROR_NETWORK:
case WOCKY_AUTH_ERROR_CONNRESET:
case WOCKY_AUTH_ERROR_STREAM:
- case WOCKY_AUTH_ERROR_INVALID_REPLY:
- case WOCKY_AUTH_ERROR_NO_SUPPORTED_MECHANISMS:
reason = TP_CONNECTION_STATUS_REASON_NETWORK_ERROR;
break;
default:
@@ -1838,6 +1845,8 @@ disconnect_callbacks (TpBaseConnection *base)
GabbleConnection *conn = GABBLE_CONNECTION (base);
GabbleConnectionPrivate *priv = conn->priv;
+ DEBUG ("");
+
g_assert (priv->iq_disco_cb != NULL);
g_assert (priv->iq_unknown_cb != NULL);
g_assert (priv->olpc_msg_cb != NULL);
@@ -1889,12 +1898,11 @@ _gabble_connection_connect (TpBaseConnection *base,
g_assert (priv->port <= G_MAXUINT16);
g_assert (priv->stream_server != NULL);
g_assert (priv->username != NULL);
- g_assert (priv->password != NULL);
g_assert (priv->resource != NULL);
jid = gabble_encode_jid (priv->username, priv->stream_server, NULL);
priv->connector = wocky_connector_new (jid, priv->password, priv->resource,
- NULL);
+ gabble_auth_manager_get_auth_registry (priv->auth_manager));
g_free (jid);
/* system certs */
diff --git a/src/debug.c b/src/debug.c
index c664f7d28..75625a3eb 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -24,28 +24,29 @@
static GabbleDebugFlags flags = 0;
static GDebugKey keys[] = {
- { "presence", GABBLE_DEBUG_PRESENCE },
- { "groups", GABBLE_DEBUG_GROUPS },
- { "roster", GABBLE_DEBUG_ROSTER },
- { "disco", GABBLE_DEBUG_DISCO },
- { "properties", GABBLE_DEBUG_PROPERTIES },
- { "roomlist", GABBLE_DEBUG_ROOMLIST },
- { "media-channel", GABBLE_DEBUG_MEDIA },
- { "im", GABBLE_DEBUG_IM },
- { "muc", GABBLE_DEBUG_MUC },
- { "connection", GABBLE_DEBUG_CONNECTION },
- { "vcard", GABBLE_DEBUG_VCARD },
- { "pipeline", GABBLE_DEBUG_PIPELINE },
- { "jid", GABBLE_DEBUG_JID },
- { "olpc", GABBLE_DEBUG_OLPC },
- { "bytestream", GABBLE_DEBUG_BYTESTREAM },
- { "tubes", GABBLE_DEBUG_TUBES },
- { "location", GABBLE_DEBUG_LOCATION },
- { "file-transfer", GABBLE_DEBUG_FT },
- { "search", GABBLE_DEBUG_SEARCH },
- { "base-channel", GABBLE_DEBUG_BASE_CHANNEL },
- { "plugins", GABBLE_DEBUG_PLUGINS },
- { "mail", GABBLE_DEBUG_MAIL_NOTIF },
+ { "presence", GABBLE_DEBUG_PRESENCE },
+ { "groups", GABBLE_DEBUG_GROUPS },
+ { "roster", GABBLE_DEBUG_ROSTER },
+ { "disco", GABBLE_DEBUG_DISCO },
+ { "properties", GABBLE_DEBUG_PROPERTIES },
+ { "roomlist", GABBLE_DEBUG_ROOMLIST },
+ { "media-channel", GABBLE_DEBUG_MEDIA },
+ { "im", GABBLE_DEBUG_IM },
+ { "muc", GABBLE_DEBUG_MUC },
+ { "connection", GABBLE_DEBUG_CONNECTION },
+ { "vcard", GABBLE_DEBUG_VCARD },
+ { "pipeline", GABBLE_DEBUG_PIPELINE },
+ { "jid", GABBLE_DEBUG_JID },
+ { "olpc", GABBLE_DEBUG_OLPC },
+ { "bytestream", GABBLE_DEBUG_BYTESTREAM },
+ { "tubes", GABBLE_DEBUG_TUBES },
+ { "location", GABBLE_DEBUG_LOCATION },
+ { "file-transfer", GABBLE_DEBUG_FT },
+ { "search", GABBLE_DEBUG_SEARCH },
+ { "base-channel", GABBLE_DEBUG_BASE_CHANNEL },
+ { "plugins", GABBLE_DEBUG_PLUGINS },
+ { "mail", GABBLE_DEBUG_MAIL_NOTIF },
+ { "authentication", GABBLE_DEBUG_AUTH },
{ 0, },
};
diff --git a/src/debug.h b/src/debug.h
index 348e0a803..4ccb2fc28 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -33,7 +33,8 @@ typedef enum
GABBLE_DEBUG_SEARCH = 1 << 19,
GABBLE_DEBUG_BASE_CHANNEL = 1 << 20,
GABBLE_DEBUG_PLUGINS = 1 << 21,
- GABBLE_DEBUG_MAIL_NOTIF = 1 << 22
+ GABBLE_DEBUG_MAIL_NOTIF = 1 << 22,
+ GABBLE_DEBUG_AUTH = 1 << 23
} GabbleDebugFlags;
void gabble_debug_set_flags_from_env (void);
diff --git a/src/gabble.c b/src/gabble.c
index 744e2f57c..382d4e397 100644
--- a/src/gabble.c
+++ b/src/gabble.c
@@ -134,7 +134,7 @@ gabble_main (int argc,
if (g_getenv ("WOCKY_DEBUG") == NULL)
{
redirect_wocky = TRUE;
- wocky_debug_set_flags (DEBUG_XMPP | DEBUG_PORTER);
+ wocky_debug_set_flags (DEBUG_XMPP | DEBUG_AUTH | DEBUG_PORTER);
}
debug_sender = tp_debug_sender_dup ();
diff --git a/src/server-sasl-channel.c b/src/server-sasl-channel.c
new file mode 100644
index 000000000..f1871c36c
--- /dev/null
+++ b/src/server-sasl-channel.c
@@ -0,0 +1,1014 @@
+/*
+ * server-sasl-channel.c - Source for GabbleServerSaslChannel
+ * Copyright (C) 2010 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+#include "server-sasl-channel.h"
+#include "gabble-signals-marshal.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <glib/gstdio.h>
+#include <gio/gio.h>
+#include <dbus/dbus-glib.h>
+#include <wocky/wocky-auth-registry.h>
+#include <wocky/wocky-utils.h>
+
+#include <telepathy-glib/channel-iface.h>
+#include <telepathy-glib/dbus.h>
+#include <telepathy-glib/enums.h>
+#include <telepathy-glib/errors.h>
+#include <telepathy-glib/exportable-channel.h>
+#include <telepathy-glib/gtypes.h>
+#include <telepathy-glib/interfaces.h>
+#include <telepathy-glib/svc-channel.h>
+#include <telepathy-glib/svc-generic.h>
+
+#define DEBUG_FLAG GABBLE_DEBUG_AUTH
+
+#include "connection.h"
+#include "debug.h"
+#include "namespaces.h"
+#include "util.h"
+
+static void channel_iface_init (gpointer, gpointer);
+static void sasl_auth_iface_init (gpointer, gpointer);
+
+static void gabble_server_sasl_channel_start_auth_async_func (
+ WockyAuthRegistry *auth_registry,
+ const GSList *mechanisms,
+ gboolean allow_plain,
+ gboolean is_secure_channel,
+ const gchar *username,
+ const gchar *password,
+ const gchar *server,
+ const gchar *session_id,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+static void gabble_server_sasl_channel_challenge_async_func (
+ WockyAuthRegistry *auth_registry,
+ const GString *challenge_data,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+static void gabble_server_sasl_channel_server_success_async_func (
+ WockyAuthRegistry *auth_registry,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+static void gabble_server_sasl_channel_failure_func (
+ WockyAuthRegistry *auth_registry,
+ GError *error);
+
+G_DEFINE_TYPE_WITH_CODE (GabbleServerSaslChannel, gabble_server_sasl_channel,
+ WOCKY_TYPE_AUTH_REGISTRY,
+ G_IMPLEMENT_INTERFACE (
+ TP_TYPE_SVC_CHANNEL,
+ channel_iface_init);
+ G_IMPLEMENT_INTERFACE (
+ TP_TYPE_SVC_DBUS_PROPERTIES,
+ tp_dbus_properties_mixin_iface_init);
+ G_IMPLEMENT_INTERFACE (
+ TP_TYPE_CHANNEL_IFACE,
+ NULL);
+ G_IMPLEMENT_INTERFACE (
+ TP_TYPE_EXPORTABLE_CHANNEL,
+ NULL);
+ G_IMPLEMENT_INTERFACE (
+ GABBLE_TYPE_SVC_CHANNEL_TYPE_SERVER_AUTHENTICATION,
+ NULL);
+ G_IMPLEMENT_INTERFACE (
+ GABBLE_TYPE_SVC_CHANNEL_INTERFACE_SASL_AUTHENTICATION,
+ sasl_auth_iface_init));
+
+static const gchar *gabble_server_sasl_channel_interfaces[] = {
+ GABBLE_IFACE_CHANNEL_TYPE_SERVER_AUTHENTICATION,
+ GABBLE_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION,
+ NULL
+};
+
+enum
+{
+ /* channel iface */
+ PROP_OBJECT_PATH = 1,
+ PROP_CHANNEL_TYPE,
+ PROP_HANDLE_TYPE,
+ PROP_HANDLE,
+ PROP_INITIATOR_HANDLE,
+ PROP_INITIATOR_ID,
+ PROP_TARGET_ID,
+ PROP_REQUESTED,
+ PROP_CONNECTION,
+ PROP_INTERFACES,
+ PROP_CHANNEL_DESTROYED,
+ PROP_CHANNEL_PROPERTIES,
+
+ /* server authentication channel */
+ PROP_AUTH_INFO,
+ PROP_AUTH_METHOD,
+
+ /* sasl authentication channel */
+ PROP_CURRENT_STATE,
+ PROP_MECHANISM,
+ PROP_CHALLENGE,
+ PROP_AVAILABLE_MECHANISMS,
+
+ LAST_PROPERTY,
+};
+
+/* private structure */
+
+struct _GabbleServerSaslChannelPrivate
+{
+ gboolean dispose_has_run;
+
+ /* Channel Iface */
+ gchar *object_path;
+ GabbleConnection *conn;
+ gboolean closed;
+
+ /* Server Authentication Iface*/
+ GHashTable *auth_info;
+
+ /* SASL Auth Iface */
+ gchar **available_mechanisms;
+ GValueArray *current_state;
+ GArray *challenge;
+ gchar *mechanism;
+
+ GSimpleAsyncResult *result;
+};
+
+static void
+gabble_server_sasl_channel_init (GabbleServerSaslChannel *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ GABBLE_TYPE_SERVER_SASL_CHANNEL, GabbleServerSaslChannelPrivate);
+}
+
+static GObject *
+gabble_server_sasl_channel_constructor (GType type,
+ guint n_props,
+ GObjectConstructParam *props)
+{
+ GObject *obj;
+ GabbleServerSaslChannel *self;
+ GabbleServerSaslChannelPrivate *priv;
+
+ obj = G_OBJECT_CLASS (gabble_server_sasl_channel_parent_class)->
+ constructor (type, n_props, props);
+
+ self = GABBLE_SERVER_SASL_CHANNEL (obj);
+ priv = self->priv;
+
+ priv->challenge = g_array_new (FALSE, FALSE, sizeof (gchar));
+
+ priv->closed = TRUE;
+
+ priv->current_state = tp_value_array_build (3,
+ G_TYPE_UINT, GABBLE_SASL_STATUS_NOT_STARTED,
+ G_TYPE_STRING, "",
+ G_TYPE_STRING, "",
+ G_TYPE_INVALID);
+
+ return obj;
+}
+
+static void
+gabble_server_sasl_channel_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GabbleServerSaslChannel *chan =
+ GABBLE_SERVER_SASL_CHANNEL (object);
+ GabbleServerSaslChannelPrivate *priv = chan->priv;
+
+ switch (property_id)
+ {
+ case PROP_OBJECT_PATH:
+ g_value_set_string (value, priv->object_path);
+ break;
+ case PROP_CHANNEL_TYPE:
+ g_value_set_static_string (value,
+ GABBLE_IFACE_CHANNEL_TYPE_SERVER_AUTHENTICATION);
+ break;
+ case PROP_HANDLE_TYPE:
+ g_value_set_uint (value, TP_HANDLE_TYPE_NONE);
+ break;
+ case PROP_HANDLE:
+ g_value_set_uint (value, 0);
+ break;
+ case PROP_TARGET_ID:
+ g_value_set_static_string (value, "");
+ break;
+ case PROP_INITIATOR_HANDLE:
+ g_value_set_uint (value, 0);
+ break;
+ case PROP_INITIATOR_ID:
+ g_value_set_static_string (value, "");
+ break;
+ case PROP_REQUESTED:
+ g_value_set_boolean (value, FALSE);
+ break;
+ case PROP_CONNECTION:
+ g_value_set_object (value, priv->conn);
+ break;
+ case PROP_INTERFACES:
+ g_value_set_boxed (value, gabble_server_sasl_channel_interfaces);
+ break;
+ case PROP_CHANNEL_DESTROYED:
+ g_value_set_boolean (value, priv->closed);
+ break;
+ case PROP_CHANNEL_PROPERTIES:
+ g_value_take_boxed (value,
+ tp_dbus_properties_mixin_make_properties_hash (object,
+ TP_IFACE_CHANNEL, "TargetHandle",
+ TP_IFACE_CHANNEL, "TargetHandleType",
+ TP_IFACE_CHANNEL, "ChannelType",
+ TP_IFACE_CHANNEL, "TargetID",
+ TP_IFACE_CHANNEL, "InitiatorHandle",
+ TP_IFACE_CHANNEL, "InitiatorID",
+ TP_IFACE_CHANNEL, "Requested",
+ TP_IFACE_CHANNEL, "Interfaces",
+ GABBLE_IFACE_CHANNEL_TYPE_SERVER_AUTHENTICATION,
+ "AuthenticationInformation",
+ GABBLE_IFACE_CHANNEL_TYPE_SERVER_AUTHENTICATION,
+ "AuthenticationMethod",
+ GABBLE_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION,
+ "AvailableMechanisms",
+ NULL));
+ break;
+ case PROP_CURRENT_STATE:
+ g_value_set_boxed (value, priv->current_state);
+ break;
+ case PROP_AUTH_INFO:
+ g_value_set_boxed (value, priv->auth_info);
+ break;
+ case PROP_AUTH_METHOD:
+ g_value_set_uint (value, GABBLE_AUTHENTICATION_TYPE_SASL);
+ break;
+ case PROP_MECHANISM:
+ g_value_set_string (value, priv->mechanism);
+ break;
+ case PROP_AVAILABLE_MECHANISMS:
+ DEBUG ("Sending available mechs: (%p) %s",
+ chan->priv->available_mechanisms,
+ chan->priv->available_mechanisms[0]);
+ g_value_set_boxed (value, chan->priv->available_mechanisms);
+ break;
+ case PROP_CHALLENGE:
+ g_value_set_boxed (value, chan->priv->challenge);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gabble_server_sasl_channel_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GabbleServerSaslChannel *chan = GABBLE_SERVER_SASL_CHANNEL (object);
+ GabbleServerSaslChannelPrivate *priv = chan->priv;
+
+ switch (property_id)
+ {
+ case PROP_CONNECTION:
+ priv->conn = g_value_get_object (value);
+ break;
+ case PROP_OBJECT_PATH:
+ case PROP_CHANNEL_TYPE:
+ case PROP_HANDLE_TYPE:
+ case PROP_HANDLE:
+ /* no-op */
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gabble_server_sasl_channel_dispose (GObject *object)
+{
+ GabbleServerSaslChannel *self = GABBLE_SERVER_SASL_CHANNEL (object);
+ GabbleServerSaslChannelPrivate *priv = self->priv;
+
+ DEBUG ("disposed");
+
+ if (priv->dispose_has_run)
+ return;
+
+ priv->dispose_has_run = TRUE;
+
+ gabble_server_sasl_channel_close (self);
+
+ g_free (priv->mechanism);
+
+ g_free (priv->object_path);
+
+ g_strfreev (priv->available_mechanisms);
+
+ g_value_array_free (priv->current_state);
+
+ g_array_free (priv->challenge, TRUE);
+
+ if (priv->auth_info != NULL)
+ g_hash_table_unref (priv->auth_info);
+
+ if (G_OBJECT_CLASS (gabble_server_sasl_channel_parent_class)->dispose)
+ G_OBJECT_CLASS (gabble_server_sasl_channel_parent_class)->dispose (object);
+}
+
+static void
+gabble_server_sasl_channel_class_init (GabbleServerSaslChannelClass *klass)
+{
+ static TpDBusPropertiesMixinPropImpl channel_props[] = {
+ { "TargetHandleType", "handle-type", NULL },
+ { "TargetHandle", "handle", NULL },
+ { "TargetID", "target-id", NULL },
+ { "ChannelType", "channel-type", NULL },
+ { "Interfaces", "interfaces", NULL },
+ { "Requested", "requested", NULL },
+ { "InitiatorHandle", "initiator-handle", NULL },
+ { "InitiatorID", "initiator-id", NULL },
+ { NULL }
+ };
+
+ static TpDBusPropertiesMixinPropImpl server_auth_props[] = {
+ { "AuthenticationInformation", "auth-info", NULL },
+ { "AuthenticationMethod", "auth-method", NULL },
+ { NULL }
+ };
+
+ static TpDBusPropertiesMixinPropImpl sasl_auth_props[] = {
+ { "CurrentState", "current-state", NULL },
+ { "AvailableMechanisms", "available-mechanisms", NULL },
+ { "CurrentChallenge", "challenge", NULL },
+ { NULL }
+ };
+
+ static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = {
+ { TP_IFACE_CHANNEL,
+ tp_dbus_properties_mixin_getter_gobject_properties,
+ NULL,
+ channel_props,
+ },
+ { GABBLE_IFACE_CHANNEL_TYPE_SERVER_AUTHENTICATION,
+ tp_dbus_properties_mixin_getter_gobject_properties,
+ NULL,
+ server_auth_props,
+ },
+ { GABBLE_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION,
+ tp_dbus_properties_mixin_getter_gobject_properties,
+ NULL,
+ sasl_auth_props,
+ },
+ { NULL }
+ };
+
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ WockyAuthRegistryClass *auth_reg_class = WOCKY_AUTH_REGISTRY_CLASS (klass);
+
+ GParamSpec *param_spec;
+
+ g_type_class_add_private (klass, sizeof (GabbleServerSaslChannelPrivate));
+
+ object_class->constructor = gabble_server_sasl_channel_constructor;
+ object_class->get_property = gabble_server_sasl_channel_get_property;
+ object_class->set_property = gabble_server_sasl_channel_set_property;
+ object_class->dispose = gabble_server_sasl_channel_dispose;
+
+ auth_reg_class->start_auth_async_func =
+ gabble_server_sasl_channel_start_auth_async_func;
+ auth_reg_class->challenge_async_func =
+ gabble_server_sasl_channel_challenge_async_func;
+ auth_reg_class->success_async_func =
+ gabble_server_sasl_channel_server_success_async_func;
+ auth_reg_class->failure_func = gabble_server_sasl_channel_failure_func;
+
+
+ /* channel iface */
+ g_object_class_override_property (object_class, PROP_CHANNEL_PROPERTIES,
+ "channel-properties");
+ g_object_class_override_property (object_class, PROP_OBJECT_PATH,
+ "object-path");
+ g_object_class_override_property (object_class, PROP_CHANNEL_TYPE,
+ "channel-type");
+ g_object_class_override_property (object_class, PROP_HANDLE_TYPE,
+ "handle-type");
+ g_object_class_override_property (object_class, PROP_HANDLE, "handle");
+ g_object_class_override_property (object_class, PROP_CHANNEL_DESTROYED,
+ "channel-destroyed");
+
+ param_spec = g_param_spec_object ("connection", "GabbleConnection object",
+ "Gabble connection object that owns this channel.",
+ GABBLE_TYPE_CONNECTION,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_CONNECTION, param_spec);
+
+ param_spec = g_param_spec_boxed ("interfaces", "Extra D-Bus interfaces",
+ "Additional Channel.Interface.* interfaces",
+ G_TYPE_STRV,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_INTERFACES, param_spec);
+
+ param_spec = g_param_spec_string ("target-id", "Target's identifier",
+ "The string obtained by inspecting the target handle",
+ NULL,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_TARGET_ID, param_spec);
+
+ param_spec = g_param_spec_boolean ("requested", "Requested?",
+ "True if this channel was requested by the local user",
+ FALSE,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_REQUESTED, param_spec);
+
+ param_spec = g_param_spec_uint ("initiator-handle", "Initiator's handle",
+ "The contact who initiated the channel",
+ 0, G_MAXUINT32, 0,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_INITIATOR_HANDLE,
+ param_spec);
+
+ param_spec = g_param_spec_string ("initiator-id", "Initiator's bare JID",
+ "The string obtained by inspecting the initiator-handle",
+ NULL,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_INITIATOR_ID,
+ param_spec);
+
+ param_spec = g_param_spec_boxed ("auth-info",
+ "Authentication information",
+ "Details used for authentication purposes.",
+ GABBLE_HASH_TYPE_AUTHDETAILS,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_AUTH_INFO,
+ param_spec);
+
+ param_spec = g_param_spec_uint ("auth-method",
+ "Authentication method",
+ "Method of authentication like SASL or Captcha.",
+ 0, NUM_GABBLE_AUTHENTICATION_TYPES, GABBLE_AUTHENTICATION_TYPE_SASL,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_AUTH_METHOD,
+ param_spec);
+
+ param_spec = g_param_spec_boxed ("current-state",
+ "Current state",
+ "The state of the current SASL authentication.",
+ GABBLE_STRUCT_TYPE_SASL_STATE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_CURRENT_STATE, param_spec);
+
+ param_spec = g_param_spec_string ("mechanism", "Mechanism",
+ "Mechanism used for this negotiation.",
+ NULL,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_MECHANISM, param_spec);
+
+ param_spec = g_param_spec_boxed ("available-mechanisms",
+ "Available authentication mechanisms",
+ "The set of mechanisms the server advertised.",
+ G_TYPE_STRV,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_AVAILABLE_MECHANISMS,
+ param_spec);
+
+ param_spec = g_param_spec_boxed ("challenge",
+ "Challenge",
+ "The latest challenge",
+ DBUS_TYPE_G_UCHAR_ARRAY,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_CHALLENGE,
+ param_spec);
+
+ klass->dbus_props_class.interfaces = prop_interfaces;
+ tp_dbus_properties_mixin_class_init (object_class,
+ G_STRUCT_OFFSET (GabbleServerSaslChannelClass, dbus_props_class));
+}
+
+static void
+change_current_state (GabbleServerSaslChannel *self,
+ GabbleSaslStatus status,
+ const gchar *dbus_error,
+ const gchar *message)
+{
+ GabbleServerSaslChannelPrivate *priv = self->priv;
+ GValue *value;
+ gboolean status_changed;
+
+ value = g_value_array_get_nth (priv->current_state, 0);
+ status_changed = (status != g_value_get_uint (value));
+ g_value_set_uint (value, status);
+
+ if (dbus_error != NULL)
+ {
+ value = g_value_array_get_nth (priv->current_state, 1);
+ g_value_set_string (value, dbus_error);
+ }
+
+ if (message != NULL)
+ {
+ value = g_value_array_get_nth (priv->current_state, 2);
+ g_value_set_string (value, message);
+ }
+
+ if (status_changed)
+ {
+ const gchar *current_message;
+ const gchar *current_dbus_error;
+ GabbleSaslStatus current_status;
+
+ tp_value_array_unpack (priv->current_state, 3, &current_status,
+ &current_dbus_error, &current_message);
+
+ gabble_svc_channel_interface_sasl_authentication_emit_state_changed (
+ self,current_status, current_dbus_error, current_message);
+ }
+}
+
+/**
+ * Channel Interface
+ */
+
+static void
+gabble_server_sasl_channel_close_async (TpSvcChannel *iface,
+ DBusGMethodInvocation *context)
+{
+ GabbleServerSaslChannel *self = GABBLE_SERVER_SASL_CHANNEL (iface);
+
+ g_assert (GABBLE_IS_SERVER_SASL_CHANNEL (self));
+
+ gabble_server_sasl_channel_close (self);
+ tp_svc_channel_return_from_close (context);
+}
+
+static void
+channel_iface_init (gpointer g_iface,
+ gpointer iface_data)
+{
+ TpSvcChannelClass *klass = (TpSvcChannelClass *) g_iface;
+
+#define IMPLEMENT(x, suffix) tp_svc_channel_implement_##x (\
+ klass, gabble_server_sasl_channel_##x##suffix)
+ IMPLEMENT(close,_async);
+#undef IMPLEMENT
+}
+
+/**
+ * Sasl Authentication Channel Interface
+ */
+
+static void
+gabble_server_sasl_channel_start_mechanism (
+ GabbleSvcChannelInterfaceSaslAuthentication *mechanisms_chooser,
+ const gchar *in_Mechanism,
+ const GArray *in_InitialData,
+ DBusGMethodInvocation *context)
+{
+ GabbleServerSaslChannel *self = GABBLE_SERVER_SASL_CHANNEL (
+ mechanisms_chooser);
+ GabbleServerSaslChannelPrivate *priv = self->priv;
+ WockyAuthRegistryStartData *start_data;
+ GSimpleAsyncResult *r = priv->result;
+ GString *initial_data = g_string_new_len (in_InitialData->data,
+ in_InitialData->len);
+
+ DEBUG ("");
+
+ priv->result = NULL;
+
+ start_data =
+ wocky_auth_registry_start_data_new (in_Mechanism, initial_data);
+
+ g_string_free (initial_data, TRUE);
+
+ g_simple_async_result_set_op_res_gpointer (r,
+ start_data, (GDestroyNotify) wocky_auth_registry_start_data_free);
+
+ dbus_g_method_return (context);
+
+ g_simple_async_result_complete_in_idle (r);
+ g_object_unref (r);
+}
+
+static void
+gabble_server_sasl_channel_respond (
+ GabbleSvcChannelInterfaceSaslAuthentication *channel,
+ const GArray *in_Response_Data,
+ DBusGMethodInvocation *context)
+{
+ GabbleServerSaslChannel *self =
+ GABBLE_SERVER_SASL_CHANNEL (channel);
+ GString *response_data;
+ GSimpleAsyncResult *r = self->priv->result;
+
+ g_assert (r != NULL);
+
+ self->priv->result = NULL;
+
+ if (in_Response_Data->len > 0)
+ response_data = g_string_new_len (in_Response_Data->data,
+ in_Response_Data->len);
+ else
+ response_data = NULL;
+
+ g_simple_async_result_set_op_res_gpointer (r, response_data,
+ (GDestroyNotify) wocky_g_string_free);
+
+ g_simple_async_result_complete_in_idle (r);
+ g_object_unref (r);
+
+ gabble_svc_channel_interface_sasl_authentication_return_from_respond (
+ context);
+}
+
+static void
+gabble_server_sasl_channel_accept (
+ GabbleSvcChannelInterfaceSaslAuthentication *channel,
+ DBusGMethodInvocation *context)
+{
+ GabbleServerSaslChannel *self = GABBLE_SERVER_SASL_CHANNEL (channel);
+ GabbleSaslStatus current_status = g_value_get_uint (g_value_array_get_nth (
+ self->priv->current_state, 0));
+ GSimpleAsyncResult *r = self->priv->result;
+ const gchar *message = NULL;
+
+
+ switch (current_status)
+ {
+ case GABBLE_SASL_STATUS_NOT_STARTED:
+ message = "Authentication has not yet begun.";
+ break;
+
+ case GABBLE_SASL_STATUS_IN_PROGRESS:
+ change_current_state (self, GABBLE_SASL_STATUS_CLIENT_ACCEPTED, NULL,
+ NULL);
+ break;
+
+ case GABBLE_SASL_STATUS_SERVER_SUCCEEDED:
+ change_current_state (self, GABBLE_SASL_STATUS_SUCCEEDED, NULL, NULL);
+ break;
+
+ case GABBLE_SASL_STATUS_CLIENT_ACCEPTED:
+ message = "Client already accepted authentication.";
+ break;
+
+ case GABBLE_SASL_STATUS_SUCCEEDED:
+ message = "Authentication already succeeded.";
+ break;
+
+ case GABBLE_SASL_STATUS_SERVER_FAILED:
+ case GABBLE_SASL_STATUS_CLIENT_FAILED:
+ message = "Authentication has already failed.";
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+
+ if (message != NULL)
+ {
+ GError *error = g_error_new_literal (TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
+ message);
+
+ dbus_g_method_return_error (context, error);
+
+ g_error_free (error);
+
+ return;
+ }
+ else if (r != NULL)
+ {
+ self->priv->result = NULL;
+
+ g_simple_async_result_complete_in_idle (r);
+ g_object_unref (r);
+ }
+
+ gabble_svc_channel_interface_sasl_authentication_return_from_accept (
+ context);
+}
+
+static void
+gabble_server_sasl_channel_abort (
+ GabbleSvcChannelInterfaceSaslAuthentication *channel,
+ guint in_Reason,
+ const gchar *in_Debug_Message,
+ DBusGMethodInvocation *context)
+{
+ GabbleServerSaslChannel *self = GABBLE_SERVER_SASL_CHANNEL (channel);
+ GSimpleAsyncResult *r = self->priv->result;
+ GabbleSaslStatus current_status = g_value_get_uint (g_value_array_get_nth (
+ self->priv->current_state, 0));
+ guint code;
+ const gchar *dbus_error;
+
+ if (current_status == GABBLE_SASL_STATUS_SUCCEEDED ||
+ current_status == GABBLE_SASL_STATUS_CLIENT_ACCEPTED)
+ {
+ GError *error = g_error_new_literal (TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
+ "Authentication has already succeeded.");
+
+ dbus_g_method_return_error (context, error);
+
+ g_error_free (error);
+
+ return;
+ }
+
+ switch (in_Reason)
+ {
+ case GABBLE_ABORT_REASON_INVALID_CHALLENGE:
+ code = WOCKY_AUTH_ERROR_INVALID_REPLY;
+ dbus_error = "org.freedesktop.Telepathy.Error.Sasl.InvalidReply";
+ break;
+
+ case GABBLE_ABORT_REASON_USER_ABORT:
+ code = WOCKY_AUTH_ERROR_FAILURE;
+ dbus_error = TP_ERROR_STR_CANCELLED;
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+
+ if (r != NULL)
+ {
+ self->priv->result = NULL;
+
+ g_simple_async_result_set_error (r, WOCKY_AUTH_ERROR, code,
+ "Authentication aborted: %s", in_Debug_Message);
+
+ g_simple_async_result_complete_in_idle (r);
+ g_object_unref (r);
+ }
+
+ change_current_state (self, GABBLE_SASL_STATUS_CLIENT_FAILED, dbus_error,
+ in_Debug_Message);
+
+ gabble_svc_channel_interface_sasl_authentication_return_from_abort (context);
+}
+
+static void
+sasl_auth_iface_init (gpointer klass,
+ gpointer unused G_GNUC_UNUSED)
+{
+#define IMPLEMENT(x) \
+ gabble_svc_channel_interface_sasl_authentication_implement_##x ( \
+ klass, gabble_server_sasl_channel_##x)
+ IMPLEMENT (start_mechanism);
+ IMPLEMENT (respond);
+ IMPLEMENT (accept);
+ IMPLEMENT (abort);
+#undef IMPLEMENT
+}
+
+/**
+ * Auth Registry Interface
+ */
+
+static void
+gabble_server_sasl_channel_start_auth_async_func (
+ WockyAuthRegistry *auth_registry,
+ const GSList *mechanisms,
+ gboolean allow_plain,
+ gboolean is_secure_channel,
+ const gchar *username,
+ const gchar *password,
+ const gchar *server,
+ const gchar *session_id,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ if (password == NULL)
+ {
+ GabbleServerSaslChannel *self = GABBLE_SERVER_SASL_CHANNEL (
+ auth_registry);
+ GabbleServerSaslChannelPrivate *priv = self->priv;
+ DBusGConnection *bus = tp_get_bus ();
+ TpBaseConnection *conn = (TpBaseConnection *) priv->conn;
+ GPtrArray *arr = g_ptr_array_new ();
+ GSList *i;
+
+ DEBUG ("");
+
+ g_assert (priv->result == NULL);
+ g_assert (conn->object_path != NULL);
+
+ g_strfreev (priv->available_mechanisms);
+
+ if (priv->auth_info != NULL)
+ g_hash_table_unref (priv->auth_info);
+
+ priv->auth_info = tp_asv_new (
+ "username", G_TYPE_STRING, username,
+ "realm", G_TYPE_STRING, server,
+ "session-id", G_TYPE_STRING, session_id,
+ NULL);
+
+ priv->result = g_simple_async_result_new (G_OBJECT (self), callback,
+ user_data, wocky_auth_registry_start_auth_finish);
+
+ for (i = (GSList *) mechanisms; i != NULL; i = i->next)
+ g_ptr_array_add (arr, g_strdup ((gchar *)i->data));
+
+ g_ptr_array_add (arr, NULL);
+
+ priv->available_mechanisms = (gchar **) g_ptr_array_free (arr, FALSE);
+
+ priv->object_path = g_strdup_printf ("%s/SaslChannel_%p",
+ conn->object_path, self);
+
+ dbus_g_connection_register_g_object (bus, priv->object_path,
+ G_OBJECT (self));
+
+ priv->closed = FALSE;
+
+ g_object_notify (G_OBJECT (self), "channel-destroyed");
+ }
+ else
+ {
+ WOCKY_AUTH_REGISTRY_CLASS (
+ gabble_server_sasl_channel_parent_class)->start_auth_async_func (
+ auth_registry, mechanisms, allow_plain, is_secure_channel,
+ username, password, server, session_id, callback, user_data);
+ }
+}
+
+static void
+gabble_server_sasl_channel_challenge_async_func (
+ WockyAuthRegistry *auth_registry,
+ const GString *challenge_data,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GabbleServerSaslChannel *self = GABBLE_SERVER_SASL_CHANNEL (auth_registry);
+ GabbleServerSaslChannelPrivate *priv = self->priv;
+
+ if (!priv->closed)
+ {
+ g_assert (priv->result == NULL);
+
+ priv->result = g_simple_async_result_new (G_OBJECT (self), callback,
+ user_data, wocky_auth_registry_challenge_finish);
+
+ g_array_free (priv->challenge, TRUE);
+
+ priv->challenge = g_array_sized_new (FALSE, FALSE, sizeof (gchar),
+ challenge_data->len);
+
+ g_array_append_vals (priv->challenge, challenge_data->str,
+ challenge_data->len);
+
+ change_current_state (self, GABBLE_SASL_STATUS_IN_PROGRESS, NULL, NULL);
+
+ gabble_svc_channel_interface_sasl_authentication_emit_new_challenge (
+ self, priv->challenge);
+ }
+ else
+ {
+ WOCKY_AUTH_REGISTRY_CLASS (
+ gabble_server_sasl_channel_parent_class)->challenge_async_func (
+ auth_registry, challenge_data, callback, user_data);
+ }
+}
+
+static void
+gabble_server_sasl_channel_server_success_async_func (
+ WockyAuthRegistry *auth_registry,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GabbleServerSaslChannel *self = GABBLE_SERVER_SASL_CHANNEL (auth_registry);
+ GabbleServerSaslChannelPrivate *priv = self->priv;
+
+ if (!priv->closed)
+ {
+ GabbleSaslStatus current_status = g_value_get_uint (
+ g_value_array_get_nth (priv->current_state, 0));
+ GSimpleAsyncResult *r = g_simple_async_result_new (G_OBJECT (self),
+ callback, user_data, wocky_auth_registry_success_finish);
+
+ DEBUG ("");
+
+ g_assert (priv->result == NULL);
+
+ if (current_status != GABBLE_SASL_STATUS_CLIENT_ACCEPTED)
+ {
+ priv->result = r;
+ change_current_state (self, GABBLE_SASL_STATUS_SERVER_SUCCEEDED,
+ NULL, NULL);
+ }
+ else
+ {
+ change_current_state (self, GABBLE_SASL_STATUS_SUCCEEDED, NULL,
+ NULL);
+ g_simple_async_result_complete_in_idle (r);
+ g_object_unref (r);
+ }
+ }
+ else
+ {
+ WOCKY_AUTH_REGISTRY_CLASS (
+ gabble_server_sasl_channel_parent_class)->success_async_func (
+ auth_registry, callback, user_data);
+ }
+}
+
+static void
+gabble_server_sasl_channel_failure_func (WockyAuthRegistry *auth_registry,
+ GError *error)
+{
+ GabbleServerSaslChannel *self = GABBLE_SERVER_SASL_CHANNEL (auth_registry);
+ const gchar *dbus_error = TP_ERROR_STR_AUTHENTICATION_FAILED;
+
+ DEBUG ("auth failed: %s", error->message);
+
+ change_current_state (self, GABBLE_SASL_STATUS_SERVER_FAILED,
+ dbus_error, error->message);
+}
+
+/*
+ * Public
+ */
+
+GabbleServerSaslChannel *
+gabble_server_sasl_channel_new (GabbleConnection *conn)
+{
+ GabbleServerSaslChannel *obj;
+
+ g_return_val_if_fail (GABBLE_IS_CONNECTION (conn), NULL);
+
+ obj = GABBLE_SERVER_SASL_CHANNEL (
+ g_object_new (GABBLE_TYPE_SERVER_SASL_CHANNEL, "connection", conn,
+ NULL));
+
+ return obj;
+}
+
+void
+gabble_server_sasl_channel_close (GabbleServerSaslChannel *self)
+{
+ GabbleServerSaslChannelPrivate *priv = self->priv;
+
+ g_assert (GABBLE_IS_SERVER_SASL_CHANNEL (self));
+
+ if (priv->closed)
+ return;
+
+ priv->closed = TRUE;
+
+ DEBUG ("called on %p", self);
+
+ tp_svc_channel_emit_closed (self);
+
+ g_object_notify (G_OBJECT (self), "channel-destroyed");
+
+ if (priv->result != NULL)
+ {
+ GSimpleAsyncResult *r = priv->result;
+
+ DEBUG ("closed channel");
+
+ priv->result = NULL;
+ g_simple_async_result_set_error (r, WOCKY_AUTH_ERROR,
+ WOCKY_AUTH_ERROR_FAILURE,
+ "%s", "Client aborted authentication.");
+ g_simple_async_result_complete_in_idle (r);
+ g_object_unref (r);
+ }
+}
+
+gboolean
+gabble_server_sasl_channel_is_open (GabbleServerSaslChannel *self)
+{
+ return !self->priv->closed;
+}
diff --git a/src/server-sasl-channel.h b/src/server-sasl-channel.h
new file mode 100644
index 000000000..b5b5ee42c
--- /dev/null
+++ b/src/server-sasl-channel.h
@@ -0,0 +1,78 @@
+/*
+ * server-sasl-channel.h - Header for GabbleServerSaslChannel
+ * Copyright (C) 2010 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __GABBLE_SERVER_SASL_CHANNEL_H__
+#define __GABBLE_SERVER_SASL_CHANNEL_H__
+
+#include <glib-object.h>
+
+#include <telepathy-glib/base-connection.h>
+#include <wocky/wocky-auth-registry.h>
+
+#include <extensions/extensions.h>
+
+#include "types.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GabbleServerSaslChannelPrivate GabbleServerSaslChannelPrivate;
+typedef struct _GabbleServerSaslChannelClass GabbleServerSaslChannelClass;
+typedef struct _GabbleServerSaslChannel GabbleServerSaslChannel;
+
+struct _GabbleServerSaslChannelClass {
+ WockyAuthRegistryClass parent_class;
+
+ TpDBusPropertiesMixinClass dbus_props_class;
+};
+
+struct _GabbleServerSaslChannel {
+ WockyAuthRegistry parent;
+
+ GabbleServerSaslChannelPrivate *priv;
+};
+
+GType gabble_server_sasl_channel_get_type (void);
+
+/* TYPE MACROS */
+#define GABBLE_TYPE_SERVER_SASL_CHANNEL \
+ (gabble_server_sasl_channel_get_type ())
+#define GABBLE_SERVER_SASL_CHANNEL(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), GABBLE_TYPE_SERVER_SASL_CHANNEL,\
+ GabbleServerSaslChannel))
+#define GABBLE_SERVER_SASL_CHANNEL_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), GABBLE_TYPE_SERVER_SASL_CHANNEL,\
+ GabbleServerSaslChannelClass))
+#define GABBLE_IS_SERVER_SASL_CHANNEL(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), GABBLE_TYPE_SERVER_SASL_CHANNEL))
+#define GABBLE_IS_SERVER_SASL_CHANNEL_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), GABBLE_TYPE_SERVER_SASL_CHANNEL))
+#define GABBLE_SERVER_SASL_CHANNEL_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), GABBLE_TYPE_SERVER_SASL_CHANNEL,\
+ GabbleServerSaslChannelClass))
+
+void gabble_server_sasl_channel_close (GabbleServerSaslChannel *self);
+
+GabbleServerSaslChannel *gabble_server_sasl_channel_new (
+ GabbleConnection *conn);
+
+gboolean gabble_server_sasl_channel_is_open (GabbleServerSaslChannel *self);
+
+G_END_DECLS
+
+#endif /* #ifndef __GABBLE_SERVER_SASL_CHANNEL_H__*/