summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Zeuthen <davidz@redhat.com>2010-05-05 12:26:00 -0400
committerDavid Zeuthen <davidz@redhat.com>2010-05-05 12:26:00 -0400
commit1681b4266d83ee1af726a88148e54d0e889b1600 (patch)
treed88c9adc76fb3e6967ab88035c456a5e57f68c6c
parent95098a9a064312ef19ea41b7c0dad89359982c20 (diff)
Add SHA1 authentication mechanism
Also various changes elsewhere to make this fit.
-rw-r--r--docs/reference/gdbus/gdbus-docs.xml2
-rw-r--r--docs/reference/gdbus/gdbus-standalone-sections.txt55
-rw-r--r--docs/reference/gdbus/gdbus-standalone.types2
-rw-r--r--gdbus/Makefile.am1
-rw-r--r--gdbus/example-peer.c4
-rw-r--r--gdbus/gcredentials.c114
-rw-r--r--gdbus/gcredentials.h54
-rw-r--r--gdbus/gdbusauth.c399
-rw-r--r--gdbus/gdbusauthmechanism.c181
-rw-r--r--gdbus/gdbusauthmechanism.h65
-rw-r--r--gdbus/gdbusauthmechanismanon.c25
-rw-r--r--gdbus/gdbusauthmechanismexternal.c35
-rw-r--r--gdbus/gdbusauthmechanismsha1.c1209
-rw-r--r--gdbus/gdbusauthmechanismsha1.h82
-rw-r--r--gdbus/gdbusauthobserver.c1
-rw-r--r--gdbus/gdbusenums.h15
16 files changed, 2004 insertions, 240 deletions
diff --git a/docs/reference/gdbus/gdbus-docs.xml b/docs/reference/gdbus/gdbus-docs.xml
index 38946df..c768b6f 100644
--- a/docs/reference/gdbus/gdbus-docs.xml
+++ b/docs/reference/gdbus/gdbus-docs.xml
@@ -25,6 +25,8 @@
<xi:include href="xml/gdbusproxy.xml"/>
<xi:include href="xml/gdbusserver.xml"/>
<xi:include href="xml/gdbusauthobserver.xml"/>
+ <xi:include href="xml/gcredentials.xml"/>
+ <xi:include href="xml/gunixcredentialsmessage.xml"/>
</chapter>
<chapter id="convenience">
<title>GDBus Convenience</title>
diff --git a/docs/reference/gdbus/gdbus-standalone-sections.txt b/docs/reference/gdbus/gdbus-standalone-sections.txt
index 7362244..053e737 100644
--- a/docs/reference/gdbus/gdbus-standalone-sections.txt
+++ b/docs/reference/gdbus/gdbus-standalone-sections.txt
@@ -1,4 +1,59 @@
<SECTION>
+<FILE>gunixcredentialsmessage</FILE>
+<TITLE>GUnixCredentialsMessage</TITLE>
+GUnixCredentialsMessage
+GUnixCredentialsMessageClass
+g_unix_credentials_message_new
+g_unix_credentials_message_new_with_credentials
+g_unix_credentials_message_get_credentials
+g_unix_credentials_message_is_supported
+<SUBSECTION Standard>
+G_IS_UNIX_CREDENTIALS_MESSAGE
+G_IS_UNIX_CREDENTIALS_MESSAGE_CLASS
+G_TYPE_UNIX_CREDENTIALS_MESSAGE
+G_UNIX_CREDENTIALS_MESSAGE
+G_UNIX_CREDENTIALS_MESSAGE_CLASS
+G_UNIX_CREDENTIALS_MESSAGE_GET_CLASS
+<SUBSECTION Private>
+GUnixCredentialsMessagePrivate
+g_unix_credentials_message_get_type
+</SECTION>
+
+<SECTION>
+<FILE>gcredentials</FILE>
+<TITLE>GCredentials</TITLE>
+GCredentials
+GCredentialsClass
+GCredentialType
+g_credentials_new
+g_credentials_new_for_process
+g_credentials_has_unix_user
+g_credentials_get_unix_user
+g_credentials_set_unix_user
+g_credentials_unset_unix_user
+g_credentials_has_unix_group
+g_credentials_get_unix_group
+g_credentials_set_unix_group
+g_credentials_unset_unix_group
+g_credentials_has_unix_process
+g_credentials_get_unix_process
+g_credentials_set_unix_process
+g_credentials_unset_unix_process
+g_credentials_has_windows_user
+g_credentials_get_windows_user
+g_credentials_set_windows_user
+g_credentials_unset_windows_user
+<SUBSECTION Standard>
+G_CREDENTIALS
+G_IS_CREDENTIALS
+G_TYPE_CREDENTIALS
+g_credentials_get_type
+G_CREDENTIALS_CLASS
+G_IS_CREDENTIALS_CLASS
+G_CREDENTIALS_GET_CLASS
+</SECTION>
+
+<SECTION>
<FILE>gdbusaddress</FILE>
g_dbus_is_address
g_dbus_is_supported_address
diff --git a/docs/reference/gdbus/gdbus-standalone.types b/docs/reference/gdbus/gdbus-standalone.types
index f372a9f..9e61548 100644
--- a/docs/reference/gdbus/gdbus-standalone.types
+++ b/docs/reference/gdbus/gdbus-standalone.types
@@ -7,4 +7,6 @@ g_dbus_proxy_get_type
g_dbus_method_invocation_get_type
g_dbus_server_get_type
g_dbus_auth_observer_get_type
+g_credentials_get_type
+g_unix_credentials_message_get_type
diff --git a/gdbus/Makefile.am b/gdbus/Makefile.am
index d9a4fac..cf6116f 100644
--- a/gdbus/Makefile.am
+++ b/gdbus/Makefile.am
@@ -67,6 +67,7 @@ libgdbus_standalone_la_SOURCES = \
gdbusauthmechanism.h gdbusauthmechanism.c \
gdbusauthmechanismanon.h gdbusauthmechanismanon.c \
gdbusauthmechanismexternal.h gdbusauthmechanismexternal.c \
+ gdbusauthmechanismsha1.h gdbusauthmechanismsha1.c \
gdbuserror.h gdbuserror.c \
gdbusconnection.h gdbusconnection.c \
gdbusmessage.h gdbusmessage.c \
diff --git a/gdbus/example-peer.c b/gdbus/example-peer.c
index a22e742..3c02c4e 100644
--- a/gdbus/example-peer.c
+++ b/gdbus/example-peer.c
@@ -134,10 +134,12 @@ main (int argc, char *argv[])
g_type_init ();
- error = NULL;
opt_address = NULL;
opt_server = FALSE;
+ opt_allow_anonymous = FALSE;
+
opt_context = g_option_context_new ("peer-to-peer example");
+ error = NULL;
g_option_context_add_main_entries (opt_context, opt_entries, NULL);
if (!g_option_context_parse (opt_context, &argc, &argv, &error))
{
diff --git a/gdbus/gcredentials.c b/gdbus/gcredentials.c
index 140934b..73ada53 100644
--- a/gdbus/gcredentials.c
+++ b/gdbus/gcredentials.c
@@ -41,15 +41,14 @@
* The #GCredentials type is used for storing information that can be
* used for identifying, authenticating and authorizing processes.
*
- * Most POSIX compliant operating systems support a secure exchange of
- * credentials over a Unix Domain Socket, see
+ * Most UNIX and UNIX-like operating systems support a secure exchange
+ * of credentials over a Unix Domain Socket, see
* #GUnixCredentialsMessage, g_unix_connection_send_credentials() and
* g_unix_connection_receive_credentials() for details.
*/
struct _GCredentialsPrivate
{
- GCredentialType credentials;
gint64 unix_user;
gint64 unix_group;
gint64 unix_process;
@@ -78,13 +77,18 @@ g_credentials_class_init (GCredentialsClass *klass)
g_type_class_add_private (klass, sizeof (GCredentialsPrivate));
gobject_class = G_OBJECT_CLASS (klass);
- gobject_class->finalize = g_credentials_finalize;
+ gobject_class->finalize = g_credentials_finalize;
}
static void
g_credentials_init (GCredentials *credentials)
{
credentials->priv = G_TYPE_INSTANCE_GET_PRIVATE (credentials, G_TYPE_CREDENTIALS, GCredentialsPrivate);
+
+ credentials->priv->unix_user = -1;
+ credentials->priv->unix_group = -1;
+ credentials->priv->unix_process = -1;
+ credentials->priv->windows_user = NULL;
}
/* ---------------------------------------------------------------------------------------------------- */
@@ -109,14 +113,10 @@ static GCredentials *
g_credentials_new_for_unix_process (void)
{
GCredentials *credentials;
-
credentials = g_credentials_new ();
credentials->priv->unix_user = getuid ();
credentials->priv->unix_group = getgid ();
credentials->priv->unix_process = getpid ();
- credentials->priv->credentials = G_CREDENTIAL_TYPE_UNIX_USER |
- G_CREDENTIAL_TYPE_UNIX_GROUP |
- G_CREDENTIAL_TYPE_UNIX_PROCESS;
return credentials;
}
#endif
@@ -140,7 +140,7 @@ g_credentials_new_for_process (void)
#elif G_OS_WIN32
return g_credentials_new_for_win32_process ();
#else
-#warning Please implement g_credentials_new_for_process() for your OS
+#warning Please implement g_credentials_new_for_process() for your OS. For now g_credentials_new_for_process() will return empty credentials.
return g_credentials_new ();
#endif
}
@@ -148,58 +148,6 @@ g_credentials_new_for_process (void)
/* ---------------------------------------------------------------------------------------------------- */
/**
- * g_credentials_get_credentials:
- * @credentials: A #GCredentials.
- *
- * Check what credentials are set in @credentials.
- *
- * Returns: Flags from the #GCredentialType enumeration.
- */
-GCredentialType
-g_credentials_get_credentials (GCredentials *credentials)
-{
- g_return_val_if_fail (G_IS_CREDENTIALS (credentials), G_CREDENTIAL_TYPE_NONE);
- return credentials->priv->credentials;
-}
-
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-/**
- * g_credentials_has_credential:
- * @credentials: A #GCredentials.
- * @credential: One (or more) flag from the #GCredentialType enumeration.
- *
- * Checks if @credentials has the credential(s) specified by @credential.
- *
- * Returns: %TRUE if @credentials has the requested credential(s), %FALSE otherwise.
- */
-gboolean
-g_credentials_has_credential (GCredentials *credentials,
- GCredentialType credential)
-{
- g_return_val_if_fail (G_IS_CREDENTIALS (credentials), FALSE);
- return (credentials->priv->credentials & credential) != 0;
-}
-
-/**
- * g_credentials_unset_credential:
- * @credentials: A #GCredentials.
- * @credential: One (or more) flag from the #GCredentialType enumeration.
- *
- * Unsets the credential(s) specified by @credential.
- */
-void
-g_credentials_unset_credential (GCredentials *credentials,
- GCredentialType credential)
-{
- g_return_if_fail (G_IS_CREDENTIALS (credentials));
- credentials->priv->credentials &= ~credential;
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-/**
* g_credentials_has_unix_user:
* @credentials: A #GCredentials.
*
@@ -211,7 +159,7 @@ gboolean
g_credentials_has_unix_user (GCredentials *credentials)
{
g_return_val_if_fail (G_IS_CREDENTIALS (credentials), FALSE);
- return g_credentials_has_credential (credentials, G_CREDENTIAL_TYPE_UNIX_USER);
+ return credentials->priv->unix_user != -1;
}
/**
@@ -220,23 +168,19 @@ g_credentials_has_unix_user (GCredentials *credentials)
*
* Gets the UNIX user identifier from @credentials.
*
- * It is a programming error to call this method unless @credentials
- * has this credential.
- *
- * Returns: The identifier.
+ * Returns: The identifier or -1 if unset.
*/
gint64
g_credentials_get_unix_user (GCredentials *credentials)
{
g_return_val_if_fail (G_IS_CREDENTIALS (credentials), -1);
- g_return_val_if_fail (g_credentials_has_unix_user (credentials), -1);
return credentials->priv->unix_user;
}
/**
* g_credentials_set_unix_user:
* @credentials: A #GCredentials.
- * @user_id: A UNIX user identifier (typically type #uid_t).
+ * @user_id: A UNIX user identifier (typically type #uid_t) or -1 to unset it.
*
* Sets the UNIX user identifier.
*/
@@ -246,7 +190,6 @@ g_credentials_set_unix_user (GCredentials *credentials,
{
g_return_if_fail (G_IS_CREDENTIALS (credentials));
credentials->priv->unix_user = user_id;
- credentials->priv->credentials |= G_CREDENTIAL_TYPE_UNIX_USER;
}
/* ---------------------------------------------------------------------------------------------------- */
@@ -263,7 +206,7 @@ gboolean
g_credentials_has_unix_group (GCredentials *credentials)
{
g_return_val_if_fail (G_IS_CREDENTIALS (credentials), FALSE);
- return g_credentials_has_credential (credentials, G_CREDENTIAL_TYPE_UNIX_GROUP);
+ return credentials->priv->unix_group != -1;
}
/**
@@ -272,23 +215,19 @@ g_credentials_has_unix_group (GCredentials *credentials)
*
* Gets the UNIX group identifier from @credentials.
*
- * It is a programming error to call this method unless @credentials
- * has this credential.
- *
- * Returns: The identifier.
+ * Returns: The identifier or -1 if unset.
*/
gint64
g_credentials_get_unix_group (GCredentials *credentials)
{
g_return_val_if_fail (G_IS_CREDENTIALS (credentials), -1);
- g_return_val_if_fail (g_credentials_has_unix_group (credentials), -1);
return credentials->priv->unix_group;
}
/**
* g_credentials_set_unix_group:
* @credentials: A #GCredentials.
- * @group_id: A UNIX group identifier (typically type #gid_t).
+ * @group_id: A UNIX group identifier (typically type #gid_t) or -1 to unset.
*
* Sets the UNIX group identifier.
*/
@@ -298,7 +237,6 @@ g_credentials_set_unix_group (GCredentials *credentials,
{
g_return_if_fail (G_IS_CREDENTIALS (credentials));
credentials->priv->unix_group = group_id;
- credentials->priv->credentials |= G_CREDENTIAL_TYPE_UNIX_GROUP;
}
/* ---------------------------------------------------------------------------------------------------- */
@@ -315,7 +253,7 @@ gboolean
g_credentials_has_unix_process (GCredentials *credentials)
{
g_return_val_if_fail (G_IS_CREDENTIALS (credentials), FALSE);
- return g_credentials_has_credential (credentials, G_CREDENTIAL_TYPE_UNIX_PROCESS);
+ return credentials->priv->unix_process != -1;
}
/**
@@ -324,23 +262,19 @@ g_credentials_has_unix_process (GCredentials *credentials)
*
* Gets the UNIX process identifier from @credentials.
*
- * It is a programming error to call this method unless @credentials
- * has this credential.
- *
- * Returns: The identifier.
+ * Returns: The identifier or -1 if unset.
*/
gint64
g_credentials_get_unix_process (GCredentials *credentials)
{
g_return_val_if_fail (G_IS_CREDENTIALS (credentials), -1);
- g_return_val_if_fail (g_credentials_has_unix_process (credentials), -1);
return credentials->priv->unix_process;
}
/**
* g_credentials_set_unix_process:
* @credentials: A #GCredentials.
- * @process_id: A UNIX process identifier (typically type #pid_t/#GPid)
+ * @process_id: A UNIX process identifier (typically type #pid_t/#GPid) or -1 to unset.
*
* Sets the UNIX process identifier.
*/
@@ -350,7 +284,6 @@ g_credentials_set_unix_process (GCredentials *credentials,
{
g_return_if_fail (G_IS_CREDENTIALS (credentials));
credentials->priv->unix_process = process_id;
- credentials->priv->credentials |= G_CREDENTIAL_TYPE_UNIX_PROCESS;
}
/* ---------------------------------------------------------------------------------------------------- */
@@ -367,7 +300,7 @@ gboolean
g_credentials_has_windows_user (GCredentials *credentials)
{
g_return_val_if_fail (G_IS_CREDENTIALS (credentials), FALSE);
- return g_credentials_has_credential (credentials, G_CREDENTIAL_TYPE_WINDOWS_USER);
+ return credentials->priv->windows_user != NULL;
}
/**
@@ -376,23 +309,19 @@ g_credentials_has_windows_user (GCredentials *credentials)
*
* Gets the Windows User SID from @credentials.
*
- * It is a programming error to call this method unless @credentials
- * has this credential.
- *
- * Returns: A string. Do not free, the string is owned by @credentials.
+ * Returns: A string or %NULL if unset. Do not free, the string is owned by @credentials.
*/
const gchar *
g_credentials_get_windows_user (GCredentials *credentials)
{
g_return_val_if_fail (G_IS_CREDENTIALS (credentials), NULL);
- g_return_val_if_fail (g_credentials_has_windows_user (credentials), NULL);
return credentials->priv->windows_user;
}
/**
* g_credentials_set_windows_user:
* @credentials: A #GCredentials.
- * @user_sid:
+ * @user_sid: The Windows User SID or %NULL to unset.
*
* Sets the Windows User SID.
*/
@@ -403,7 +332,6 @@ g_credentials_set_windows_user (GCredentials *credentials,
g_return_if_fail (G_IS_CREDENTIALS (credentials));
g_free (credentials->priv->windows_user);
credentials->priv->windows_user = g_strdup (user_sid);
- credentials->priv->credentials |= G_CREDENTIAL_TYPE_WINDOWS_USER;
}
/* ---------------------------------------------------------------------------------------------------- */
diff --git a/gdbus/gcredentials.h b/gdbus/gcredentials.h
index 0ab1e6c..d9191ca 100644
--- a/gdbus/gcredentials.h
+++ b/gdbus/gcredentials.h
@@ -75,36 +75,30 @@ struct _GCredentialsClass
void (*_g_reserved8) (void);
};
-GType g_credentials_get_type (void) G_GNUC_CONST;
-
-GCredentials *g_credentials_new (void);
-GCredentials *g_credentials_new_for_process (void);
-
-GCredentialType g_credentials_get_credentials (GCredentials *credentials);
-gboolean g_credentials_has_credential (GCredentials *credentials,
- GCredentialType credential);
-void g_credentials_unset_credential (GCredentials *credentials,
- GCredentialType credential);
-
-gboolean g_credentials_has_unix_user (GCredentials *credentials);
-gint64 g_credentials_get_unix_user (GCredentials *credentials);
-void g_credentials_set_unix_user (GCredentials *credentials,
- gint64 user_id);
-
-gboolean g_credentials_has_unix_group (GCredentials *credentials);
-gint64 g_credentials_get_unix_group (GCredentials *credentials);
-void g_credentials_set_unix_group (GCredentials *credentials,
- gint64 group_id);
-
-gboolean g_credentials_has_unix_process (GCredentials *credentials);
-gint64 g_credentials_get_unix_process (GCredentials *credentials);
-void g_credentials_set_unix_process (GCredentials *credentials,
- gint64 process_id);
-
-gboolean g_credentials_has_windows_user (GCredentials *credentials);
-const gchar *g_credentials_get_windows_user (GCredentials *credentials);
-void g_credentials_set_windows_user (GCredentials *credentials,
- const gchar *user_sid);
+GType g_credentials_get_type (void) G_GNUC_CONST;
+
+GCredentials *g_credentials_new (void);
+GCredentials *g_credentials_new_for_process (void);
+
+gboolean g_credentials_has_unix_user (GCredentials *credentials);
+gint64 g_credentials_get_unix_user (GCredentials *credentials);
+void g_credentials_set_unix_user (GCredentials *credentials,
+ gint64 user_id);
+
+gboolean g_credentials_has_unix_group (GCredentials *credentials);
+gint64 g_credentials_get_unix_group (GCredentials *credentials);
+void g_credentials_set_unix_group (GCredentials *credentials,
+ gint64 group_id);
+
+gboolean g_credentials_has_unix_process (GCredentials *credentials);
+gint64 g_credentials_get_unix_process (GCredentials *credentials);
+void g_credentials_set_unix_process (GCredentials *credentials,
+ gint64 process_id);
+
+gboolean g_credentials_has_windows_user (GCredentials *credentials);
+const gchar *g_credentials_get_windows_user (GCredentials *credentials);
+void g_credentials_set_windows_user (GCredentials *credentials,
+ const gchar *user_sid);
G_END_DECLS
diff --git a/gdbus/gdbusauth.c b/gdbus/gdbusauth.c
index 6015b1b..b5ccf42 100644
--- a/gdbus/gdbusauth.c
+++ b/gdbus/gdbusauth.c
@@ -27,6 +27,7 @@
#include "gdbusauth.h"
#include "gdbusauthmechanismanon.h"
#include "gdbusauthmechanismexternal.h"
+#include "gdbusauthmechanismsha1.h"
#include "gdbusauthobserver.h"
@@ -42,6 +43,37 @@
#include <sys/socket.h>
#endif
+#define DEBUG_ENABLED 1
+
+static void
+debug_print (const gchar *message, ...)
+{
+#if DEBUG_ENABLED
+ gchar *s;
+ GString *str;
+ va_list var_args;
+ guint n;
+
+ va_start (var_args, message);
+ s = g_strdup_vprintf (message, var_args);
+ va_end (var_args);
+
+ str = g_string_new (NULL);
+ for (n = 0; s[n] != '\0'; n++)
+ {
+ if (G_UNLIKELY (s[n] == '\r'))
+ g_string_append (str, "\\r");
+ else if (G_UNLIKELY (s[n] == '\n'))
+ g_string_append (str, "\\n");
+ else
+ g_string_append_c (str, s[n]);
+ }
+ g_print ("GDBusAuth-debug: %s\n", str->str);
+ g_string_free (str, TRUE);
+ g_free (s);
+#endif
+}
+
/* ---------------------------------------------------------------------------------------------------- */
/* TODO: move to gio */
@@ -231,15 +263,21 @@ g_unix_connection_receive_credentials (GUnixConnection *connection,
/* ---------------------------------------------------------------------------------------------------- */
+typedef struct
+{
+ const gchar *name;
+ gint priority;
+ GType gtype;
+} Mechanism;
+
+static void mechanism_free (Mechanism *m);
struct _GDBusAuthPrivate
{
GIOStream *stream;
- /* maps authenticaion mechanism name to GType, e.g.
- * "ANONYMOUS" -> G_TYPE_DBUS_AUTH_MECHANISM_ANON
- */
- GHashTable *map_auth_mech_name_to_gtype;
+ /* A list of available Mechanism, sorted according to priority */
+ GList *available_mechanisms;
};
enum
@@ -259,7 +297,8 @@ _g_dbus_auth_finalize (GObject *object)
if (auth->priv->stream != NULL)
g_object_unref (auth->priv->stream);
- g_hash_table_unref (auth->priv->map_auth_mech_name_to_gtype);
+ g_list_foreach (auth->priv->available_mechanisms, (GFunc) mechanism_free, NULL);
+ g_list_free (auth->priv->available_mechanisms);
if (G_OBJECT_CLASS (_g_dbus_auth_parent_class)->finalize != NULL)
G_OBJECT_CLASS (_g_dbus_auth_parent_class)->finalize (object);
@@ -332,22 +371,71 @@ _g_dbus_auth_class_init (GDBusAuthClass *klass)
}
static void
+mechanism_free (Mechanism *m)
+{
+ g_free (m);
+}
+
+static void
+add_mechanism (GDBusAuth *auth,
+ GType mechanism_type)
+{
+ Mechanism *m;
+
+ m = g_new0 (Mechanism, 1);
+ m->name = _g_dbus_auth_mechanism_get_name (mechanism_type);
+ m->priority = _g_dbus_auth_mechanism_get_priority (mechanism_type);
+ m->gtype = mechanism_type;
+
+ auth->priv->available_mechanisms = g_list_prepend (auth->priv->available_mechanisms, m);
+}
+
+static gint
+mech_compare_func (Mechanism *a, Mechanism *b)
+{
+ gint ret;
+ /* ensure deterministic order */
+ ret = b->priority - a->priority;
+ if (ret == 0)
+ ret = g_strcmp0 (b->name, a->name);
+ return ret;
+}
+
+static void
_g_dbus_auth_init (GDBusAuth *auth)
{
auth->priv = G_TYPE_INSTANCE_GET_PRIVATE (auth, G_TYPE_DBUS_AUTH, GDBusAuthPrivate);
- auth->priv->map_auth_mech_name_to_gtype = g_hash_table_new_full (g_str_hash, g_str_equal,
- g_free,
- NULL);
-
/* TODO: trawl extension points */
- g_hash_table_insert (auth->priv->map_auth_mech_name_to_gtype,
- g_strdup ("ANONYMOUS"),
- GINT_TO_POINTER (G_TYPE_DBUS_AUTH_MECHANISM_ANON));
+ add_mechanism (auth, G_TYPE_DBUS_AUTH_MECHANISM_ANON);
+ add_mechanism (auth, G_TYPE_DBUS_AUTH_MECHANISM_SHA1);
+ add_mechanism (auth, G_TYPE_DBUS_AUTH_MECHANISM_EXTERNAL);
- g_hash_table_insert (auth->priv->map_auth_mech_name_to_gtype,
- g_strdup ("EXTERNAL"),
- GINT_TO_POINTER (G_TYPE_DBUS_AUTH_MECHANISM_EXTERNAL));
+ auth->priv->available_mechanisms = g_list_sort (auth->priv->available_mechanisms,
+ (GCompareFunc) mech_compare_func);
+}
+
+static GType
+find_mech_by_name (GDBusAuth *auth,
+ const gchar *name)
+{
+ GType ret;
+ GList *l;
+
+ ret = (GType) 0;
+
+ for (l = auth->priv->available_mechanisms; l != NULL; l = l->next)
+ {
+ Mechanism *m = l->data;
+ if (g_strcmp0 (name, m->name) == 0)
+ {
+ ret = m->gtype;
+ goto out;
+ }
+ }
+
+ out:
+ return ret;
}
GDBusAuth *
@@ -531,6 +619,7 @@ hexencode (const gchar *str)
static GDBusAuthMechanism *
client_choose_mech_and_send_initial_response (GDBusAuth *auth,
+ GCredentials *credentials_that_were_sent,
const gchar* const *supported_auth_mechs,
GPtrArray *attempted_auth_mechs,
GDataOutputStream *dos,
@@ -546,8 +635,11 @@ client_choose_mech_and_send_initial_response (GDBusAuth *auth,
gchar *encoded;
gchar *s;
+ again:
mech = NULL;
+ debug_print ("CLIENT: Trying to choose mechanism");
+
/* find an authentication mechanism to try, if any */
auth_mech_to_use_gtype = (GType) 0;
for (n = 0; supported_auth_mechs[n] != NULL; n++)
@@ -564,8 +656,7 @@ client_choose_mech_and_send_initial_response (GDBusAuth *auth,
}
if (!attempted_already)
{
- auth_mech_to_use_gtype = (GType) g_hash_table_lookup (auth->priv->map_auth_mech_name_to_gtype,
- supported_auth_mechs[n]);
+ auth_mech_to_use_gtype = find_mech_by_name (auth, supported_auth_mechs[n]);
if (auth_mech_to_use_gtype != (GType) 0)
break;
}
@@ -573,24 +664,57 @@ client_choose_mech_and_send_initial_response (GDBusAuth *auth,
if (auth_mech_to_use_gtype == (GType) 0)
{
+ guint n;
+ gchar *available;
+ GString *tried_str;
+
+ debug_print ("CLIENT: Exhausted all available mechanisms");
+
+ available = g_strjoinv (", ", (gchar **) supported_auth_mechs);
+
+ tried_str = g_string_new (NULL);
+ for (n = 0; n < attempted_auth_mechs->len; n++)
+ {
+ if (n > 0)
+ g_string_append (tried_str, ", ");
+ g_string_append (tried_str, attempted_auth_mechs->pdata[n]);
+ }
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_FAILED,
- "Exhausted all available authentication mechanisms (tried %d)",
- attempted_auth_mechs->len);
+ _("Exhausted all available authentication mechanisms (tried: %s) (available: %s)"),
+ tried_str->str,
+ available);
+ g_string_free (tried_str, TRUE);
+ g_free (available);
goto out;
}
/* OK, decided on a mechanism - let's do this thing */
- mech = g_object_new (auth_mech_to_use_gtype, NULL);
- g_ptr_array_add (attempted_auth_mechs, (gpointer) _g_dbus_auth_mechanism_get_name (mech));
+ mech = g_object_new (auth_mech_to_use_gtype,
+ "stream", auth->priv->stream,
+ "credentials", credentials_that_were_sent,
+ NULL);
+ debug_print ("CLIENT: Trying mechanism `%s'", _g_dbus_auth_mechanism_get_name (auth_mech_to_use_gtype));
+ g_ptr_array_add (attempted_auth_mechs, (gpointer) _g_dbus_auth_mechanism_get_name (auth_mech_to_use_gtype));
+
+ /* the auth mechanism may not be supported
+ * (for example, EXTERNAL only works if credentials were exchanged)
+ */
+ if (!_g_dbus_auth_mechanism_is_supported (mech))
+ {
+ debug_print ("CLIENT: Mechanism `%s' says it is not supported", _g_dbus_auth_mechanism_get_name (auth_mech_to_use_gtype));
+ g_object_unref (mech);
+ mech = NULL;
+ goto again;
+ }
initial_response_len = -1;
initial_response = _g_dbus_auth_mechanism_client_initiate (mech,
&initial_response_len);
#if 0
g_printerr ("using auth mechanism with name `%s' of type `%s' with initial response `%s'\n",
- _g_dbus_auth_mechanism_get_name (mech),
+ _g_dbus_auth_mechanism_get_name (auth_mech_to_use_gtype),
g_type_name (G_TYPE_FROM_INSTANCE (mech)),
initial_response);
#endif
@@ -599,15 +723,16 @@ client_choose_mech_and_send_initial_response (GDBusAuth *auth,
//g_printerr ("initial_response = `%s'\n", initial_response);
encoded = hexencode (initial_response);
s = g_strdup_printf ("AUTH %s %s\r\n",
- _g_dbus_auth_mechanism_get_name (mech),
+ _g_dbus_auth_mechanism_get_name (auth_mech_to_use_gtype),
encoded);
g_free (initial_response);
g_free (encoded);
}
else
{
- s = g_strdup_printf ("AUTH %s\r\n", _g_dbus_auth_mechanism_get_name (mech));
+ s = g_strdup_printf ("AUTH %s\r\n", _g_dbus_auth_mechanism_get_name (auth_mech_to_use_gtype));
}
+ debug_print ("CLIENT: writing `%s'", s);
if (!g_data_output_stream_put_string (dos, s, cancellable, error))
{
g_object_unref (mech);
@@ -639,8 +764,10 @@ _g_dbus_auth_run_client (GDBusAuth *auth,
GCancellable *cancellable,
GError **error)
{
+ gchar *s;
GDataInputStream *dis;
GDataOutputStream *dos;
+ GCredentials *credentials;
gchar *ret_guid;
gchar *line;
gsize line_length;
@@ -650,11 +777,14 @@ _g_dbus_auth_run_client (GDBusAuth *auth,
ClientState state;
GDBusCapabilityFlags negotiated_capabilities;
+ debug_print ("CLIENT: initiating");
+
ret_guid = NULL;
supported_auth_mechs = NULL;
attempted_auth_mechs = g_ptr_array_new ();
mech = NULL;
negotiated_capabilities = 0;
+ credentials = NULL;
dis = G_DATA_INPUT_STREAM (g_data_input_stream_new (g_io_stream_get_input_stream (auth->priv->stream)));
dos = G_DATA_OUTPUT_STREAM (g_data_output_stream_new (g_io_stream_get_output_stream (auth->priv->stream)));
@@ -664,17 +794,12 @@ _g_dbus_auth_run_client (GDBusAuth *auth,
#ifdef G_OS_UNIX
if (G_IS_UNIX_CONNECTION (auth->priv->stream) && g_unix_credentials_message_is_supported ())
{
- GCredentials *credentials;
credentials = g_credentials_new_for_process ();
if (!g_unix_connection_send_credentials (G_UNIX_CONNECTION (auth->priv->stream),
credentials,
cancellable,
error))
- {
- g_object_unref (credentials);
- goto out;
- }
- g_object_unref (credentials);
+ goto out;
}
else
{
@@ -686,10 +811,17 @@ _g_dbus_auth_run_client (GDBusAuth *auth,
goto out;
#endif
+ if (credentials != NULL)
+ debug_print ("CLIENT: sent credentials");
+ else
+ debug_print ("CLIENT: didn't send any credentials");
+
/* TODO: to reduce rountrips, try to pick an auth mechanism to start with */
/* Get list of supported authentication mechanisms */
- if (!g_data_output_stream_put_string (dos, "AUTH\r\n", cancellable, error))
+ s = "AUTH\r\n";
+ debug_print ("CLIENT: writing `%s'", s);
+ if (!g_data_output_stream_put_string (dos, s, cancellable, error))
goto out;
state = CLIENT_STATE_WAITING_FOR_REJECT;
@@ -698,9 +830,11 @@ _g_dbus_auth_run_client (GDBusAuth *auth,
switch (state)
{
case CLIENT_STATE_WAITING_FOR_REJECT:
+ debug_print ("CLIENT: WaitingForReject");
line = _my_g_data_input_stream_read_line (dis, &line_length, cancellable, error);
if (line == NULL)
goto out;
+ debug_print ("CLIENT: WaitingForReject, read '%s'", line);
foobar:
if (!g_str_has_prefix (line, "REJECTED "))
{
@@ -722,6 +856,7 @@ _g_dbus_auth_run_client (GDBusAuth *auth,
}
g_free (line);
mech = client_choose_mech_and_send_initial_response (auth,
+ credentials,
(const gchar* const *) supported_auth_mechs,
attempted_auth_mechs,
dos,
@@ -736,9 +871,11 @@ _g_dbus_auth_run_client (GDBusAuth *auth,
break;
case CLIENT_STATE_WAITING_FOR_OK:
+ debug_print ("CLIENT: WaitingForOK");
line = _my_g_data_input_stream_read_line (dis, &line_length, cancellable, error);
if (line == NULL)
goto out;
+ debug_print ("CLIENT: WaitingForOK, read `%s'", line);
if (g_str_has_prefix (line, "OK "))
{
if (!g_dbus_is_guid (line + 3))
@@ -756,13 +893,17 @@ _g_dbus_auth_run_client (GDBusAuth *auth,
if (offered_capabilities & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING)
{
- if (!g_data_output_stream_put_string (dos, "NEGOTIATE_UNIX_FD\r\n", cancellable, error))
+ s = "NEGOTIATE_UNIX_FD\r\n";
+ debug_print ("CLIENT: writing `%s'", s);
+ if (!g_data_output_stream_put_string (dos, s, cancellable, error))
goto out;
state = CLIENT_STATE_WAITING_FOR_AGREE_UNIX_FD;
}
else
{
- if (!g_data_output_stream_put_string (dos, "BEGIN\r\n", cancellable, error))
+ s = "BEGIN\r\n";
+ debug_print ("CLIENT: writing `%s'", s);
+ if (!g_data_output_stream_put_string (dos, s, cancellable, error))
goto out;
/* and we're done! */
goto out;
@@ -786,13 +927,17 @@ _g_dbus_auth_run_client (GDBusAuth *auth,
break;
case CLIENT_STATE_WAITING_FOR_AGREE_UNIX_FD:
+ debug_print ("CLIENT: WaitingForAgreeUnixFD");
line = _my_g_data_input_stream_read_line (dis, &line_length, cancellable, error);
if (line == NULL)
goto out;
+ debug_print ("CLIENT: WaitingForAgreeUnixFD, read=`%s'", line);
if (g_strcmp0 (line, "AGREE_UNIX_FD") == 0)
{
negotiated_capabilities |= G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING;
- if (!g_data_output_stream_put_string (dos, "BEGIN\r\n", cancellable, error))
+ s = "BEGIN\r\n";
+ debug_print ("CLIENT: writing `%s'", s);
+ if (!g_data_output_stream_put_string (dos, s, cancellable, error))
goto out;
/* and we're done! */
goto out;
@@ -801,7 +946,9 @@ _g_dbus_auth_run_client (GDBusAuth *auth,
{
//g_strstrip (line + 5); g_debug ("bah, no unix_fd: `%s'", line + 5);
g_free (line);
- if (!g_data_output_stream_put_string (dos, "BEGIN\r\n", cancellable, error))
+ s = "BEGIN\r\n";
+ debug_print ("CLIENT: writing `%s'", s);
+ if (!g_data_output_stream_put_string (dos, s, cancellable, error))
goto out;
/* and we're done! */
goto out;
@@ -820,8 +967,61 @@ _g_dbus_auth_run_client (GDBusAuth *auth,
break;
case CLIENT_STATE_WAITING_FOR_DATA:
- /* TODO: handle */
- g_assert_not_reached ();
+ debug_print ("CLIENT: WaitingForData");
+ line = _my_g_data_input_stream_read_line (dis, &line_length, cancellable, error);
+ if (line == NULL)
+ goto out;
+ debug_print ("CLIENT: WaitingForData, read=`%s'", line);
+ if (g_str_has_prefix (line, "DATA "))
+ {
+ gchar *encoded;
+ gchar *decoded_data;
+ gsize decoded_data_len;
+
+ encoded = g_strdup (line + 5);
+ g_free (line);
+ g_strstrip (encoded);
+ decoded_data = hexdecode (encoded, &decoded_data_len, error);
+ g_free (encoded);
+ if (decoded_data == NULL)
+ {
+ g_prefix_error (error, "DATA response is malformed: ");
+ /* invalid encoding, disconnect! */
+ goto out;
+ }
+ _g_dbus_auth_mechanism_client_data_receive (mech, decoded_data, decoded_data_len);
+ g_free (decoded_data);
+
+ if (_g_dbus_auth_mechanism_client_get_state (mech) == G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND)
+ {
+ gchar *data;
+ gsize data_len;
+ gchar *encoded_data;
+ data = _g_dbus_auth_mechanism_client_data_send (mech, &data_len);
+ encoded_data = hexencode (data);
+ s = g_strdup_printf ("DATA %s\r\n", encoded_data);
+ g_free (encoded_data);
+ g_free (data);
+ debug_print ("CLIENT: writing `%s'", s);
+ if (!g_data_output_stream_put_string (dos, s, cancellable, error))
+ {
+ g_free (s);
+ goto out;
+ }
+ g_free (s);
+ }
+ state = CLIENT_STATE_WAITING_FOR_OK;
+ }
+ else
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "In WaitingForData: unexpected response `%s'",
+ line);
+ g_free (line);
+ goto out;
+ }
break;
default:
@@ -852,6 +1052,11 @@ _g_dbus_auth_run_client (GDBusAuth *auth,
*out_negotiated_capabilities = negotiated_capabilities;
}
+ if (credentials != NULL)
+ g_object_unref (credentials);
+
+ debug_print ("CLIENT: Done, authenticated=%d", ret_guid != NULL);
+
return ret_guid;
}
@@ -864,27 +1069,24 @@ get_auth_mechanisms (GDBusAuth *auth,
const gchar *suffix,
const gchar *separator)
{
- GString *str;
- GList *keys;
GList *l;
+ GString *str;
gboolean need_sep;
str = g_string_new (prefix);
-
- keys = g_hash_table_get_keys (auth->priv->map_auth_mech_name_to_gtype);
- keys = g_list_sort (keys, (GCompareFunc) g_strcmp0);
need_sep = FALSE;
- for (l = keys; l != NULL; l = l->next)
+ for (l = auth->priv->available_mechanisms; l != NULL; l = l->next)
{
- const gchar *mech_name = l->data;
- if (!allow_anonymous && g_strcmp0 (mech_name, "ANONYMOUS") == 0)
+ Mechanism *m = l->data;
+
+ if (!allow_anonymous && g_strcmp0 (m->name, "ANONYMOUS") == 0)
continue;
+
if (need_sep)
g_string_append (str, separator);
- g_string_append (str, mech_name);
+ g_string_append (str, m->name);
need_sep = TRUE;
}
- g_list_free (keys);
g_string_append (str, suffix);
return g_string_free (str, FALSE);
@@ -922,6 +1124,8 @@ _g_dbus_auth_run_server (GDBusAuth *auth,
GDBusCapabilityFlags negotiated_capabilities;
GCredentials *credentials;
+ debug_print ("SERVER: initiating");
+
ret = FALSE;
dis = NULL;
dos = NULL;
@@ -977,6 +1181,10 @@ _g_dbus_auth_run_server (GDBusAuth *auth,
goto out;
}
#endif
+ if (credentials != NULL)
+ debug_print ("SERVER: received credentials");
+ else
+ debug_print ("SERVER: didn't receive any credentials");
state = SERVER_STATE_WAITING_FOR_AUTH;
while (TRUE)
@@ -984,13 +1192,15 @@ _g_dbus_auth_run_server (GDBusAuth *auth,
switch (state)
{
case SERVER_STATE_WAITING_FOR_AUTH:
+ debug_print ("SERVER: WaitingForAuth");
line = _my_g_data_input_stream_read_line (dis, &line_length, cancellable, error);
+ debug_print ("SERVER: WaitingForAuth, read `%s'", line);
if (line == NULL)
goto out;
if (g_strcmp0 (line, "AUTH") == 0)
{
- gchar *s;
s = get_auth_mechanisms (auth, allow_anonymous, "REJECTED ", "\r\n", " ");
+ debug_print ("SERVER: writing `%s'", s);
if (!g_data_output_stream_put_string (dos, s, cancellable, error))
{
g_free (s);
@@ -1036,15 +1246,14 @@ _g_dbus_auth_run_server (GDBusAuth *auth,
/* TODO: record that the client has attempted to use this mechanism */
//g_debug ("client is trying `%s'", mech_name);
- auth_mech_to_use_gtype = (GType) g_hash_table_lookup (auth->priv->map_auth_mech_name_to_gtype,
- mech_name);
+ auth_mech_to_use_gtype = find_mech_by_name (auth, mech_name);
if ((auth_mech_to_use_gtype == (GType) 0) ||
(!allow_anonymous && g_strcmp0 (mech_name, "ANONYMOUS") == 0))
{
- gchar *s;
/* We don't support this auth mechanism */
g_strfreev (tokens);
s = get_auth_mechanisms (auth, allow_anonymous, "REJECTED ", "\r\n", " ");
+ debug_print ("SERVER: writing `%s'", s);
if (!g_data_output_stream_put_string (dos, s, cancellable, error))
{
g_free (s);
@@ -1060,7 +1269,10 @@ _g_dbus_auth_run_server (GDBusAuth *auth,
gchar *initial_response;
gsize initial_response_len;
- mech = g_object_new (auth_mech_to_use_gtype, NULL);
+ mech = g_object_new (auth_mech_to_use_gtype,
+ "stream", auth->priv->stream,
+ "credentials", credentials,
+ NULL);
initial_response = NULL;
initial_response_len = 0;
@@ -1082,6 +1294,7 @@ _g_dbus_auth_run_server (GDBusAuth *auth,
g_free (initial_response);
g_strfreev (tokens);
+ change_state:
switch (_g_dbus_auth_mechanism_server_get_state (mech))
{
case G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED:
@@ -1100,6 +1313,7 @@ _g_dbus_auth_run_server (GDBusAuth *auth,
else
{
s = g_strdup_printf ("OK %s\r\n", guid);
+ debug_print ("SERVER: writing `%s'", s);
if (!g_data_output_stream_put_string (dos, s, cancellable, error))
{
g_free (s);
@@ -1112,6 +1326,7 @@ _g_dbus_auth_run_server (GDBusAuth *auth,
case G_DBUS_AUTH_MECHANISM_STATE_REJECTED:
s = get_auth_mechanisms (auth, allow_anonymous, "REJECTED ", "\r\n", " ");
+ debug_print ("SERVER: writing `%s'", s);
if (!g_data_output_stream_put_string (dos, s, cancellable, error))
{
g_free (s);
@@ -1121,6 +1336,31 @@ _g_dbus_auth_run_server (GDBusAuth *auth,
state = SERVER_STATE_WAITING_FOR_AUTH;
break;
+ case G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA:
+ state = SERVER_STATE_WAITING_FOR_DATA;
+ break;
+
+ case G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND:
+ {
+ gchar *data;
+ gsize data_len;
+ gchar *encoded_data;
+ data = _g_dbus_auth_mechanism_server_data_send (mech, &data_len);
+ encoded_data = hexencode (data);
+ s = g_strdup_printf ("DATA %s\r\n", encoded_data);
+ g_free (encoded_data);
+ g_free (data);
+ debug_print ("SERVER: writing `%s'", s);
+ if (!g_data_output_stream_put_string (dos, s, cancellable, error))
+ {
+ g_free (s);
+ goto out;
+ }
+ g_free (s);
+ }
+ goto change_state;
+ break;
+
default:
/* TODO */
g_assert_not_reached ();
@@ -1141,18 +1381,46 @@ _g_dbus_auth_run_server (GDBusAuth *auth,
break;
case SERVER_STATE_WAITING_FOR_DATA:
+ debug_print ("SERVER: WaitingForData");
line = _my_g_data_input_stream_read_line (dis, &line_length, cancellable, error);
+ debug_print ("SERVER: WaitingForData, read `%s'", line);
if (line == NULL)
goto out;
- g_set_error (error,
- G_IO_ERROR,
- G_IO_ERROR_FAILED,
- "Unexpected line `%s' while in WaitingForData state",
- line);
- g_free (line);
+ if (g_str_has_prefix (line, "DATA "))
+ {
+ gchar *encoded;
+ gchar *decoded_data;
+ gsize decoded_data_len;
+
+ encoded = g_strdup (line + 5);
+ g_free (line);
+ g_strstrip (encoded);
+ decoded_data = hexdecode (encoded, &decoded_data_len, error);
+ g_free (encoded);
+ if (decoded_data == NULL)
+ {
+ g_prefix_error (error, "DATA response is malformed: ");
+ /* invalid encoding, disconnect! */
+ goto out;
+ }
+ _g_dbus_auth_mechanism_server_data_receive (mech, decoded_data, decoded_data_len);
+ g_free (decoded_data);
+ /* oh man, this goto-crap is so ugly.. really need to rewrite the state machine */
+ goto change_state;
+ }
+ else
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "Unexpected line `%s' while in WaitingForData state",
+ line);
+ g_free (line);
+ }
goto out;
case SERVER_STATE_WAITING_FOR_BEGIN:
+ debug_print ("SERVER: WaitingForBegin");
/* Use extremely slow (but reliable) line reader - this basically
* does a recvfrom() system call per character
*
@@ -1164,6 +1432,7 @@ _g_dbus_auth_run_server (GDBusAuth *auth,
&line_length,
cancellable,
error);
+ debug_print ("SERVER: WaitingForBegin, read `%s'", line);
if (line == NULL)
goto out;
if (g_strcmp0 (line, "BEGIN") == 0)
@@ -1178,12 +1447,16 @@ _g_dbus_auth_run_server (GDBusAuth *auth,
if (offered_capabilities & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING)
{
negotiated_capabilities |= G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING;
- if (!g_data_output_stream_put_string (dos, "AGREE_UNIX_FD\r\n", cancellable, error))
+ s = "AGREE_UNIX_FD\r\n";
+ debug_print ("SERVER: writing `%s'", s);
+ if (!g_data_output_stream_put_string (dos, s, cancellable, error))
goto out;
}
else
{
- if (!g_data_output_stream_put_string (dos, "ERROR \"fd passing not offered\"\r\n", cancellable, error))
+ s = "ERROR \"fd passing not offered\"\r\n";
+ debug_print ("SERVER: writing `%s'", s);
+ if (!g_data_output_stream_put_string (dos, s, cancellable, error))
goto out;
}
}
@@ -1191,7 +1464,9 @@ _g_dbus_auth_run_server (GDBusAuth *auth,
{
g_debug ("Unexpected line `%s' while in WaitingForBegin state", line);
g_free (line);
- if (!g_data_output_stream_put_string (dos, "ERROR \"Unknown Command\"\r\n", cancellable, error))
+ s = "ERROR \"Unknown Command\"\r\n";
+ debug_print ("SERVER: writing `%s'", s);
+ if (!g_data_output_stream_put_string (dos, s, cancellable, error))
goto out;
}
break;
@@ -1233,6 +1508,8 @@ _g_dbus_auth_run_server (GDBusAuth *auth,
if (credentials != NULL)
g_object_unref (credentials);
+ debug_print ("SERVER: Done, authenticated=%d", ret);
+
return ret;
}
diff --git a/gdbus/gdbusauthmechanism.c b/gdbus/gdbusauthmechanism.c
index 313e465..56dfcbc 100644
--- a/gdbus/gdbusauthmechanism.c
+++ b/gdbus/gdbusauthmechanism.c
@@ -25,32 +25,205 @@
#include <glib/gi18n.h>
#include "gdbusauthmechanism.h"
+#include "gcredentials.h"
#include "gdbuserror.h"
#include "gdbusenumtypes.h"
+/* ---------------------------------------------------------------------------------------------------- */
+
+struct _GDBusAuthMechanismPrivate
+{
+ GIOStream *stream;
+ GCredentials *credentials;
+};
+
+enum
+{
+ PROP_0,
+ PROP_STREAM,
+ PROP_CREDENTIALS
+};
+
G_DEFINE_ABSTRACT_TYPE (GDBusAuthMechanism, _g_dbus_auth_mechanism, G_TYPE_OBJECT);
/* ---------------------------------------------------------------------------------------------------- */
static void
+_g_dbus_auth_mechanism_finalize (GObject *object)
+{
+ GDBusAuthMechanism *mechanism = G_DBUS_AUTH_MECHANISM (object);
+
+ if (mechanism->priv->stream != NULL)
+ g_object_unref (mechanism->priv->stream);
+ if (mechanism->priv->credentials != NULL)
+ g_object_unref (mechanism->priv->credentials);
+
+ if (G_OBJECT_CLASS (_g_dbus_auth_mechanism_parent_class)->finalize != NULL)
+ G_OBJECT_CLASS (_g_dbus_auth_mechanism_parent_class)->finalize (object);
+}
+
+static void
+_g_dbus_auth_mechanism_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GDBusAuthMechanism *mechanism = G_DBUS_AUTH_MECHANISM (object);
+
+ switch (prop_id)
+ {
+ case PROP_STREAM:
+ g_value_set_object (value, mechanism->priv->stream);
+ break;
+
+ case PROP_CREDENTIALS:
+ g_value_set_object (value, mechanism->priv->credentials);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+_g_dbus_auth_mechanism_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GDBusAuthMechanism *mechanism = G_DBUS_AUTH_MECHANISM (object);
+
+ switch (prop_id)
+ {
+ case PROP_STREAM:
+ mechanism->priv->stream = g_value_dup_object (value);
+ break;
+
+ case PROP_CREDENTIALS:
+ mechanism->priv->credentials = g_value_dup_object (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
_g_dbus_auth_mechanism_class_init (GDBusAuthMechanismClass *klass)
{
+ GObjectClass *gobject_class;
+
+ g_type_class_add_private (klass, sizeof (GDBusAuthMechanismPrivate));
+
+ gobject_class = G_OBJECT_CLASS (klass);
+ gobject_class->get_property = _g_dbus_auth_mechanism_get_property;
+ gobject_class->set_property = _g_dbus_auth_mechanism_set_property;
+ gobject_class->finalize = _g_dbus_auth_mechanism_finalize;
+
+ g_object_class_install_property (gobject_class,
+ PROP_STREAM,
+ g_param_spec_object ("stream",
+ _("IO Stream"),
+ _("The underlying GIOStream used for I/O"),
+ G_TYPE_IO_STREAM,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_BLURB |
+ G_PARAM_STATIC_NICK));
+
+ /**
+ * GDBusAuthMechanism:credentials:
+ *
+ * If authenticating as a server, this property contains the
+ * received credentials, if any.
+ *
+ * If authenticating as a client, the property contains the
+ * credentials that were sent, if any.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_CREDENTIALS,
+ g_param_spec_object ("credentials",
+ _("Credentials"),
+ _("The credentials of the remote peer"),
+ G_TYPE_CREDENTIALS,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_BLURB |
+ G_PARAM_STATIC_NICK));
}
static void
_g_dbus_auth_mechanism_init (GDBusAuthMechanism *mechanism)
{
/* not used for now */
- mechanism->priv = NULL;
+ mechanism->priv = G_TYPE_INSTANCE_GET_PRIVATE (mechanism,
+ G_TYPE_DBUS_AUTH_MECHANISM,
+ GDBusAuthMechanismPrivate);
}
/* ---------------------------------------------------------------------------------------------------- */
-const gchar *
-_g_dbus_auth_mechanism_get_name (GDBusAuthMechanism *mechanism)
+GIOStream *
+_g_dbus_auth_mechanism_get_stream (GDBusAuthMechanism *mechanism)
+{
+ g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM (mechanism), NULL);
+ return mechanism->priv->stream;
+}
+
+GCredentials *
+_g_dbus_auth_mechanism_get_credentials (GDBusAuthMechanism *mechanism)
{
g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM (mechanism), NULL);
- return G_DBUS_AUTH_MECHANISM_GET_CLASS (mechanism)->get_name (mechanism);
+ return mechanism->priv->credentials;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+const gchar *
+_g_dbus_auth_mechanism_get_name (GType mechanism_type)
+{
+ const gchar *name;
+ GDBusAuthMechanismClass *klass;
+
+ g_return_val_if_fail (g_type_is_a (mechanism_type, G_TYPE_DBUS_AUTH_MECHANISM), NULL);
+
+ klass = g_type_class_ref (mechanism_type);
+ g_assert (klass != NULL);
+ name = klass->get_name ();
+ //g_type_class_unref (klass);
+
+ return name;
+}
+
+gint
+_g_dbus_auth_mechanism_get_priority (GType mechanism_type)
+{
+ gint priority;
+ GDBusAuthMechanismClass *klass;
+
+ g_return_val_if_fail (g_type_is_a (mechanism_type, G_TYPE_DBUS_AUTH_MECHANISM), 0);
+
+ klass = g_type_class_ref (mechanism_type);
+ g_assert (klass != NULL);
+ priority = klass->get_priority ();
+ //g_type_class_unref (klass);
+
+ return priority;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+gboolean
+_g_dbus_auth_mechanism_is_supported (GDBusAuthMechanism *mechanism)
+{
+ g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM (mechanism), FALSE);
+ return G_DBUS_AUTH_MECHANISM_GET_CLASS (mechanism)->is_supported (mechanism);
}
gchar *
diff --git a/gdbus/gdbusauthmechanism.h b/gdbus/gdbusauthmechanism.h
index 4eda2b0..2dfcb42 100644
--- a/gdbus/gdbusauthmechanism.h
+++ b/gdbus/gdbusauthmechanism.h
@@ -63,40 +63,43 @@ struct _GDBusAuthMechanismClass
* GCredentials parameter...
*/
+ gint (*get_priority) (void);
+ const gchar *(*get_name) (void);
+
/* functions shared by server/client */
- const gchar *(*get_name) (GDBusAuthMechanism *mechanismanism);
- gchar *(*encode_data) (GDBusAuthMechanism *mechanismanism,
+ gboolean (*is_supported) (GDBusAuthMechanism *mechanism);
+ gchar *(*encode_data) (GDBusAuthMechanism *mechanism,
const gchar *data,
gsize data_len,
gsize *out_data_len);
- gchar *(*decode_data) (GDBusAuthMechanism *mechanismanism,
+ gchar *(*decode_data) (GDBusAuthMechanism *mechanism,
const gchar *data,
gsize data_len,
gsize *out_data_len);
/* functions for server-side authentication */
- GDBusAuthMechanismState (*server_get_state) (GDBusAuthMechanism *mechanismanism);
- void (*server_initiate) (GDBusAuthMechanism *mechanismanism,
+ GDBusAuthMechanismState (*server_get_state) (GDBusAuthMechanism *mechanism);
+ void (*server_initiate) (GDBusAuthMechanism *mechanism,
const gchar *initial_response,
gsize initial_response_len);
- void (*server_data_receive) (GDBusAuthMechanism *mechanismanism,
+ void (*server_data_receive) (GDBusAuthMechanism *mechanism,
const gchar *data,
gsize data_len);
- gchar *(*server_data_send) (GDBusAuthMechanism *mechanismanism,
+ gchar *(*server_data_send) (GDBusAuthMechanism *mechanism,
gsize *out_data_len);
- gchar *(*server_get_reject_reason) (GDBusAuthMechanism *mechanismanism);
- void (*server_shutdown) (GDBusAuthMechanism *mechanismanism);
+ gchar *(*server_get_reject_reason) (GDBusAuthMechanism *mechanism);
+ void (*server_shutdown) (GDBusAuthMechanism *mechanism);
/* functions for client-side authentication */
- GDBusAuthMechanismState (*client_get_state) (GDBusAuthMechanism *mechanismanism);
- gchar *(*client_initiate) (GDBusAuthMechanism *mechanismanism,
+ GDBusAuthMechanismState (*client_get_state) (GDBusAuthMechanism *mechanism);
+ gchar *(*client_initiate) (GDBusAuthMechanism *mechanism,
gsize *out_initial_response_len);
- void (*client_data_receive) (GDBusAuthMechanism *mechanismanism,
+ void (*client_data_receive) (GDBusAuthMechanism *mechanism,
const gchar *data,
gsize data_len);
- gchar *(*client_data_send) (GDBusAuthMechanism *mechanismanism,
+ gchar *(*client_data_send) (GDBusAuthMechanism *mechanism,
gsize *out_data_len);
- void (*client_shutdown) (GDBusAuthMechanism *mechanismanism);
+ void (*client_shutdown) (GDBusAuthMechanism *mechanism);
/*< private >*/
@@ -127,37 +130,43 @@ struct _GDBusAuthMechanism
GType _g_dbus_auth_mechanism_get_type (void) G_GNUC_CONST;
-const gchar *_g_dbus_auth_mechanism_get_name (GDBusAuthMechanism *mechanismanism);
-gchar *_g_dbus_auth_mechanism_encode_data (GDBusAuthMechanism *mechanismanism,
+gint _g_dbus_auth_mechanism_get_priority (GType mechanism_type);
+const gchar *_g_dbus_auth_mechanism_get_name (GType mechanism_type);
+
+GIOStream *_g_dbus_auth_mechanism_get_stream (GDBusAuthMechanism *mechanism);
+GCredentials *_g_dbus_auth_mechanism_get_credentials (GDBusAuthMechanism *mechanism);
+
+gboolean _g_dbus_auth_mechanism_is_supported (GDBusAuthMechanism *mechanism);
+gchar *_g_dbus_auth_mechanism_encode_data (GDBusAuthMechanism *mechanism,
const gchar *data,
gsize data_len,
gsize *out_data_len);
-gchar *_g_dbus_auth_mechanism_decode_data (GDBusAuthMechanism *mechanismanism,
+gchar *_g_dbus_auth_mechanism_decode_data (GDBusAuthMechanism *mechanism,
const gchar *data,
gsize data_len,
gsize *out_data_len);
-GDBusAuthMechanismState _g_dbus_auth_mechanism_server_get_state (GDBusAuthMechanism *mechanismanism);
-void _g_dbus_auth_mechanism_server_initiate (GDBusAuthMechanism *mechanismanism,
+GDBusAuthMechanismState _g_dbus_auth_mechanism_server_get_state (GDBusAuthMechanism *mechanism);
+void _g_dbus_auth_mechanism_server_initiate (GDBusAuthMechanism *mechanism,
const gchar *initial_response,
gsize initial_response_len);
-void _g_dbus_auth_mechanism_server_data_receive (GDBusAuthMechanism *mechanismanism,
+void _g_dbus_auth_mechanism_server_data_receive (GDBusAuthMechanism *mechanism,
const gchar *data,
gsize data_len);
-gchar *_g_dbus_auth_mechanism_server_data_send (GDBusAuthMechanism *mechanismanism,
+gchar *_g_dbus_auth_mechanism_server_data_send (GDBusAuthMechanism *mechanism,
gsize *out_data_len);
-gchar *_g_dbus_auth_mechanism_server_get_reject_reason (GDBusAuthMechanism *mechanismanism);
-void _g_dbus_auth_mechanism_server_shutdown (GDBusAuthMechanism *mechanismanism);
+gchar *_g_dbus_auth_mechanism_server_get_reject_reason (GDBusAuthMechanism *mechanism);
+void _g_dbus_auth_mechanism_server_shutdown (GDBusAuthMechanism *mechanism);
-GDBusAuthMechanismState _g_dbus_auth_mechanism_client_get_state (GDBusAuthMechanism *mechanismanism);
-gchar *_g_dbus_auth_mechanism_client_initiate (GDBusAuthMechanism *mechanismanism,
+GDBusAuthMechanismState _g_dbus_auth_mechanism_client_get_state (GDBusAuthMechanism *mechanism);
+gchar *_g_dbus_auth_mechanism_client_initiate (GDBusAuthMechanism *mechanism,
gsize *out_initial_response_len);
-void _g_dbus_auth_mechanism_client_data_receive (GDBusAuthMechanism *mechanismanism,
+void _g_dbus_auth_mechanism_client_data_receive (GDBusAuthMechanism *mechanism,
const gchar *data,
gsize data_len);
-gchar *_g_dbus_auth_mechanism_client_data_send (GDBusAuthMechanism *mechanismanism,
+gchar *_g_dbus_auth_mechanism_client_data_send (GDBusAuthMechanism *mechanism,
gsize *out_data_len);
-void _g_dbus_auth_mechanism_client_shutdown (GDBusAuthMechanism *mechanismanism);
+void _g_dbus_auth_mechanism_client_shutdown (GDBusAuthMechanism *mechanism);
G_END_DECLS
diff --git a/gdbus/gdbusauthmechanismanon.c b/gdbus/gdbusauthmechanismanon.c
index d841539..2038632 100644
--- a/gdbus/gdbusauthmechanismanon.c
+++ b/gdbus/gdbusauthmechanismanon.c
@@ -35,7 +35,10 @@ struct _GDBusAuthMechanismAnonPrivate
GDBusAuthMechanismState state;
};
-static const gchar *mechanism_get_name (GDBusAuthMechanism *mechanism);
+static gint mechanism_get_priority (void);
+static const gchar *mechanism_get_name (void);
+
+static gboolean mechanism_is_supported (GDBusAuthMechanism *mechanism);
static gchar *mechanism_encode_data (GDBusAuthMechanism *mechanism,
const gchar *data,
gsize data_len,
@@ -92,7 +95,9 @@ _g_dbus_auth_mechanism_anon_class_init (GDBusAuthMechanismAnonClass *klass)
gobject_class->finalize = _g_dbus_auth_mechanism_anon_finalize;
mechanism_class = G_DBUS_AUTH_MECHANISM_CLASS (klass);
+ mechanism_class->get_priority = mechanism_get_priority;
mechanism_class->get_name = mechanism_get_name;
+ mechanism_class->is_supported = mechanism_is_supported;
mechanism_class->encode_data = mechanism_encode_data;
mechanism_class->decode_data = mechanism_decode_data;
mechanism_class->server_get_state = mechanism_server_get_state;
@@ -118,13 +123,27 @@ _g_dbus_auth_mechanism_anon_init (GDBusAuthMechanismAnon *mechanism)
/* ---------------------------------------------------------------------------------------------------- */
+
+static gint
+mechanism_get_priority (void)
+{
+ return 0;
+}
+
+
static const gchar *
-mechanism_get_name (GDBusAuthMechanism *mechanism)
+mechanism_get_name (void)
{
- g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_ANON (mechanism), NULL);
return "ANONYMOUS";
}
+static gboolean
+mechanism_is_supported (GDBusAuthMechanism *mechanism)
+{
+ g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_ANON (mechanism), FALSE);
+ return TRUE;
+}
+
static gchar *
mechanism_encode_data (GDBusAuthMechanism *mechanism,
const gchar *data,
diff --git a/gdbus/gdbusauthmechanismexternal.c b/gdbus/gdbusauthmechanismexternal.c
index 793ef56..aceeade 100644
--- a/gdbus/gdbusauthmechanismexternal.c
+++ b/gdbus/gdbusauthmechanismexternal.c
@@ -40,7 +40,10 @@ struct _GDBusAuthMechanismExternalPrivate
GDBusAuthMechanismState state;
};
-static const gchar *mechanism_get_name (GDBusAuthMechanism *mechanism);
+static gint mechanism_get_priority (void);
+static const gchar *mechanism_get_name (void);
+
+static gboolean mechanism_is_supported (GDBusAuthMechanism *mechanism);
static gchar *mechanism_encode_data (GDBusAuthMechanism *mechanism,
const gchar *data,
gsize data_len,
@@ -98,6 +101,8 @@ _g_dbus_auth_mechanism_external_class_init (GDBusAuthMechanismExternalClass *kla
mechanism_class = G_DBUS_AUTH_MECHANISM_CLASS (klass);
mechanism_class->get_name = mechanism_get_name;
+ mechanism_class->get_priority = mechanism_get_priority;
+ mechanism_class->is_supported = mechanism_is_supported;
mechanism_class->encode_data = mechanism_encode_data;
mechanism_class->decode_data = mechanism_decode_data;
mechanism_class->server_get_state = mechanism_server_get_state;
@@ -123,10 +128,27 @@ _g_dbus_auth_mechanism_external_init (GDBusAuthMechanismExternal *mechanism)
/* ---------------------------------------------------------------------------------------------------- */
+static gboolean
+mechanism_is_supported (GDBusAuthMechanism *mechanism)
+{
+ g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), FALSE);
+ /* This mechanism is only available if credentials has been exchanged */
+ if (_g_dbus_auth_mechanism_get_credentials (mechanism) != NULL)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+static gint
+mechanism_get_priority (void)
+{
+ /* We prefer EXTERNAL to most other mechanism (DBUS_COOKIE_SHA1 and ANONYMOUS) */
+ return 100;
+}
+
static const gchar *
-mechanism_get_name (GDBusAuthMechanism *mechanism)
+mechanism_get_name (void)
{
- g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), NULL);
return "EXTERNAL";
}
@@ -172,8 +194,11 @@ mechanism_server_initiate (GDBusAuthMechanism *mechanism,
g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism));
g_return_if_fail (!m->priv->is_server && !m->priv->is_client);
- //if (initial_response != NULL)
- // g_debug ("EXTERNAL: initial_response was `%s'", initial_response);
+ if (initial_response != NULL)
+ {
+ g_debug ("EXTERNAL: initial_response was `%s'", initial_response);
+ g_debug ("EXTERNAL: credentials `%p'", _g_dbus_auth_mechanism_get_credentials (G_DBUS_AUTH_MECHANISM (mechanism)));
+ }
m->priv->is_server = TRUE;
diff --git a/gdbus/gdbusauthmechanismsha1.c b/gdbus/gdbusauthmechanismsha1.c
new file mode 100644
index 0000000..5fca3ac
--- /dev/null
+++ b/gdbus/gdbusauthmechanismsha1.c
@@ -0,0 +1,1209 @@
+/* GDBus - GLib D-Bus Library
+ *
+ * Copyright (C) 2008-2009 Red Hat, Inc.
+ *
+ * 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 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., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz@redhat.com>
+ */
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+
+#include "gdbusauthmechanismsha1.h"
+#include "gcredentials.h"
+#include "gdbuserror.h"
+#include "gdbusenumtypes.h"
+
+#ifdef G_OS_UNIX
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#endif
+
+#include <errno.h>
+
+#include <glib/gstdio.h>
+
+struct _GDBusAuthMechanismSha1Private
+{
+ gboolean is_client;
+ gboolean is_server;
+ GDBusAuthMechanismState state;
+
+ /* used on the client side */
+ gchar *to_send;
+
+ /* used on the server side */
+ gchar *cookie;
+ gchar *server_challenge;
+};
+
+static gint mechanism_get_priority (void);
+static const gchar *mechanism_get_name (void);
+
+static gboolean mechanism_is_supported (GDBusAuthMechanism *mechanism);
+static gchar *mechanism_encode_data (GDBusAuthMechanism *mechanism,
+ const gchar *data,
+ gsize data_len,
+ gsize *out_data_len);
+static gchar *mechanism_decode_data (GDBusAuthMechanism *mechanism,
+ const gchar *data,
+ gsize data_len,
+ gsize *out_data_len);
+static GDBusAuthMechanismState mechanism_server_get_state (GDBusAuthMechanism *mechanism);
+static void mechanism_server_initiate (GDBusAuthMechanism *mechanism,
+ const gchar *initial_response,
+ gsize initial_response_len);
+static void mechanism_server_data_receive (GDBusAuthMechanism *mechanism,
+ const gchar *data,
+ gsize data_len);
+static gchar *mechanism_server_data_send (GDBusAuthMechanism *mechanism,
+ gsize *out_data_len);
+static gchar *mechanism_server_get_reject_reason (GDBusAuthMechanism *mechanism);
+static void mechanism_server_shutdown (GDBusAuthMechanism *mechanism);
+static GDBusAuthMechanismState mechanism_client_get_state (GDBusAuthMechanism *mechanism);
+static gchar *mechanism_client_initiate (GDBusAuthMechanism *mechanism,
+ gsize *out_initial_response_len);
+static void mechanism_client_data_receive (GDBusAuthMechanism *mechanism,
+ const gchar *data,
+ gsize data_len);
+static gchar *mechanism_client_data_send (GDBusAuthMechanism *mechanism,
+ gsize *out_data_len);
+static void mechanism_client_shutdown (GDBusAuthMechanism *mechanism);
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+G_DEFINE_TYPE (GDBusAuthMechanismSha1, _g_dbus_auth_mechanism_sha1, G_TYPE_DBUS_AUTH_MECHANISM);
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+_g_dbus_auth_mechanism_sha1_finalize (GObject *object)
+{
+ GDBusAuthMechanismSha1 *mechanism = G_DBUS_AUTH_MECHANISM_SHA1 (object);
+
+ g_free (mechanism->priv->to_send);
+
+ g_free (mechanism->priv->cookie);
+ g_free (mechanism->priv->server_challenge);
+
+ if (G_OBJECT_CLASS (_g_dbus_auth_mechanism_sha1_parent_class)->finalize != NULL)
+ G_OBJECT_CLASS (_g_dbus_auth_mechanism_sha1_parent_class)->finalize (object);
+}
+
+static void
+_g_dbus_auth_mechanism_sha1_class_init (GDBusAuthMechanismSha1Class *klass)
+{
+ GObjectClass *gobject_class;
+ GDBusAuthMechanismClass *mechanism_class;
+
+ g_type_class_add_private (klass, sizeof (GDBusAuthMechanismSha1Private));
+
+ gobject_class = G_OBJECT_CLASS (klass);
+ gobject_class->finalize = _g_dbus_auth_mechanism_sha1_finalize;
+
+ mechanism_class = G_DBUS_AUTH_MECHANISM_CLASS (klass);
+ mechanism_class->get_priority = mechanism_get_priority;
+ mechanism_class->get_name = mechanism_get_name;
+ mechanism_class->is_supported = mechanism_is_supported;
+ mechanism_class->encode_data = mechanism_encode_data;
+ mechanism_class->decode_data = mechanism_decode_data;
+ mechanism_class->server_get_state = mechanism_server_get_state;
+ mechanism_class->server_initiate = mechanism_server_initiate;
+ mechanism_class->server_data_receive = mechanism_server_data_receive;
+ mechanism_class->server_data_send = mechanism_server_data_send;
+ mechanism_class->server_get_reject_reason = mechanism_server_get_reject_reason;
+ mechanism_class->server_shutdown = mechanism_server_shutdown;
+ mechanism_class->client_get_state = mechanism_client_get_state;
+ mechanism_class->client_initiate = mechanism_client_initiate;
+ mechanism_class->client_data_receive = mechanism_client_data_receive;
+ mechanism_class->client_data_send = mechanism_client_data_send;
+ mechanism_class->client_shutdown = mechanism_client_shutdown;
+}
+
+static void
+_g_dbus_auth_mechanism_sha1_init (GDBusAuthMechanismSha1 *mechanism)
+{
+ mechanism->priv = G_TYPE_INSTANCE_GET_PRIVATE (mechanism,
+ G_TYPE_DBUS_AUTH_MECHANISM_SHA1,
+ GDBusAuthMechanismSha1Private);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gint
+mechanism_get_priority (void)
+{
+ return 0;
+}
+
+static const gchar *
+mechanism_get_name (void)
+{
+ return "DBUS_COOKIE_SHA1";
+}
+
+static gboolean
+mechanism_is_supported (GDBusAuthMechanism *mechanism)
+{
+ g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), FALSE);
+ return TRUE;
+}
+
+static gchar *
+mechanism_encode_data (GDBusAuthMechanism *mechanism,
+ const gchar *data,
+ gsize data_len,
+ gsize *out_data_len)
+{
+ return NULL;
+}
+
+
+static gchar *
+mechanism_decode_data (GDBusAuthMechanism *mechanism,
+ const gchar *data,
+ gsize data_len,
+ gsize *out_data_len)
+{
+ return NULL;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gint
+random_ascii (void)
+{
+ gint ret;
+ ret = g_random_int_range (0, 60);
+ if (ret < 25)
+ ret += 'A';
+ else if (ret < 50)
+ ret += 'a' - 25;
+ else
+ ret += '0' - 50;
+ return ret;
+}
+
+static gchar *
+random_ascii_string (guint len)
+{
+ GString *challenge;
+ guint n;
+
+ challenge = g_string_new (NULL);
+ for (n = 0; n < len; n++)
+ g_string_append_c (challenge, random_ascii ());
+ return g_string_free (challenge, FALSE);
+}
+
+static gchar *
+random_blob (guint len)
+{
+ GString *challenge;
+ guint n;
+
+ challenge = g_string_new (NULL);
+ for (n = 0; n < len; n++)
+ g_string_append_c (challenge, g_random_int_range (0, 256));
+ return g_string_free (challenge, FALSE);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/* ensure keyring dir exists and permissions are correct */
+static gchar *
+ensure_keyring_directory (GError **error)
+{
+ gchar *path;
+ const gchar *e;
+
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ e = g_getenv ("G_DBUS_COOKIE_SHA1_KEYRING_DIR");
+ if (e != NULL)
+ {
+ path = g_strdup (e);
+ }
+ else
+ {
+ path = g_build_filename (g_get_home_dir (),
+ ".dbus-keyrings",
+ NULL);
+ }
+
+ if (g_file_test (path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
+ {
+ if (g_getenv ("G_DBUS_COOKIE_SHA1_KEYRING_DIR_IGNORE_PERMISSION") == NULL)
+ {
+#ifdef G_OS_UNIX
+ struct stat statbuf;
+ if (stat (path, &statbuf) != 0)
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ g_io_error_from_errno (errno),
+ _("Error statting directory `%s': %s"),
+ path,
+ strerror (errno));
+ g_free (path);
+ path = NULL;
+ goto out;
+ }
+ if ((statbuf.st_mode & 0777) != 0700)
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ _("Permissions on directory `%s' are malformed. Expected mode 0700, got 0%o"),
+ path,
+ statbuf.st_mode & 0777);
+ g_free (path);
+ path = NULL;
+ goto out;
+ }
+#else
+#error Please implement permission checking on non-UNIX platforms
+#endif
+ }
+ goto out;
+ }
+
+ if (g_mkdir (path, 0700) != 0)
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ g_io_error_from_errno (errno),
+ _("Error creating directory `%s': %s"),
+ path,
+ strerror (errno));
+ g_free (path);
+ path = NULL;
+ goto out;
+ }
+
+out:
+ return path;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+append_nibble (GString *s, gint val)
+{
+ g_string_append_c (s, val >= 10 ? ('a' + val - 10) : ('0' + val));
+}
+
+static gchar *
+hexencode (const gchar *str,
+ gssize len)
+{
+ guint n;
+ GString *s;
+
+ if (len == -1)
+ len = strlen (str);
+
+ s = g_string_new (NULL);
+ for (n = 0; n < len; n++)
+ {
+ gint val;
+ gint upper_nibble;
+ gint lower_nibble;
+
+ val = ((const guchar *) str)[n];
+ upper_nibble = val >> 4;
+ lower_nibble = val & 0x0f;
+
+ append_nibble (s, upper_nibble);
+ append_nibble (s, lower_nibble);
+ }
+
+ return g_string_free (s, FALSE);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/* looks up an entry in the keyring */
+static gchar *
+keyring_lookup_entry (const gchar *cookie_context,
+ gint cookie_id,
+ GError **error)
+{
+ gchar *ret;
+ gchar *keyring_dir;
+ gchar *contents;
+ gchar *path;
+ guint n;
+ gchar **lines;
+
+ g_return_val_if_fail (cookie_context != NULL, FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ ret = NULL;
+ path = NULL;
+ contents = NULL;
+ lines = NULL;
+
+ keyring_dir = ensure_keyring_directory (error);
+ if (keyring_dir == NULL)
+ goto out;
+
+ path = g_build_filename (keyring_dir, cookie_context, NULL);
+
+ if (!g_file_get_contents (path,
+ &contents,
+ NULL,
+ error))
+ {
+ g_prefix_error (error,
+ _("Error opening keyring `%s' for reading: "),
+ path);
+ goto out;
+ }
+ g_assert (contents != NULL);
+
+ lines = g_strsplit (contents, "\n", 0);
+ for (n = 0; lines[n] != NULL; n++)
+ {
+ const gchar *line = lines[n];
+ gchar **tokens;
+ gchar *endp;
+ gint line_id;
+ guint64 line_when;
+
+ if (line[0] == '\0')
+ continue;
+
+ tokens = g_strsplit (line, " ", 0);
+ if (g_strv_length (tokens) != 3)
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ _("Line %d of the keyring at `%s' with content `%s' is malformed"),
+ n + 1,
+ path,
+ line);
+ g_strfreev (tokens);
+ goto out;
+ }
+
+ line_id = g_ascii_strtoll (tokens[0], &endp, 10);
+ if (*endp != '\0')
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ _("First token of line %d of the keyring at `%s' with content `%s' is malformed"),
+ n + 1,
+ path,
+ line);
+ g_strfreev (tokens);
+ goto out;
+ }
+
+ line_when = g_ascii_strtoll (tokens[1], &endp, 10);
+ if (*endp != '\0')
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ _("Second token of line %d of the keyring at `%s' with content `%s' is malformed"),
+ n + 1,
+ path,
+ line);
+ g_strfreev (tokens);
+ goto out;
+ }
+
+ if (line_id == cookie_id)
+ {
+ /* YAY, success */
+ ret = tokens[2]; /* steal pointer */
+ tokens[2] = NULL;
+ g_strfreev (tokens);
+ goto out;
+ }
+
+ g_strfreev (tokens);
+ }
+
+ /* BOOH, didn't find the cookie */
+
+ out:
+ g_free (keyring_dir);
+ g_free (path);
+ g_free (contents);
+ g_strfreev (lines);
+ return ret;
+}
+
+/* function for logging important events that the system administrator should take notice of */
+static void
+_log (const gchar *message,
+ ...)
+{
+ gchar *s;
+ va_list var_args;
+
+ va_start (var_args, message);
+ s = g_strdup_vprintf (message, var_args);
+ va_end (var_args);
+
+ /* TODO: might want to send this to syslog instead */
+ g_printerr ("GDBus-DBUS_COOKIE_SHA1: %s\n", s);
+ g_free (s);
+}
+
+static gint
+keyring_acquire_lock (const gchar *path,
+ GError **error)
+{
+ gchar *lock;
+ gint ret;
+ guint num_tries;
+ guint num_create_tries;
+
+ g_return_val_if_fail (path != NULL, FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ ret = -1;
+ lock = g_strdup_printf ("%s.lock", path);
+
+ /* This is what the D-Bus spec says
+ *
+ * Create a lockfile name by appending ".lock" to the name of the
+ * cookie file. The server should attempt to create this file using
+ * O_CREAT | O_EXCL. If file creation fails, the lock
+ * fails. Servers should retry for a reasonable period of time,
+ * then they may choose to delete an existing lock to keep users
+ * from having to manually delete a stale lock. [1]
+ *
+ * [1] : Lockfiles are used instead of real file locking fcntl() because
+ * real locking implementations are still flaky on network filesystems
+ */
+
+ num_create_tries = 0;
+#ifdef EEXISTS
+ again:
+#endif
+ num_tries = 0;
+ while (g_file_test (lock, G_FILE_TEST_EXISTS))
+ {
+ /* sleep 10ms, then try again */
+ g_usleep (1000*10);
+ num_tries++;
+ if (num_tries == 50)
+ {
+ /* ok, we slept 50*10ms = 0.5 seconds.. Conclude that the lock-file must be
+ * stale (nuke the it from orbit)
+ */
+ if (g_unlink (lock) != 0)
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ g_io_error_from_errno (errno),
+ _("Error deleting stale lock-file `%s': %s"),
+ lock,
+ strerror (errno));
+ goto out;
+ }
+ _log ("Deleted stale lock-file `%s'", lock);
+ break;
+ }
+ }
+
+ ret = g_open (lock, O_CREAT |
+#ifdef O_EXCL
+ O_EXCL,
+#else
+ 0,
+#endif
+ 0700);
+ if (ret == -1)
+ {
+#ifdef EEXISTS
+ /* EEXIST: pathname already exists and O_CREAT and O_EXCL were used. */
+ if (errno == EEXISTS)
+ {
+ num_create_tries++;
+ if (num_create_tries < 5)
+ goto again;
+ }
+#endif
+ g_set_error (error,
+ G_IO_ERROR,
+ g_io_error_from_errno (errno),
+ _("Error creating lock-file `%s': %s"),
+ lock,
+ strerror (errno));
+ goto out;
+ }
+
+ out:
+ g_free (lock);
+ return ret;
+}
+
+static gboolean
+keyring_release_lock (const gchar *path,
+ gint lock_fd,
+ GError **error)
+{
+ gchar *lock;
+ gboolean ret;
+
+ g_return_val_if_fail (path != NULL, FALSE);
+ g_return_val_if_fail (lock_fd != -1, FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ ret = FALSE;
+ lock = g_strdup_printf ("%s.lock", path);
+ if (g_unlink (lock) != 0)
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ g_io_error_from_errno (errno),
+ _("Error unlinking lock-file `%s': %s"),
+ lock,
+ strerror (errno));
+ goto out;
+ }
+ if (close (lock_fd) != 0)
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ g_io_error_from_errno (errno),
+ _("Error closing (unlinked) lock-file `%s': %s"),
+ lock,
+ strerror (errno));
+ goto out;
+ }
+
+ ret = TRUE;
+
+ out:
+ g_free (lock);
+ return ret;
+}
+
+
+/* adds an entry to the keyring, taking care of locking and deleting stale/future entries */
+static gboolean
+keyring_generate_entry (const gchar *cookie_context,
+ gint *out_id,
+ gchar **out_cookie,
+ GError **error)
+{
+ gboolean ret;
+ gchar *keyring_dir;
+ gchar *path;
+ gchar *contents;
+ GError *local_error;
+ gchar **lines;
+ gint max_line_id;
+ GString *new_contents;
+ guint64 now;
+ gboolean have_id;
+ gint use_id;
+ gchar *use_cookie;
+ gboolean changed_file;
+ gint lock_fd;
+
+ g_return_val_if_fail (cookie_context != NULL, FALSE);
+ g_return_val_if_fail (out_id != NULL, FALSE);
+ g_return_val_if_fail (out_cookie != NULL, FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ ret = FALSE;
+ path = NULL;
+ contents = NULL;
+ lines = NULL;
+ new_contents = NULL;
+ have_id = FALSE;
+ use_cookie = NULL;
+ lock_fd = -1;
+
+ keyring_dir = ensure_keyring_directory (error);
+ if (keyring_dir == NULL)
+ goto out;
+
+ path = g_build_filename (keyring_dir, cookie_context, NULL);
+
+ lock_fd = keyring_acquire_lock (path, error);
+ if (lock_fd == -1)
+ goto out;
+
+ local_error = NULL;
+ contents = NULL;
+ if (!g_file_get_contents (path,
+ &contents,
+ NULL,
+ &local_error))
+ {
+ if (local_error->domain == G_FILE_ERROR && local_error->code == G_FILE_ERROR_NOENT)
+ {
+ /* file doesn't have to exist */
+ g_error_free (local_error);
+ }
+ else
+ {
+ g_propagate_prefixed_error (error,
+ local_error,
+ _("Error opening keyring `%s' for writing: "),
+ path);
+ goto out;
+ }
+ }
+
+ new_contents = g_string_new (NULL);
+ now = time (NULL);
+ changed_file = FALSE;
+
+ max_line_id = 0;
+ if (contents != NULL)
+ {
+ guint n;
+ lines = g_strsplit (contents, "\n", 0);
+ for (n = 0; lines[n] != NULL; n++)
+ {
+ const gchar *line = lines[n];
+ gchar **tokens;
+ gchar *endp;
+ gint line_id;
+ guint64 line_when;
+ gboolean keep_entry;
+
+ if (line[0] == '\0')
+ continue;
+
+ tokens = g_strsplit (line, " ", 0);
+ if (g_strv_length (tokens) != 3)
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ _("Line %d of the keyring at `%s' with content `%s' is malformed"),
+ n + 1,
+ path,
+ line);
+ g_strfreev (tokens);
+ goto out;
+ }
+
+ line_id = g_ascii_strtoll (tokens[0], &endp, 10);
+ if (*endp != '\0')
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ _("First token of line %d of the keyring at `%s' with content `%s' is malformed"),
+ n + 1,
+ path,
+ line);
+ g_strfreev (tokens);
+ goto out;
+ }
+
+ line_when = g_ascii_strtoll (tokens[1], &endp, 10);
+ if (*endp != '\0')
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ _("Second token of line %d of the keyring at `%s' with content `%s' is malformed"),
+ n + 1,
+ path,
+ line);
+ g_strfreev (tokens);
+ goto out;
+ }
+
+ /* D-Bus spec says:
+ *
+ * Once the lockfile has been created, the server loads the
+ * cookie file. It should then delete any cookies that are
+ * old (the timeout can be fairly short), or more than a
+ * reasonable time in the future (so that cookies never
+ * accidentally become permanent, if the clock was set far
+ * into the future at some point). If no recent keys remain,
+ * the server may generate a new key.
+ *
+ */
+ keep_entry = TRUE;
+ if (line_when > now)
+ {
+ /* Oddball case: entry is more recent than our current wall-clock time..
+ * This is OK, it means that another server on another machine but with
+ * same $HOME wrote the entry.
+ *
+ * So discard the entry if it's more than 1 day in the future ("reasonable
+ * time in the future").
+ */
+ if (line_when - now > 24*60*60)
+ {
+ keep_entry = FALSE;
+ _log ("Deleted SHA1 cookie from %" G_GUINT64_FORMAT " seconds in the future", line_when - now);
+ }
+ }
+ else
+ {
+ /* Discard entry if it's older than 15 minutes ("can be fairly short") */
+ if (now - line_when > 15*60)
+ {
+ keep_entry = FALSE;
+ }
+ }
+
+ if (!keep_entry)
+ {
+ changed_file = FALSE;
+ }
+ else
+ {
+ g_string_append_printf (new_contents,
+ "%d %" G_GUINT64_FORMAT " %s\n",
+ line_id,
+ line_when,
+ tokens[2]);
+ max_line_id = MAX (line_id, max_line_id);
+ /* Only reuse entry if not older than 10 minutes.
+ *
+ * (We need a bit of grace time compared to 15 minutes above.. otherwise
+ * there's a race where we reuse the 14min59.9 secs old entry and a
+ * split-second later another server purges the now 15 minute old entry.)
+ */
+ if (now - line_when < 10 * 60)
+ {
+ if (!have_id)
+ {
+ use_id = line_id;
+ use_cookie = tokens[2]; /* steal memory */
+ tokens[2] = NULL;
+ have_id = TRUE;
+ }
+ }
+ }
+ g_strfreev (tokens);
+ }
+ } /* for each line */
+
+ ret = TRUE;
+
+ if (have_id)
+ {
+ *out_id = use_id;
+ *out_cookie = use_cookie;
+ use_cookie = NULL;
+ }
+ else
+ {
+ gchar *raw_cookie;
+ *out_id = max_line_id + 1;
+ raw_cookie = random_blob (32);
+ *out_cookie = hexencode (raw_cookie, 32);
+ g_free (raw_cookie);
+
+ g_string_append_printf (new_contents,
+ "%d %" G_GUINT64_FORMAT " %s\n",
+ *out_id,
+ (guint64) time (NULL),
+ *out_cookie);
+ changed_file = TRUE;
+ }
+
+ /* and now actually write the cookie file if there are changes (this is atomic) */
+ if (changed_file)
+ {
+ if (!g_file_set_contents (path,
+ new_contents->str,
+ -1,
+ error))
+ {
+ *out_id = 0;
+ *out_cookie = 0;
+ g_free (*out_cookie);
+ ret = FALSE;
+ goto out;
+ }
+ }
+
+ out:
+
+ if (lock_fd != -1)
+ {
+ GError *local_error;
+ local_error = NULL;
+ if (!keyring_release_lock (path, lock_fd, &local_error))
+ {
+ if (error != NULL)
+ {
+ if (*error == NULL)
+ {
+ *error = local_error;
+ }
+ else
+ {
+ g_prefix_error (error,
+ _("(Additionally, releasing the lock for `%s' also failed: %s) "),
+ path,
+ local_error->message);
+ }
+ }
+ else
+ {
+ g_error_free (local_error);
+ }
+ }
+ }
+
+ g_free (keyring_dir);
+ g_free (path);
+ g_strfreev (lines);
+ g_free (contents);
+ if (new_contents != NULL)
+ g_string_free (new_contents, TRUE);
+ g_free (use_cookie);
+ return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gchar *
+generate_sha1 (const gchar *server_challenge,
+ const gchar *client_challenge,
+ const gchar *cookie)
+{
+ GString *str;
+ gchar *sha1;
+
+ str = g_string_new (server_challenge);
+ g_string_append_c (str, ':');
+ g_string_append (str, client_challenge);
+ g_string_append_c (str, ':');
+ g_string_append (str, cookie);
+ sha1 = g_compute_checksum_for_string (G_CHECKSUM_SHA1, str->str, -1);
+ g_string_free (str, TRUE);
+
+ return sha1;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static GDBusAuthMechanismState
+mechanism_server_get_state (GDBusAuthMechanism *mechanism)
+{
+ GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
+
+ g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), G_DBUS_AUTH_MECHANISM_STATE_INVALID);
+ g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, G_DBUS_AUTH_MECHANISM_STATE_INVALID);
+
+ return m->priv->state;
+}
+
+static void
+mechanism_server_initiate (GDBusAuthMechanism *mechanism,
+ const gchar *initial_response,
+ gsize initial_response_len)
+{
+ GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
+
+ g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism));
+ g_return_if_fail (!m->priv->is_server && !m->priv->is_client);
+
+ m->priv->is_server = TRUE;
+ m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
+
+ if (initial_response != NULL && strlen (initial_response) > 0)
+ {
+#ifdef G_OS_UNIX
+ gint64 uid;
+ gchar *endp;
+
+ uid = g_ascii_strtoll (initial_response, &endp, 10);
+ if (*endp == '\0')
+ {
+ if (uid == getuid ())
+ {
+ m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND;
+ }
+ }
+#elif defined(G_OS_WIN32)
+ GCredentials *credentials;
+ credentials = g_credentials_new_for_process ();
+ if (g_strcmp0 (g_credentials_get_windows_user (credentials), initial_response) == 0)
+ m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND;
+ g_object_unref (credentials);
+#else
+#error please implement
+#endif
+ }
+}
+
+static void
+mechanism_server_data_receive (GDBusAuthMechanism *mechanism,
+ const gchar *data,
+ gsize data_len)
+{
+ GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
+ gchar **tokens;
+ const gchar *client_challenge;
+ const gchar *alleged_sha1;
+ gchar *sha1;
+
+ g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism));
+ g_return_if_fail (m->priv->is_server && !m->priv->is_client);
+ g_return_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA);
+
+ tokens = NULL;
+ sha1 = NULL;
+
+ tokens = g_strsplit (data, " ", 0);
+ if (g_strv_length (tokens) != 2)
+ {
+ g_warning ("Malformed data `%s'", data);
+ m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
+ goto out;
+ }
+
+ client_challenge = tokens[0];
+ alleged_sha1 = tokens[1];
+
+ sha1 = generate_sha1 (m->priv->server_challenge, client_challenge, m->priv->cookie);
+
+ if (g_strcmp0 (sha1, alleged_sha1) == 0)
+ {
+ m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED;
+ }
+ else
+ {
+ m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
+ }
+
+ out:
+ g_strfreev (tokens);
+ g_free (sha1);
+}
+
+static gchar *
+mechanism_server_data_send (GDBusAuthMechanism *mechanism,
+ gsize *out_data_len)
+{
+ GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
+ gchar *s;
+ gint cookie_id;
+ const gchar *cookie_context;
+ GError *error;
+
+ g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), NULL);
+ g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, NULL);
+ g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND, NULL);
+
+ s = NULL;
+
+ /* TODO: use GDBusAuthObserver here to get the cookie context to use? */
+ cookie_context = "org_gtk_gdbus_general";
+
+ error = NULL;
+ if (!keyring_generate_entry (cookie_context,
+ &cookie_id,
+ &m->priv->cookie,
+ &error))
+ {
+ g_warning ("Error adding entry to keyring: %s", error->message);
+ g_error_free (error);
+ m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
+ goto out;
+ }
+
+ m->priv->server_challenge = random_ascii_string (16);
+ s = g_strdup_printf ("%s %d %s",
+ cookie_context,
+ cookie_id,
+ m->priv->server_challenge);
+
+ m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA;
+
+ out:
+ return s;
+}
+
+static gchar *
+mechanism_server_get_reject_reason (GDBusAuthMechanism *mechanism)
+{
+ GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
+
+ g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), NULL);
+ g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, NULL);
+ g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_REJECTED, NULL);
+
+ /* can never end up here because we are never in the REJECTED state */
+ g_assert_not_reached ();
+
+ return NULL;
+}
+
+static void
+mechanism_server_shutdown (GDBusAuthMechanism *mechanism)
+{
+ GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
+
+ g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism));
+ g_return_if_fail (m->priv->is_server && !m->priv->is_client);
+
+ m->priv->is_server = FALSE;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static GDBusAuthMechanismState
+mechanism_client_get_state (GDBusAuthMechanism *mechanism)
+{
+ GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
+
+ g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), G_DBUS_AUTH_MECHANISM_STATE_INVALID);
+ g_return_val_if_fail (m->priv->is_client && !m->priv->is_server, G_DBUS_AUTH_MECHANISM_STATE_INVALID);
+
+ return m->priv->state;
+}
+
+static gchar *
+mechanism_client_initiate (GDBusAuthMechanism *mechanism,
+ gsize *out_initial_response_len)
+{
+ GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
+ gchar *initial_response;
+
+ g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), NULL);
+ g_return_val_if_fail (!m->priv->is_server && !m->priv->is_client, NULL);
+
+ m->priv->is_client = TRUE;
+ m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA;
+
+ *out_initial_response_len = -1;
+
+#ifdef G_OS_UNIX
+ initial_response = g_strdup_printf ("%" G_GINT64_FORMAT, (gint64) getuid ());
+#elif defined (G_OS_WIN32)
+ {
+ GCredentials *credentials;
+ credentials = g_credentials_new_for_process ();
+ initial_response = g_strdup (g_credentials_get_windows_user (credentials));
+ g_object_unref (credentials);
+ }
+#else
+#endif
+ g_assert (initial_response != NULL);
+
+ return initial_response;
+}
+
+static void
+mechanism_client_data_receive (GDBusAuthMechanism *mechanism,
+ const gchar *data,
+ gsize data_len)
+{
+ GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
+ gchar **tokens;
+ const gchar *cookie_context;
+ guint cookie_id;
+ const gchar *server_challenge;
+ gchar *client_challenge;
+ gchar *endp;
+ gchar *cookie;
+ GError *error;
+ gchar *sha1;
+
+ g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism));
+ g_return_if_fail (m->priv->is_client && !m->priv->is_server);
+ g_return_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA);
+
+ tokens = NULL;
+ cookie = NULL;
+ client_challenge = NULL;
+
+ tokens = g_strsplit (data, " ", 0);
+ if (g_strv_length (tokens) != 3)
+ {
+ g_warning ("Malformed data `%s'", data);
+ m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
+ goto out;
+ }
+
+ cookie_context = tokens[0];
+ cookie_id = g_ascii_strtoll (tokens[1], &endp, 10);
+ if (*endp != '\0')
+ {
+ g_warning ("Malformed cookie_id `%s'", tokens[1]);
+ m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
+ goto out;
+ }
+ server_challenge = tokens[2];
+
+ error = NULL;
+ cookie = keyring_lookup_entry (cookie_context, cookie_id, &error);
+ if (cookie == NULL)
+ {
+ g_warning ("Problems lookup up entry in keyring: %s", error->message);
+ g_error_free (error);
+ m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
+ goto out;
+ }
+
+ client_challenge = random_ascii_string (16);
+ sha1 = generate_sha1 (server_challenge, client_challenge, cookie);
+ m->priv->to_send = g_strdup_printf ("%s %s", client_challenge, sha1);
+ g_free (sha1);
+ m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND;
+
+ out:
+ g_strfreev (tokens);
+ g_free (cookie);
+ g_free (client_challenge);
+}
+
+static gchar *
+mechanism_client_data_send (GDBusAuthMechanism *mechanism,
+ gsize *out_data_len)
+{
+ GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
+
+ g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), NULL);
+ g_return_val_if_fail (m->priv->is_client && !m->priv->is_server, NULL);
+ g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND, NULL);
+
+ g_assert (m->priv->to_send != NULL);
+
+ m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED;
+
+ return g_strdup (m->priv->to_send);
+}
+
+static void
+mechanism_client_shutdown (GDBusAuthMechanism *mechanism)
+{
+ GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
+
+ g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism));
+ g_return_if_fail (m->priv->is_client && !m->priv->is_server);
+
+ m->priv->is_client = FALSE;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
diff --git a/gdbus/gdbusauthmechanismsha1.h b/gdbus/gdbusauthmechanismsha1.h
new file mode 100644
index 0000000..7d89553
--- /dev/null
+++ b/gdbus/gdbusauthmechanismsha1.h
@@ -0,0 +1,82 @@
+/* GDBus - GLib D-Bus Library
+ *
+ * Copyright (C) 2008-2009 Red Hat, Inc.
+ *
+ * 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 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., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz@redhat.com>
+ */
+
+#if !defined (G_DBUS_COMPILATION)
+#error "gdbusauthmechanismsha1.h is a private header file."
+#endif
+
+#ifndef __G_DBUS_AUTH_MECHANISM_SHA1_H__
+#define __G_DBUS_AUTH_MECHANISM_SHA1_H__
+
+#include <gdbus/gdbustypes.h>
+#include <gdbus/gdbusauthmechanism.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_DBUS_AUTH_MECHANISM_SHA1 (_g_dbus_auth_mechanism_sha1_get_type ())
+#define G_DBUS_AUTH_MECHANISM_SHA1(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_DBUS_AUTH_MECHANISM_SHA1, GDBusAuthMechanismSha1))
+#define G_DBUS_AUTH_MECHANISM_SHA1_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_DBUS_AUTH_MECHANISM_SHA1, GDBusAuthMechanismSha1Class))
+#define G_DBUS_AUTH_MECHANISM_SHA1_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_DBUS_AUTH_MECHANISM_SHA1, GDBusAuthMechanismSha1Class))
+#define G_IS_DBUS_AUTH_MECHANISM_SHA1(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_DBUS_AUTH_MECHANISM_SHA1))
+#define G_IS_DBUS_AUTH_MECHANISM_SHA1_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_DBUS_AUTH_MECHANISM_SHA1))
+
+typedef struct _GDBusAuthMechanismSha1 GDBusAuthMechanismSha1;
+typedef struct _GDBusAuthMechanismSha1Class GDBusAuthMechanismSha1Class;
+typedef struct _GDBusAuthMechanismSha1Private GDBusAuthMechanismSha1Private;
+
+struct _GDBusAuthMechanismSha1Class
+{
+ /*< private >*/
+ GDBusAuthMechanismClass parent_class;
+
+ /*< private >*/
+ /* Padding for future expansion */
+ void (*_g_reserved1) (void);
+ void (*_g_reserved2) (void);
+ void (*_g_reserved3) (void);
+ void (*_g_reserved4) (void);
+ void (*_g_reserved5) (void);
+ void (*_g_reserved6) (void);
+ void (*_g_reserved7) (void);
+ void (*_g_reserved8) (void);
+ void (*_g_reserved9) (void);
+ void (*_g_reserved10) (void);
+ void (*_g_reserved11) (void);
+ void (*_g_reserved12) (void);
+ void (*_g_reserved13) (void);
+ void (*_g_reserved14) (void);
+ void (*_g_reserved15) (void);
+ void (*_g_reserved16) (void);
+};
+
+struct _GDBusAuthMechanismSha1
+{
+ GDBusAuthMechanism parent_instance;
+ GDBusAuthMechanismSha1Private *priv;
+};
+
+GType _g_dbus_auth_mechanism_sha1_get_type (void) G_GNUC_CONST;
+
+
+G_END_DECLS
+
+#endif /* __G_DBUS_AUTH_MECHANISM_SHA1_H__ */
diff --git a/gdbus/gdbusauthobserver.c b/gdbus/gdbusauthobserver.c
index f64a13f..47eb79c 100644
--- a/gdbus/gdbusauthobserver.c
+++ b/gdbus/gdbusauthobserver.c
@@ -137,6 +137,7 @@ g_dbus_auth_observer_class_init (GDBusAuthObserverClass *klass)
/**
* GDBusAuthObserver::deny-authenticated-peer:
+ * @observer: The #GDBusAuthObserver emitting the signal.
* @stream: A #GIOStream for the #GDBusConnection.
* @credentials: Credentials received from the peer or %NULL.
*
diff --git a/gdbus/gdbusenums.h b/gdbus/gdbusenums.h
index 0dc3cf0..11f681d 100644
--- a/gdbus/gdbusenums.h
+++ b/gdbus/gdbusenums.h
@@ -405,21 +405,6 @@ typedef enum
G_DBUS_SERVER_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS = (1<<1)
} GDBusServerFlags;
-/**
- * GCredentialType:
- *
- * A flag enumeration for different kinds of credentials.
- */
-typedef enum
-{
- G_CREDENTIAL_TYPE_NONE = 0,
- G_CREDENTIAL_TYPE_UNIX_USER = (1<<0),
- G_CREDENTIAL_TYPE_UNIX_GROUP = (1<<1),
- G_CREDENTIAL_TYPE_UNIX_PROCESS = (1<<2),
- G_CREDENTIAL_TYPE_WINDOWS_USER = (1<<3),
-} GCredentialType;
-
-
G_END_DECLS
#endif /* __G_DBUS_ENUMS_H__ */