diff options
author | David Zeuthen <davidz@redhat.com> | 2010-05-05 12:26:00 -0400 |
---|---|---|
committer | David Zeuthen <davidz@redhat.com> | 2010-05-05 12:26:00 -0400 |
commit | 1681b4266d83ee1af726a88148e54d0e889b1600 (patch) | |
tree | d88c9adc76fb3e6967ab88035c456a5e57f68c6c | |
parent | 95098a9a064312ef19ea41b7c0dad89359982c20 (diff) |
Add SHA1 authentication mechanism
Also various changes elsewhere to make this fit.
-rw-r--r-- | docs/reference/gdbus/gdbus-docs.xml | 2 | ||||
-rw-r--r-- | docs/reference/gdbus/gdbus-standalone-sections.txt | 55 | ||||
-rw-r--r-- | docs/reference/gdbus/gdbus-standalone.types | 2 | ||||
-rw-r--r-- | gdbus/Makefile.am | 1 | ||||
-rw-r--r-- | gdbus/example-peer.c | 4 | ||||
-rw-r--r-- | gdbus/gcredentials.c | 114 | ||||
-rw-r--r-- | gdbus/gcredentials.h | 54 | ||||
-rw-r--r-- | gdbus/gdbusauth.c | 399 | ||||
-rw-r--r-- | gdbus/gdbusauthmechanism.c | 181 | ||||
-rw-r--r-- | gdbus/gdbusauthmechanism.h | 65 | ||||
-rw-r--r-- | gdbus/gdbusauthmechanismanon.c | 25 | ||||
-rw-r--r-- | gdbus/gdbusauthmechanismexternal.c | 35 | ||||
-rw-r--r-- | gdbus/gdbusauthmechanismsha1.c | 1209 | ||||
-rw-r--r-- | gdbus/gdbusauthmechanismsha1.h | 82 | ||||
-rw-r--r-- | gdbus/gdbusauthobserver.c | 1 | ||||
-rw-r--r-- | gdbus/gdbusenums.h | 15 |
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__ */ |