diff options
author | Eitan Isaacson <eitan@monotonous.org> | 2010-05-22 09:01:15 -0700 |
---|---|---|
committer | Eitan Isaacson <eitan@monotonous.org> | 2010-06-02 22:32:09 -0700 |
commit | 689eea8705dc3050740b024403d383e02b347ac8 (patch) | |
tree | 0eea4613038556f266e2a0ecad156527f10df44d | |
parent | bb23e7068b2f60478f715b4b6b3b6d88c8054766 (diff) |
Added server SASL channel and auth manager.
-rw-r--r-- | src/Makefile.am | 4 | ||||
-rw-r--r-- | src/auth-manager.c | 259 | ||||
-rw-r--r-- | src/auth-manager.h | 67 | ||||
-rw-r--r-- | src/connection-manager.c | 3 | ||||
-rw-r--r-- | src/connection.c | 16 | ||||
-rw-r--r-- | src/debug.c | 45 | ||||
-rw-r--r-- | src/debug.h | 3 | ||||
-rw-r--r-- | src/gabble.c | 2 | ||||
-rw-r--r-- | src/server-sasl-channel.c | 1014 | ||||
-rw-r--r-- | src/server-sasl-channel.h | 78 |
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, ¤t_status, + ¤t_dbus_error, ¤t_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__*/ |