diff options
author | David Zeuthen <davidz@redhat.com> | 2010-05-04 10:53:10 -0400 |
---|---|---|
committer | David Zeuthen <davidz@redhat.com> | 2010-05-04 10:53:10 -0400 |
commit | 95098a9a064312ef19ea41b7c0dad89359982c20 (patch) | |
tree | 08baa98558ab1cbe00f800b1a86b6ee5023a6cb9 | |
parent | 114680658d61cddf2878af3d519d44131364b61e (diff) |
Add a way of dealing with credentials
-rw-r--r-- | docs/reference/gdbus/gdbus-docs.xml | 1 | ||||
-rw-r--r-- | docs/reference/gdbus/gdbus-standalone-sections.txt | 25 | ||||
-rw-r--r-- | docs/reference/gdbus/gdbus-standalone.types | 2 | ||||
-rw-r--r-- | gdbus/Makefile.am | 6 | ||||
-rw-r--r-- | gdbus/example-peer.c | 45 | ||||
-rw-r--r-- | gdbus/gcredentials.c | 409 | ||||
-rw-r--r-- | gdbus/gcredentials.h | 111 | ||||
-rw-r--r-- | gdbus/gdbus-marshal.list | 1 | ||||
-rw-r--r-- | gdbus/gdbus.h | 3 | ||||
-rw-r--r-- | gdbus/gdbusauth.c | 421 | ||||
-rw-r--r-- | gdbus/gdbusauth.h | 16 | ||||
-rw-r--r-- | gdbus/gdbusauthobserver.c | 216 | ||||
-rw-r--r-- | gdbus/gdbusauthobserver.h | 104 | ||||
-rw-r--r-- | gdbus/gdbusconnection.c | 77 | ||||
-rw-r--r-- | gdbus/gdbusconnection.h | 3 | ||||
-rw-r--r-- | gdbus/gdbusenums.h | 15 | ||||
-rw-r--r-- | gdbus/gdbusprivate.c | 7 | ||||
-rw-r--r-- | gdbus/gdbusserver.c | 146 | ||||
-rw-r--r-- | gdbus/gdbusserver.h | 20 | ||||
-rw-r--r-- | gdbus/gdbustypes.h | 5 | ||||
-rw-r--r-- | gdbus/gunixcredentialsmessage.c | 341 | ||||
-rw-r--r-- | gdbus/gunixcredentialsmessage.h | 67 | ||||
-rw-r--r-- | gdbus/tests/addresses.c | 3 | ||||
-rw-r--r-- | gdbus/tests/peer.c | 151 |
24 files changed, 2116 insertions, 79 deletions
diff --git a/docs/reference/gdbus/gdbus-docs.xml b/docs/reference/gdbus/gdbus-docs.xml index 6ab50a8..38946df 100644 --- a/docs/reference/gdbus/gdbus-docs.xml +++ b/docs/reference/gdbus/gdbus-docs.xml @@ -24,6 +24,7 @@ <xi:include href="xml/gdbusmethodinvocation.xml"/> <xi:include href="xml/gdbusproxy.xml"/> <xi:include href="xml/gdbusserver.xml"/> + <xi:include href="xml/gdbusauthobserver.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 abc04c4..7362244 100644 --- a/docs/reference/gdbus/gdbus-standalone-sections.txt +++ b/docs/reference/gdbus/gdbus-standalone-sections.txt @@ -20,12 +20,34 @@ g_dbus_is_interface_name </SECTION> <SECTION> +<FILE>gdbusauthobserver</FILE> +<TITLE>GDBusAuthObserver</TITLE> +GDBusAuthObserver +GDBusAuthObserverClass +g_dbus_auth_observer_new +g_dbus_auth_observer_deny_authenticated_peer +<SUBSECTION Standard> +G_DBUS_AUTH_OBSERVER +G_IS_DBUS_AUTH_OBSERVER +G_TYPE_DBUS_AUTH_OBSERVER +g_dbus_server_get_gtype +G_DBUS_AUTH_OBSERVER_CLASS +G_IS_DBUS_AUTH_OBSERVER_CLASS +G_DBUS_AUTH_OBSERVER_GET_CLASS +</SECTION> + +<SECTION> <FILE>gdbusserver</FILE> <TITLE>GDBusServer</TITLE> GDBusServer GDBusServerClass GDBusServerFlags g_dbus_server_new_sync +g_dbus_server_start +g_dbus_server_stop +g_dbus_server_is_active +g_dbus_server_get_guid +g_dbus_server_get_flags g_dbus_server_get_client_address <SUBSECTION Standard> G_DBUS_SERVER @@ -111,7 +133,6 @@ g_dbus_connection_new_for_address g_dbus_connection_new_for_address_finish g_dbus_connection_new_for_address_sync GDBusCapabilityFlags -g_dbus_connection_get_capabilities g_dbus_connection_close g_dbus_connection_is_closed g_dbus_connection_get_exit_on_close @@ -119,6 +140,8 @@ g_dbus_connection_set_exit_on_close g_dbus_connection_get_stream g_dbus_connection_get_guid g_dbus_connection_get_unique_name +g_dbus_connection_get_capabilities +g_dbus_connection_get_peer_credentials GDBusInvokeMethodFlags g_dbus_connection_invoke_method g_dbus_connection_invoke_method_finish diff --git a/docs/reference/gdbus/gdbus-standalone.types b/docs/reference/gdbus/gdbus-standalone.types index 4c1cc86..f372a9f 100644 --- a/docs/reference/gdbus/gdbus-standalone.types +++ b/docs/reference/gdbus/gdbus-standalone.types @@ -6,3 +6,5 @@ g_dbus_error_get_type g_dbus_proxy_get_type g_dbus_method_invocation_get_type g_dbus_server_get_type +g_dbus_auth_observer_get_type + diff --git a/gdbus/Makefile.am b/gdbus/Makefile.am index 20faee5..d9a4fac 100644 --- a/gdbus/Makefile.am +++ b/gdbus/Makefile.am @@ -35,6 +35,9 @@ gdbus_headers = \ gdbus.h \ gdbusenums.h \ gdbustypes.h \ + gdbusauthobserver.h \ + gcredentials.h \ + gunixcredentialsmessage.h \ gdbusutils.h \ gdbuserror.h \ gdbusaddress.h \ @@ -55,8 +58,11 @@ libgdbus_standalone_la_SOURCES = \ gdbusutils.h gdbusutils.c \ gdbusenumtypes.h \ gdbus-marshal.h gdbus-marshal.c \ + gcredentials.h gcredentials.c \ + gunixcredentialsmessage.h gunixcredentialsmessage.c \ gdbusenumtypes.h gdbusenumtypes.c \ gdbusaddress.h gdbusaddress.c \ + gdbusauthobserver.h gdbusauthobserver.c \ gdbusauth.h gdbusauth.c \ gdbusauthmechanism.h gdbusauthmechanism.c \ gdbusauthmechanismanon.h gdbusauthmechanismanon.c \ diff --git a/gdbus/example-peer.c b/gdbus/example-peer.c index 1a180ee..a22e742 100644 --- a/gdbus/example-peer.c +++ b/gdbus/example-peer.c @@ -53,14 +53,50 @@ static const GDBusInterfaceVTable interface_vtable = /* ---------------------------------------------------------------------------------------------------- */ +static gchar * +credentials_to_string (GCredentials *credentials) +{ + GString *s; + s = g_string_new (NULL); + if (g_credentials_has_unix_user (credentials)) + { + g_string_append_printf (s, "unix_user=%d", (gint) g_credentials_get_unix_user (credentials)); + } + if (g_credentials_has_unix_group (credentials)) + { + if (s->len > 0) + g_string_append_c (s, ','); + g_string_append_printf (s, "unix_group=%d", (gint) g_credentials_get_unix_group (credentials)); + } + if (g_credentials_has_unix_process (credentials)) + { + if (s->len > 0) + g_string_append_c (s, ','); + g_string_append_printf (s, "unix_process=%d", (gint) g_credentials_get_unix_process (credentials)); + } + return g_string_free (s, FALSE); +} + static void on_new_connection (GDBusServer *server, GDBusConnection *connection, gpointer user_data) { guint registration_id; + GCredentials *credentials; + gchar *s; + + credentials = g_dbus_connection_get_peer_credentials (connection); + if (credentials == NULL) + s = g_strdup ("(no credentials received)"); + else + s = credentials_to_string (credentials); + - g_print ("Client connected. Negotiated capabilities: unix-fd-passing=%d\n", + g_print ("Client connected.\n" + "Peer credentials: %s\n" + "Negotiated capabilities: unix-fd-passing=%d\n", + s, g_dbus_connection_get_capabilities (connection) & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING); g_object_ref (connection); @@ -144,8 +180,10 @@ main (int argc, char *argv[]) server = g_dbus_server_new_sync (opt_address, server_flags, guid, - NULL, + NULL, /* GDBusAuthObserver */ + NULL, /* GCancellable */ &error); + g_dbus_server_start (server); g_free (guid); if (server == NULL) @@ -185,7 +223,8 @@ main (int argc, char *argv[]) goto out; } - g_print ("Connected. Negotiated capabilities: unix-fd-passing=%d\n", + g_print ("Connected.\n" + "Negotiated capabilities: unix-fd-passing=%d\n", g_dbus_connection_get_capabilities (connection) & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING); greeting = g_strdup_printf ("Hey, it's %" G_GUINT64_FORMAT " already!", (guint64) time (NULL)); diff --git a/gdbus/gcredentials.c b/gdbus/gcredentials.c new file mode 100644 index 0000000..140934b --- /dev/null +++ b/gdbus/gcredentials.c @@ -0,0 +1,409 @@ +/* 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 <stdlib.h> +#include <glib/gi18n.h> +#include <gobject/gvaluecollector.h> + +#include "gcredentials.h" + +#ifdef G_OS_UNIX +#include <sys/types.h> +#include <unistd.h> +#endif + +/** + * SECTION:gcredentials + * @short_description: Credentials + * @include: gdbus/gdbus.h + * + * 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 + * #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; + gchar *windows_user; +}; + +G_DEFINE_TYPE (GCredentials, g_credentials, G_TYPE_OBJECT); + +static void +g_credentials_finalize (GObject *object) +{ + GCredentials *credentials = G_CREDENTIALS (object); + + g_free (credentials->priv->windows_user); + + if (G_OBJECT_CLASS (g_credentials_parent_class)->finalize != NULL) + G_OBJECT_CLASS (g_credentials_parent_class)->finalize (object); +} + + +static void +g_credentials_class_init (GCredentialsClass *klass) +{ + GObjectClass *gobject_class; + + g_type_class_add_private (klass, sizeof (GCredentialsPrivate)); + + gobject_class = G_OBJECT_CLASS (klass); + 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); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +/** + * g_credentials_new: + * + * Creates a new empty credentials object. + * + * Returns: A #GCredentials. Free with g_object_unref(). + */ +GCredentials * +g_credentials_new (void) +{ + return g_object_new (G_TYPE_CREDENTIALS, NULL); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +#ifdef G_OS_UNIX +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 + +/* ---------------------------------------------------------------------------------------------------- */ + +/** + * g_credentials_new_for_process: + * + * Gets the credentials for the current process. Note that the exact + * set of credentials in the returned object vary according to + * platform. + * + * Returns: A #GCredentials. Free with g_object_unref(). + */ +GCredentials * +g_credentials_new_for_process (void) +{ +#ifdef G_OS_UNIX + return g_credentials_new_for_unix_process (); +#elif G_OS_WIN32 + return g_credentials_new_for_win32_process (); +#else +#warning Please implement g_credentials_new_for_process() for your OS + return g_credentials_new (); +#endif +} + +/* ---------------------------------------------------------------------------------------------------- */ + +/** + * 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. + * + * Checks if @credentials has a UNIX user credential. + * + * Returns: %TRUE if @credentials has this type of credential, %FALSE otherwise. + */ +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); +} + +/** + * g_credentials_get_unix_user: + * @credentials: A #GCredentials. + * + * Gets the UNIX user identifier from @credentials. + * + * It is a programming error to call this method unless @credentials + * has this credential. + * + * Returns: The identifier. + */ +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). + * + * Sets the UNIX user identifier. + */ +void +g_credentials_set_unix_user (GCredentials *credentials, + gint64 user_id) +{ + g_return_if_fail (G_IS_CREDENTIALS (credentials)); + credentials->priv->unix_user = user_id; + credentials->priv->credentials |= G_CREDENTIAL_TYPE_UNIX_USER; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +/** + * g_credentials_has_unix_group: + * @credentials: A #GCredentials. + * + * Checks if @credentials has a UNIX group credential. + * + * Returns: %TRUE if @credentials has this type of credential, %FALSE otherwise. + */ +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); +} + +/** + * g_credentials_get_unix_group: + * @credentials: A #GCredentials. + * + * Gets the UNIX group identifier from @credentials. + * + * It is a programming error to call this method unless @credentials + * has this credential. + * + * Returns: The identifier. + */ +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). + * + * Sets the UNIX group identifier. + */ +void +g_credentials_set_unix_group (GCredentials *credentials, + gint64 group_id) +{ + g_return_if_fail (G_IS_CREDENTIALS (credentials)); + credentials->priv->unix_group = group_id; + credentials->priv->credentials |= G_CREDENTIAL_TYPE_UNIX_GROUP; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +/** + * g_credentials_has_unix_process: + * @credentials: A #GCredentials. + * + * Checks if @credentials has a UNIX process credential. + * + * Returns: %TRUE if @credentials has this type of credential, %FALSE otherwise. + */ +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); +} + +/** + * g_credentials_get_unix_process: + * @credentials: A #GCredentials. + * + * Gets the UNIX process identifier from @credentials. + * + * It is a programming error to call this method unless @credentials + * has this credential. + * + * Returns: The identifier. + */ +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) + * + * Sets the UNIX process identifier. + */ +void +g_credentials_set_unix_process (GCredentials *credentials, + gint64 process_id) +{ + g_return_if_fail (G_IS_CREDENTIALS (credentials)); + credentials->priv->unix_process = process_id; + credentials->priv->credentials |= G_CREDENTIAL_TYPE_UNIX_PROCESS; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +/** + * g_credentials_has_windows_user: + * @credentials: A #GCredentials. + * + * Checks if @credentials has a Windows user SID (Security Identifier). + * + * Returns: %TRUE if @credentials has this type of credential, %FALSE otherwise. + */ +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); +} + +/** + * g_credentials_get_windows_user: + * @credentials: A #GCredentials. + * + * 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. + */ +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: + * + * Sets the Windows User SID. + */ +void +g_credentials_set_windows_user (GCredentials *credentials, + const gchar *user_sid) +{ + 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 new file mode 100644 index 0000000..0ab1e6c --- /dev/null +++ b/gdbus/gcredentials.h @@ -0,0 +1,111 @@ +/* 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_G_DBUS_H_INSIDE__) && !defined (G_DBUS_COMPILATION) +#error "Only <gdbus/gdbus.h> can be included directly." +#endif + +#ifndef __G_CREDENTIALS_H__ +#define __G_CREDENTIALS_H__ + +#include <gdbus/gdbustypes.h> + +G_BEGIN_DECLS + +#define G_TYPE_CREDENTIALS (g_credentials_get_type ()) +#define G_CREDENTIALS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_CREDENTIALS, GCredentials)) +#define G_CREDENTIALS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_CREDENTIALS, GCredentialsClass)) +#define G_CREDENTIALS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_CREDENTIALS, GCredentialsClass)) +#define G_IS_CREDENTIALS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_CREDENTIALS)) +#define G_IS_CREDENTIALS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_CREDENTIALS)) + +typedef struct _GCredentialsClass GCredentialsClass; +typedef struct _GCredentialsPrivate GCredentialsPrivate; + +/** + * GCredentials: + * + * The #GCredentials structure contains only private data and + * should only be accessed using the provided API. + */ +struct _GCredentials +{ + /*< private >*/ + GObject parent_instance; + GCredentialsPrivate *priv; +}; + +/** + * GCredentialsClass: + * + * Class structure for #GCredentials. + */ +struct _GCredentialsClass +{ + /*< private >*/ + GObjectClass parent_class; + + /* 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); +}; + +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); + +G_END_DECLS + +#endif /* __G_DBUS_PROXY_H__ */ diff --git a/gdbus/gdbus-marshal.list b/gdbus/gdbus-marshal.list index d69c692..b30ad08 100644 --- a/gdbus/gdbus-marshal.list +++ b/gdbus/gdbus-marshal.list @@ -1,2 +1,3 @@ VOID:STRING,STRING,BOXED VOID:BOOL,BOXED +BOOLEAN:OBJECT,OBJECT diff --git a/gdbus/gdbus.h b/gdbus/gdbus.h index 69ee0f1..60603e0 100644 --- a/gdbus/gdbus.h +++ b/gdbus/gdbus.h @@ -39,6 +39,9 @@ #include <gdbus/gdbusintrospection.h> #include <gdbus/gdbusmethodinvocation.h> #include <gdbus/gdbusserver.h> +#include <gdbus/gcredentials.h> +#include <gdbus/gunixcredentialsmessage.h> +#include <gdbus/gdbusauthobserver.h> #undef __G_DBUS_G_DBUS_H_INSIDE__ diff --git a/gdbus/gdbusauth.c b/gdbus/gdbusauth.c index fe72066..6015b1b 100644 --- a/gdbus/gdbusauth.c +++ b/gdbus/gdbusauth.c @@ -28,9 +28,209 @@ #include "gdbusauthmechanismanon.h" #include "gdbusauthmechanismexternal.h" +#include "gdbusauthobserver.h" + #include "gdbuserror.h" #include "gdbusutils.h" #include "gdbusenumtypes.h" +#include "gcredentials.h" + +#ifdef G_OS_UNIX +#include <gio/gunixconnection.h> +#include "gunixcredentialsmessage.h" +#include <sys/types.h> +#include <sys/socket.h> +#endif + + +/* ---------------------------------------------------------------------------------------------------- */ +/* TODO: move to gio */ + +/** + * g_unix_connection_send_credentials: + * @connection: A #GUnixConnection. + * @credentials: A #GCredentials to send. + * @cancellable: A #GCancellable or %NULL. + * @error: Return location for error or %NULL. + * + * Passes the credentials stored in @credentials to the recieving side + * of the connection. The recieving end has to call + * g_unix_connection_receive_credentials() (or similar) to accept the + * credentials. + * + * The credentials which the sender specifies are checked by the + * kernel. A process with effective user ID 0 is allowed to specify + * values that do not match its own. This means that the credentials + * can be used to authenticate other connections. + * + * As well as sending the credentials this also writes a single NUL + * byte to the stream, as this is required for credentials passing to + * work on some implementations. + * + * Returns: %TRUE on success, %FALSE if @error is set. + * + * Since: 2.26 + */ +static gboolean +g_unix_connection_send_credentials (GUnixConnection *connection, + GCredentials *credentials, + GCancellable *cancellable, + GError **error) +{ + GSocketControlMessage *scm; + GSocket *socket; + gboolean ret; + GOutputVector vector; + guchar nul_byte[1] = {'\0'}; + + g_return_val_if_fail (G_IS_UNIX_CONNECTION (connection), FALSE); + g_return_val_if_fail (G_IS_CREDENTIALS (credentials), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + ret = FALSE; + + vector.buffer = &nul_byte; + vector.size = 1; + scm = g_unix_credentials_message_new_with_credentials (credentials); + g_object_get (connection, "socket", &socket, NULL); + if (g_socket_send_message (socket, + NULL, /* address */ + &vector, + 1, + &scm, + 1, + G_SOCKET_MSG_NONE, + cancellable, + error) != 1) + { + g_prefix_error (error, _("Error sending credentials: ")); + goto out; + } + + ret = TRUE; + + out: + g_object_unref (socket); + g_object_unref (scm); + return ret; +} + +/** + * g_unix_connection_receive_credentials: + * @connection: A #GUnixConnection. + * @cancellable: A #GCancellable or %NULL. + * @error: Return location for error or %NULL. + * + * Receives credentials from the sending end of the connection. The + * sending end has to call g_unix_connection_send_credentials() (or + * similar) for this to work. + * + * As well as reading the credentials this also reads (and discards) a + * single byte from the stream, as this is required for credentials + * passing to work on some implementations. + * + * Returns: Received credentials on success (free with + * g_object_unref()), %NULL if @error is set. + * + * Since: 2.26 + */ +static GCredentials * +g_unix_connection_receive_credentials (GUnixConnection *connection, + GCancellable *cancellable, + GError **error) +{ + GCredentials *ret; + GSocketControlMessage **scms; + gint nscm; + GSocket *socket; + gint n; + volatile GType credentials_message_gtype; + gssize num_bytes_read; + + g_return_val_if_fail (G_IS_UNIX_CONNECTION (connection), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + ret = NULL; + scms = NULL; + + g_object_get (connection, "socket", &socket, NULL); + +#if 1 + /* TODO: Move this to gsocket.c... */ + { + int opt_val = 1; + if (setsockopt (g_socket_get_fd (socket), + SOL_SOCKET, + SO_PASSCRED, + &opt_val, + sizeof opt_val) != 0) + { + g_warning ("boo, error setting SO_PASSCRED: %m"); + } + } +#endif + + /* ensure the type of GUnixCredentialsMessage has been registered with the type system */ + credentials_message_gtype = G_TYPE_UNIX_CREDENTIALS_MESSAGE; + num_bytes_read = g_socket_receive_message (socket, + NULL, /* GSocketAddress **address */ + NULL, + 0, + &scms, + &nscm, + NULL, + cancellable, + error); + if (num_bytes_read != 1) + { + /* Handle situation where g_socket_receive_message() returns + * 0 bytes and not setting @error + */ + if (num_bytes_read == 0 && error != NULL && *error == NULL) + { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + _("Expecting to read a single byte for receiving credentials but read zero bytes")); + } + goto out; + } + + if (nscm != 1) + { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + _("Expecting 1 control message, got %d"), + nscm); + goto out; + } + + if (!G_IS_UNIX_CREDENTIALS_MESSAGE (scms[0])) + { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + _("Unexpected type of ancillary data")); + goto out; + } + + ret = g_unix_credentials_message_get_credentials (G_UNIX_CREDENTIALS_MESSAGE (scms[0])); + g_object_ref (ret); + + out: + if (scms != NULL) + { + for (n = 0; n < nscm; n++) + g_object_unref (scms[n]); + g_free (scms); + } + g_object_unref (socket); + return ret; +} + +/* ---------------------------------------------------------------------------------------------------- */ + struct _GDBusAuthPrivate { @@ -159,6 +359,100 @@ _g_dbus_auth_new (GIOStream *stream) } /* ---------------------------------------------------------------------------------------------------- */ +/* like g_data_input_stream_read_line() but sets error if there's no content to read */ +static gchar * +_my_g_data_input_stream_read_line (GDataInputStream *dis, + gsize *out_line_length, + GCancellable *cancellable, + GError **error) +{ + gchar *ret; + + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + ret = g_data_input_stream_read_line (dis, + out_line_length, + cancellable, + error); + if (ret == NULL && error != NULL && *error == NULL) + { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + _("Unexpected lack of content trying to read a line")); + } + + return ret; +} + +/* This function is to avoid situations like this + * + * BEGIN\r\nl\0\0\1... + * + * e.g. where we read into the first D-Bus message while waiting for + * the final line from the client (TODO: file bug against gio for + * this) + */ +static gchar * +_my_g_input_stream_read_line_safe (GInputStream *i, + gsize *out_line_length, + GCancellable *cancellable, + GError **error) +{ + GString *str; + gchar c; + gssize num_read; + gboolean last_was_cr; + + str = g_string_new (NULL); + + last_was_cr = FALSE; + while (TRUE) + { + num_read = g_input_stream_read (i, + &c, + 1, + cancellable, + error); + if (num_read == -1) + goto fail; + if (num_read == 0) + { + if (error != NULL && *error == NULL) + { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + _("Unexpected lack of content trying to (safely) read a line")); + } + goto fail; + } + + g_string_append_c (str, (gint) c); + if (last_was_cr) + { + if (c == 0x0a) + { + g_assert (str->len >= 2); + g_string_set_size (str, str->len - 2); + goto out; + } + } + last_was_cr = (c == 0x0d); + } + + out: + if (out_line_length != NULL) + *out_line_length = str->len; + return g_string_free (str, FALSE); + + fail: + g_assert (error == NULL || *error != NULL); + g_string_free (str, TRUE); + return NULL; +} + +/* ---------------------------------------------------------------------------------------------------- */ static void append_nibble (GString *s, gint val) @@ -367,9 +661,30 @@ _g_dbus_auth_run_client (GDBusAuth *auth, g_data_input_stream_set_newline_type (dis, G_DATA_STREAM_NEWLINE_TYPE_CR_LF); - /* TODO: send credentials if using a unix domain socket */ +#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); + } + else + { + if (!g_data_output_stream_put_byte (dos, '\0', cancellable, error)) + goto out; + } +#else if (!g_data_output_stream_put_byte (dos, '\0', cancellable, error)) goto out; +#endif /* TODO: to reduce rountrips, try to pick an auth mechanism to start with */ @@ -383,7 +698,7 @@ _g_dbus_auth_run_client (GDBusAuth *auth, switch (state) { case CLIENT_STATE_WAITING_FOR_REJECT: - line = g_data_input_stream_read_line (dis, &line_length, cancellable, error); + line = _my_g_data_input_stream_read_line (dis, &line_length, cancellable, error); if (line == NULL) goto out; foobar: @@ -421,7 +736,7 @@ _g_dbus_auth_run_client (GDBusAuth *auth, break; case CLIENT_STATE_WAITING_FOR_OK: - line = g_data_input_stream_read_line (dis, &line_length, cancellable, error); + line = _my_g_data_input_stream_read_line (dis, &line_length, cancellable, error); if (line == NULL) goto out; if (g_str_has_prefix (line, "OK ")) @@ -471,7 +786,7 @@ _g_dbus_auth_run_client (GDBusAuth *auth, break; case CLIENT_STATE_WAITING_FOR_AGREE_UNIX_FD: - line = g_data_input_stream_read_line (dis, &line_length, cancellable, error); + line = _my_g_data_input_stream_read_line (dis, &line_length, cancellable, error); if (line == NULL) goto out; if (g_strcmp0 (line, "AGREE_UNIX_FD") == 0) @@ -584,13 +899,15 @@ typedef enum } ServerState; gboolean -_g_dbus_auth_run_server (GDBusAuth *auth, - const gchar *guid, - gboolean allow_anonymous, - GDBusCapabilityFlags offered_capabilities, - GDBusCapabilityFlags *out_negotiated_capabilities, - GCancellable *cancellable, - GError **error) +_g_dbus_auth_run_server (GDBusAuth *auth, + GDBusAuthObserver *observer, + const gchar *guid, + gboolean allow_anonymous, + GDBusCapabilityFlags offered_capabilities, + GDBusCapabilityFlags *out_negotiated_capabilities, + GCredentials **out_received_credentials, + GCancellable *cancellable, + GError **error) { gboolean ret; ServerState state; @@ -603,12 +920,14 @@ _g_dbus_auth_run_server (GDBusAuth *auth, GDBusAuthMechanism *mech; gchar *s; GDBusCapabilityFlags negotiated_capabilities; + GCredentials *credentials; ret = FALSE; dis = NULL; dos = NULL; mech = NULL; negotiated_capabilities = 0; + credentials = NULL; if (!g_dbus_is_guid (guid)) { @@ -626,6 +945,30 @@ _g_dbus_auth_run_server (GDBusAuth *auth, g_data_input_stream_set_newline_type (dis, G_DATA_STREAM_NEWLINE_TYPE_CR_LF); /* first read the NUL-byte (TODO: read credentials if using a unix domain socket) */ +#ifdef G_OS_UNIX + if (G_IS_UNIX_CONNECTION (auth->priv->stream) && g_unix_credentials_message_is_supported ()) + { + local_error = NULL; + credentials = g_unix_connection_receive_credentials (G_UNIX_CONNECTION (auth->priv->stream), + cancellable, + &local_error); + if (credentials == NULL) + { + g_propagate_error (error, local_error); + goto out; + } + } + else + { + local_error = NULL; + byte = g_data_input_stream_read_byte (dis, cancellable, &local_error); + if (local_error != NULL) + { + g_propagate_error (error, local_error); + goto out; + } + } +#else local_error = NULL; byte = g_data_input_stream_read_byte (dis, cancellable, &local_error); if (local_error != NULL) @@ -633,15 +976,7 @@ _g_dbus_auth_run_server (GDBusAuth *auth, g_propagate_error (error, local_error); goto out; } - if (byte != '\0') - { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "Expected a NUL byte, got `%c'", - byte); - goto out; - } +#endif state = SERVER_STATE_WAITING_FOR_AUTH; while (TRUE) @@ -649,7 +984,7 @@ _g_dbus_auth_run_server (GDBusAuth *auth, switch (state) { case SERVER_STATE_WAITING_FOR_AUTH: - line = g_data_input_stream_read_line (dis, &line_length, cancellable, error); + line = _my_g_data_input_stream_read_line (dis, &line_length, cancellable, error); if (line == NULL) goto out; if (g_strcmp0 (line, "AUTH") == 0) @@ -750,14 +1085,29 @@ _g_dbus_auth_run_server (GDBusAuth *auth, switch (_g_dbus_auth_mechanism_server_get_state (mech)) { case G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED: - s = g_strdup_printf ("OK %s\r\n", guid); - if (!g_data_output_stream_put_string (dos, s, cancellable, error)) + if (observer != NULL && + g_dbus_auth_observer_deny_authenticated_peer (observer, + auth->priv->stream, + credentials)) { - g_free (s); + /* disconnect */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + _("Cancelled via GDBusAuthObserver::deny-authenticated-peer")); goto out; } - g_free (s); - state = SERVER_STATE_WAITING_FOR_BEGIN; + else + { + s = g_strdup_printf ("OK %s\r\n", guid); + if (!g_data_output_stream_put_string (dos, s, cancellable, error)) + { + g_free (s); + goto out; + } + g_free (s); + state = SERVER_STATE_WAITING_FOR_BEGIN; + } break; case G_DBUS_AUTH_MECHANISM_STATE_REJECTED: @@ -791,7 +1141,7 @@ _g_dbus_auth_run_server (GDBusAuth *auth, break; case SERVER_STATE_WAITING_FOR_DATA: - line = g_data_input_stream_read_line (dis, &line_length, cancellable, error); + line = _my_g_data_input_stream_read_line (dis, &line_length, cancellable, error); if (line == NULL) goto out; g_set_error (error, @@ -803,7 +1153,17 @@ _g_dbus_auth_run_server (GDBusAuth *auth, goto out; case SERVER_STATE_WAITING_FOR_BEGIN: - line = g_data_input_stream_read_line (dis, &line_length, cancellable, error); + /* Use extremely slow (but reliable) line reader - this basically + * does a recvfrom() system call per character + * + * (the problem with using GDataInputStream's read_line is that because of + * buffering it might start reading into the first D-Bus message that + * appears after "BEGIN\r\n"....) + */ + line = _my_g_input_stream_read_line_safe (g_io_stream_get_input_stream (auth->priv->stream), + &line_length, + cancellable, + error); if (line == NULL) goto out; if (g_strcmp0 (line, "BEGIN") == 0) @@ -866,8 +1226,13 @@ _g_dbus_auth_run_server (GDBusAuth *auth, { if (out_negotiated_capabilities != NULL) *out_negotiated_capabilities = negotiated_capabilities; + if (out_received_credentials != NULL) + *out_received_credentials = credentials != NULL ? g_object_ref (credentials) : NULL; } + if (credentials != NULL) + g_object_unref (credentials); + return ret; } diff --git a/gdbus/gdbusauth.h b/gdbus/gdbusauth.h index 76493f5..ed5b516 100644 --- a/gdbus/gdbusauth.h +++ b/gdbus/gdbusauth.h @@ -65,13 +65,15 @@ GDBusAuth *_g_dbus_auth_new (GIOStream *stream); /* TODO: need to expose encode()/decode() from the AuthMechanism (and whether it is needed at all) */ -gboolean _g_dbus_auth_run_server (GDBusAuth *auth, - const gchar *guid, - gboolean allow_anonymous, - GDBusCapabilityFlags offered_capabilities, - GDBusCapabilityFlags *out_negotiated_capabilities, - GCancellable *cancellable, - GError **error); +gboolean _g_dbus_auth_run_server (GDBusAuth *auth, + GDBusAuthObserver *observer, + const gchar *guid, + gboolean allow_anonymous, + GDBusCapabilityFlags offered_capabilities, + GDBusCapabilityFlags *out_negotiated_capabilities, + GCredentials **out_received_credentials, + GCancellable *cancellable, + GError **error); gchar *_g_dbus_auth_run_client (GDBusAuth *auth, GDBusCapabilityFlags offered_capabilities, diff --git a/gdbus/gdbusauthobserver.c b/gdbus/gdbusauthobserver.c new file mode 100644 index 0000000..f64a13f --- /dev/null +++ b/gdbus/gdbusauthobserver.c @@ -0,0 +1,216 @@ +/* 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 "gdbusauthobserver.h" +#include "gdbus-marshal.h" +#include "gcredentials.h" +#include "gdbusenumtypes.h" + +/** + * SECTION:gdbusauthobserver + * @short_description: Object used for authenticating connections + * @include: gdbus/gdbus.h + * + * The #GDBusAuthObserver type provides a mechanism for participating + * in how a #GDBusServer (or a #GDBusConnection) authenticates remote + * peers. Simply instantiate a #GDBusAuthObserver and connect to the + * signals you are interested in. Note that new signals may be added + * in the future + * + * For example, if you only want to allow D-Bus connections from + * processes owned by the same uid as the server, you would do this: + * <example id="auth-observer"><title>Controlling Authentication</title><programlisting> + * static gboolean + * on_deny_authenticated_peer (GDBusAuthObserver *observer, + * GIOStream *stream, + * GCredentials *credentials, + * gpointer user_data) + * { + * gboolean deny; + * deny = TRUE; + * if (credentials != NULL && + * g_credentials_has_unix_user (credentials) && + * g_credentials_get_unix_user (credentials) == getuid ()) + * deny = FALSE; + * return deny; + * } + * + * static gboolean + * on_new_connection (GDBusServer *server, + * GDBusConnection *connection, + * gpointer user_data) + * { + * /<!-- -->* Guaranteed here that @connection is from a process owned by the same user *<!-- -->/ + * } + * + * [...] + * + * GDBusAuthObserver *observer; + * GDBusServer *server; + * GError *error; + * + * error = NULL; + * observer = g_dbus_auth_observer_new (); + * server = g_dbus_server_new_sync ("unix:tmpdir=/tmp/my-app-name", + * G_DBUS_SERVER_FLAGS_NONE, + * observer, + * NULL, /<!-- -->* GCancellable *<!-- -->/ + * &error); + * g_signal_connect (observer, + * "deny-authenticated-peer", + * G_CALLBACK (on_deny_authenticated_peer), + * NULL); + * g_signal_connect (server, + * "new-connection", + * G_CALLBACK (on_new_connection), + * NULL); + * g_object_unref (observer); + * g_dbus_server_start (server); + * </programlisting></example> + */ + +struct _GDBusAuthObserverPrivate +{ + gint foo; +}; + +enum +{ + DENY_AUTHENTICATED_PEER_SIGNAL, + LAST_SIGNAL, +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +G_DEFINE_TYPE (GDBusAuthObserver, g_dbus_auth_observer, G_TYPE_OBJECT); + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +g_dbus_auth_observer_finalize (GObject *object) +{ + //GDBusAuthObserver *observer = G_DBUS_AUTH_OBSERVER (object); + + if (G_OBJECT_CLASS (g_dbus_auth_observer_parent_class)->finalize != NULL) + G_OBJECT_CLASS (g_dbus_auth_observer_parent_class)->finalize (object); +} + +static gboolean +g_dbus_auth_observer_deny_authenticated_peer_real (GDBusAuthObserver *observer, + GIOStream *stream, + GCredentials *credentials) +{ + return FALSE; +} + +static void +g_dbus_auth_observer_class_init (GDBusAuthObserverClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = g_dbus_auth_observer_finalize; + + klass->deny_authenticated_peer = g_dbus_auth_observer_deny_authenticated_peer_real; + + /** + * GDBusAuthObserver::deny-authenticated-peer: + * @stream: A #GIOStream for the #GDBusConnection. + * @credentials: Credentials received from the peer or %NULL. + * + * Emitted to check if a peer that is successfully authenticated + * should be denied. + * + * Returns: %TRUE if the peer should be denied, %FALSE otherwise. + */ + signals[DENY_AUTHENTICATED_PEER_SIGNAL] = + g_signal_new ("deny-authenticated-peer", + G_TYPE_DBUS_AUTH_OBSERVER, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GDBusAuthObserverClass, deny_authenticated_peer), + g_signal_accumulator_true_handled, + NULL, /* accu_data */ + _gdbus_marshal_BOOLEAN__OBJECT_OBJECT, + G_TYPE_BOOLEAN, + 2, + G_TYPE_IO_STREAM, + G_TYPE_CREDENTIALS); + + + g_type_class_add_private (klass, sizeof (GDBusAuthObserverPrivate)); +} + +static void +g_dbus_auth_observer_init (GDBusAuthObserver *observer) +{ + /* not used for now */ + observer->priv = G_TYPE_INSTANCE_GET_PRIVATE (observer, + G_TYPE_DBUS_AUTH_OBSERVER, + GDBusAuthObserverPrivate);; +} + +/** + * g_dbus_auth_observer_new: + * + * Creates a new #GDBusAuthObserver object. + * + * Returns: A #GDBusAuthObserver. Free with g_object_unref(). + */ +GDBusAuthObserver * +g_dbus_auth_observer_new (void) +{ + return g_object_new (G_TYPE_DBUS_AUTH_OBSERVER, NULL); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +/** + * g_dbus_auth_observer_deny_authenticated_peer: + * @observer: A #GDBusAuthObserver. + * @stream: A #GIOStream for the #GDBusConnection. + * @credentials: Credentials received from the peer or %NULL. + * + * Emits the #GDBusAuthObserver::deny-authenticated-peer signal on @observer. + * + * Returns: %TRUE if the peer should be denied, %FALSE otherwise. + */ +gboolean +g_dbus_auth_observer_deny_authenticated_peer (GDBusAuthObserver *observer, + GIOStream *stream, + GCredentials *credentials) +{ + gboolean denied; + + denied = FALSE; + g_signal_emit (observer, + signals[DENY_AUTHENTICATED_PEER_SIGNAL], + 0, + stream, + credentials, + &denied); + return denied; +} + + diff --git a/gdbus/gdbusauthobserver.h b/gdbus/gdbusauthobserver.h new file mode 100644 index 0000000..5f7a406 --- /dev/null +++ b/gdbus/gdbusauthobserver.h @@ -0,0 +1,104 @@ +/* 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_G_DBUS_H_INSIDE__) && !defined (G_DBUS_COMPILATION) +#error "Only <gdbus/gdbus.h> can be included directly." +#endif + +#ifndef __G_DBUS_AUTH_OBSERVER_H__ +#define __G_DBUS_AUTH_OBSERVER_H__ + +#include <gdbus/gdbustypes.h> + +G_BEGIN_DECLS + +#define G_TYPE_DBUS_AUTH_OBSERVER (g_dbus_auth_observer_get_type ()) +#define G_DBUS_AUTH_OBSERVER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_DBUS_AUTH_OBSERVER, GDBusAuthObserver)) +#define G_DBUS_AUTH_OBSERVER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_DBUS_AUTH_OBSERVER, GDBusAuthObserverClass)) +#define G_DBUS_AUTH_OBSERVER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_DBUS_AUTH_OBSERVER, GDBusAuthObserverClass)) +#define G_IS_DBUS_AUTH_OBSERVER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_DBUS_AUTH_OBSERVER)) +#define G_IS_DBUS_AUTH_OBSERVER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_DBUS_AUTH_OBSERVER)) + +typedef struct _GDBusAuthObserverClass GDBusAuthObserverClass; +typedef struct _GDBusAuthObserverPrivate GDBusAuthObserverPrivate; + + +/** + * GDBusAuthObserverClass: + * @deny_authenticated_peer: Signal class handler for the #GDBusAuthObserver::deny-authenticated-peer signal. + * + * Class structure for #GDBusAuthObserverClass. + */ +struct _GDBusAuthObserverClass +{ + /*< private >*/ + GObjectClass parent_class; + + /*< public >*/ + + /* Signals */ + gboolean (*deny_authenticated_peer) (GDBusAuthObserver *observer, + GIOStream *stream, + GCredentials *credentials); + + + /*< 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); +}; + +/** + * GDBusAuthObserver: + * + * The #GDBusAuthObserver structure contains only private data and + * should only be accessed using the provided API. + */ +struct _GDBusAuthObserver +{ + GObject parent_instance; + GDBusAuthObserverPrivate *priv; +}; + +GType g_dbus_auth_observer_get_type (void) G_GNUC_CONST; +GDBusAuthObserver *g_dbus_auth_observer_new (void); +gboolean g_dbus_auth_observer_deny_authenticated_peer (GDBusAuthObserver *observer, + GIOStream *stream, + GCredentials *credentials); + +G_END_DECLS + +#endif /* _G_DBUS_AUTH_OBSERVER_H__ */ diff --git a/gdbus/gdbusconnection.c b/gdbus/gdbusconnection.c index b4a272e..bfa859f 100644 --- a/gdbus/gdbusconnection.c +++ b/gdbus/gdbusconnection.c @@ -114,6 +114,7 @@ #include "gdbusintrospection.h" #include "gdbusmethodinvocation.h" #include "gdbusprivate.h" +#include "gdbusauthobserver.h" #include "gdbus-marshal.h" /** @@ -258,6 +259,9 @@ struct _GDBusConnectionPrivate /* Capabilities negotiated during authentication */ GDBusCapabilityFlags capabilities; + + GDBusAuthObserver *authentication_observer; + GCredentials *crendentials; }; typedef struct ExportedObject ExportedObject; @@ -283,6 +287,7 @@ enum PROP_CLOSED, PROP_EXIT_ON_CLOSE, PROP_CAPABILITY_FLAGS, + PROP_AUTHENTICATION_OBSERVER, }; static void distribute_signals (GDBusConnection *connection, @@ -347,6 +352,9 @@ g_dbus_connection_finalize (GObject *object) { GDBusConnection *connection = G_DBUS_CONNECTION (object); + if (connection->priv->authentication_observer != NULL) + g_object_unref (connection->priv->authentication_observer); + if (connection->priv->auth != NULL) g_object_unref (connection->priv->auth); @@ -468,6 +476,10 @@ g_dbus_connection_set_property (GObject *object, g_dbus_connection_set_exit_on_close (connection, g_value_get_boolean (value)); break; + case PROP_AUTHENTICATION_OBSERVER: + connection->priv->authentication_observer = g_value_dup_object (value); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -657,6 +669,23 @@ g_dbus_connection_class_init (GDBusConnectionClass *klass) G_PARAM_STATIC_NICK)); /** + * GDBusConnection:authentication-observer: + * + * A #GDBusAuthObserver object to assist in the authentication process or %NULL. + */ + g_object_class_install_property (gobject_class, + PROP_AUTHENTICATION_OBSERVER, + g_param_spec_object ("authentication-observer", + _("Authentication Observer"), + _("Object used to assist in the authentication process"), + G_TYPE_DBUS_AUTH_OBSERVER, + G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_NAME | + G_PARAM_STATIC_BLURB | + G_PARAM_STATIC_NICK)); + + /** * GDBusConnection::closed: * @connection: The #GDBusConnection emitting the signal. * @remote_peer_vanished: %TRUE if @connection is closed because the @@ -1575,10 +1604,12 @@ initable_init (GInitable *initable, g_assert (connection->priv->guid != NULL); connection->priv->auth = _g_dbus_auth_new (connection->priv->stream); if (!_g_dbus_auth_run_server (connection->priv->auth, + connection->priv->authentication_observer, connection->priv->guid, (connection->priv->flags & G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS), get_offered_capabilities_max (connection), &connection->priv->capabilities, + &connection->priv->crendentials, cancellable, &connection->priv->initialization_error)) goto out; @@ -1597,6 +1628,14 @@ initable_init (GInitable *initable, goto out; } + if (connection->priv->authentication_observer != NULL) + { + g_object_unref (connection->priv->authentication_observer); + connection->priv->authentication_observer = NULL; + } + + //g_output_stream_flush (G_SOCKET_CONNECTION (connection->priv->stream) + //g_debug ("haz unix fd passing powers: %d", connection->priv->capabilities & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING); /* Hack used until @@ -1721,6 +1760,7 @@ async_initable_iface_init (GAsyncInitableIface *async_initable_iface) * @stream: A #GIOStream. * @guid: The GUID to use if a authenticating as a server or %NULL. * @flags: Flags describing how to make the connection. + * @authentication_observer: A #GDBusAuthObserver or %NULL. * @cancellable: A #GCancellable or %NULL. * @callback: A #GAsyncReadyCallback to call when the request is satisfied. * @user_data: The data to pass to @callback. @@ -1728,6 +1768,10 @@ async_initable_iface_init (GAsyncInitableIface *async_initable_iface) * Asynchronously sets up a D-Bus connection for exchanging D-Bus messages * with the end represented by @stream. * + * If %G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER is set in @flags, + * @auth_observer (if not %NULL) is used to assist in the client + * authentication process. + * * When the operation is finished, @callback will be invoked. You can * then call g_dbus_connection_new_finish() to get the result of the * operation. @@ -1740,6 +1784,7 @@ void g_dbus_connection_new (GIOStream *stream, const gchar *guid, GDBusConnectionFlags flags, + GDBusAuthObserver *authentication_observer, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) @@ -1753,6 +1798,7 @@ g_dbus_connection_new (GIOStream *stream, "stream", stream, "guid", guid, "flags", flags, + "authentication-observer", authentication_observer, NULL); } @@ -1792,12 +1838,17 @@ g_dbus_connection_new_finish (GAsyncResult *res, * @stream: A #GIOStream. * @guid: The GUID to use if a authenticating as a server or %NULL. * @flags: Flags describing how to make the connection. + * @authentication_observer: A #GDBusAuthObserver or %NULL. * @cancellable: A #GCancellable or %NULL. * @error: Return location for error or %NULL. * * Synchronously sets up a D-Bus connection for exchanging D-Bus messages * with the end represented by @stream. * + * If %G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER is set in @flags, + * @auth_observer (if not %NULL) is used to assist in the client + * authentication process. + * * This is a synchronous failable constructor. See * g_dbus_connection_new() for the asynchronous version. * @@ -1807,6 +1858,7 @@ GDBusConnection * g_dbus_connection_new_sync (GIOStream *stream, const gchar *guid, GDBusConnectionFlags flags, + GDBusAuthObserver *authentication_observer, GCancellable *cancellable, GError **error) { @@ -1818,6 +1870,7 @@ g_dbus_connection_new_sync (GIOStream *stream, "stream", stream, "guid", guid, "flags", flags, + "authentication-observer", authentication_observer, NULL); } @@ -2010,6 +2063,30 @@ g_dbus_connection_get_unique_name (GDBusConnection *connection) return connection->priv->bus_unique_name; } +/** + * g_dbus_connection_get_peer_credentials: + * @connection: A #GDBusConnection. + * + * Gets the credentials of the authenticated peer. This will always + * return %NULL unless @connection acted as a server + * (e.g. %G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER was passed) + * when set up and the client passed credentials as part of the + * authentication process. + * + * In a message bus setup, the message bus is always the server and + * each application is a client. So this method will always return + * %NULL for message bus clients. + * + * Returns: A #GCredentials or %NULL if not available. Do not free + * this object, it is owned by @connection. + */ +GCredentials * +g_dbus_connection_get_peer_credentials (GDBusConnection *connection) +{ + g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL); + return connection->priv->crendentials; +} + /* ---------------------------------------------------------------------------------------------------- */ static guint _global_filter_id = 1; diff --git a/gdbus/gdbusconnection.h b/gdbus/gdbusconnection.h index 3401bfb..2fc593f 100644 --- a/gdbus/gdbusconnection.h +++ b/gdbus/gdbusconnection.h @@ -102,6 +102,7 @@ GDBusConnection *g_bus_get_sync (GBusType bus_type, void g_dbus_connection_new (GIOStream *stream, const gchar *guid, GDBusConnectionFlags flags, + GDBusAuthObserver *auth_observer, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); @@ -110,6 +111,7 @@ GDBusConnection *g_dbus_connection_new_finish (GAsyncResult GDBusConnection *g_dbus_connection_new_sync (GIOStream *stream, const gchar *guid, GDBusConnectionFlags flags, + GDBusAuthObserver *auth_observer, GCancellable *cancellable, GError **error); @@ -132,6 +134,7 @@ void g_dbus_connection_close (GDBusConnection GIOStream *g_dbus_connection_get_stream (GDBusConnection *connection); const gchar *g_dbus_connection_get_guid (GDBusConnection *connection); const gchar *g_dbus_connection_get_unique_name (GDBusConnection *connection); +GCredentials *g_dbus_connection_get_peer_credentials (GDBusConnection *connection); gboolean g_dbus_connection_get_exit_on_close (GDBusConnection *connection); void g_dbus_connection_set_exit_on_close (GDBusConnection *connection, gboolean exit_on_close); diff --git a/gdbus/gdbusenums.h b/gdbus/gdbusenums.h index 11f681d..0dc3cf0 100644 --- a/gdbus/gdbusenums.h +++ b/gdbus/gdbusenums.h @@ -405,6 +405,21 @@ 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__ */ diff --git a/gdbus/gdbusprivate.c b/gdbus/gdbusprivate.c index 68184d8..34f3f79 100644 --- a/gdbus/gdbusprivate.c +++ b/gdbus/gdbusprivate.c @@ -30,6 +30,7 @@ #ifdef G_OS_UNIX #include <gio/gunixconnection.h> #include <gio/gunixfdmessage.h> +#include "gunixcredentialsmessage.h" #include <unistd.h> #endif @@ -93,7 +94,6 @@ _g_socket_read_with_control_messages_ready (GSocket *socket, NULL, data->cancellable, &error); - if (result >= 0) { g_simple_async_result_set_op_res_gssize (data->simple, result); @@ -408,7 +408,6 @@ _g_dbus_worker_do_read_cb (GInputStream *input_stream, bytes_read = _g_socket_read_with_control_messages_finish (worker->socket, res, &error); - if (worker->read_num_ancillary_messages > 0) { gint n; @@ -444,6 +443,10 @@ _g_dbus_worker_do_read_cb (GInputStream *input_stream, } g_free (fds); } + else if (G_IS_UNIX_CREDENTIALS_MESSAGE (control_message)) + { + /* do nothing */ + } #endif else { diff --git a/gdbus/gdbusserver.c b/gdbus/gdbusserver.c index 5acd46b..922e3c4 100644 --- a/gdbus/gdbusserver.c +++ b/gdbus/gdbusserver.c @@ -39,6 +39,7 @@ #include "gdbusenumtypes.h" #include "gdbus-marshal.h" #include "gdbusprivate.h" +#include "gdbusauthobserver.h" /** * SECTION:gdbusserver @@ -68,6 +69,10 @@ struct _GDBusServerPrivate * of the :new-connection GObject signal. */ GMainContext *main_context_at_construction; + + gboolean active; + + GDBusAuthObserver *authentication_observer; }; enum @@ -77,6 +82,8 @@ enum PROP_CLIENT_ADDRESS, PROP_FLAGS, PROP_GUID, + PROP_ACTIVE, + PROP_AUTHENTICATION_OBSERVER, }; enum @@ -98,6 +105,9 @@ g_dbus_server_finalize (GObject *object) { GDBusServer *server = G_DBUS_SERVER (object); + if (server->priv->authentication_observer != NULL) + g_object_unref (server->priv->authentication_observer); + if (server->priv->listener != NULL) g_object_unref (server->priv->listener); @@ -147,6 +157,14 @@ g_dbus_server_get_property (GObject *object, g_value_set_string (value, server->priv->client_address); break; + case PROP_ACTIVE: + g_value_set_boolean (value, server->priv->active); + break; + + case PROP_AUTHENTICATION_OBSERVER: + g_value_set_object (value, server->priv->authentication_observer); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -175,6 +193,10 @@ g_dbus_server_set_property (GObject *object, server->priv->address = g_value_dup_string (value); break; + case PROP_AUTHENTICATION_OBSERVER: + server->priv->authentication_observer = g_value_dup_object (value); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -262,21 +284,58 @@ g_dbus_server_class_init (GDBusServerClass *klass) G_PARAM_STATIC_NICK)); /** + * GDBusServer:active: + * + * Whether the server is currently active. + */ + g_object_class_install_property (gobject_class, + PROP_ACTIVE, + g_param_spec_string ("active", + _("Active"), + _("Whether the server is currently active"), + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_NAME | + G_PARAM_STATIC_BLURB | + G_PARAM_STATIC_NICK)); + + /** + * GDBusServer:authentication-observer: + * + * A #GDBusAuthObserver object to assist in the authentication process or %NULL. + */ + g_object_class_install_property (gobject_class, + PROP_AUTHENTICATION_OBSERVER, + g_param_spec_object ("authentication-observer", + _("Authentication Observer"), + _("Object used to assist in the authentication process"), + G_TYPE_DBUS_AUTH_OBSERVER, + G_PARAM_READABLE | + G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_NAME | + G_PARAM_STATIC_BLURB | + G_PARAM_STATIC_NICK)); + + /** * GDBusServer::new-connection: * @server: The #GDBusServer emitting the signal. * @connection: A #GDBusConnection for the new connection. * - * Emitted when a new authenticated connection has been made. + * Emitted when a new authenticated connection has been made. Use + * g_dbus_connection_get_peer_credentials() to figure out what + * identity (if any), was authenticated. * * If you want to accept the connection, simply ref the @connection - * object and call g_dbus_connection_close() + unref it when you are - * done with it. + * object. Then call g_dbus_connection_close() and unref it when you + * are done with it. A typical thing to do when accepting a + * connection is to listen to the #GDBusConnection::closed signal. * * If #GDBusServer:flags contains %G_DBUS_SERVER_FLAGS_RUN_IN_THREAD * then the signal is emitted in a new thread dedicated to the * connection. Otherwise the signal is emitted in the <link * linkend="g-main-context-push-thread-default">thread-default main - * loop</link> of the thread where @server was constructed in. + * loop</link> of the thread that @server was constructed in. */ _signals[NEW_CONNECTION_SIGNAL] = g_signal_new ("new-connection", G_TYPE_DBUS_SERVER, @@ -314,6 +373,7 @@ on_run (GSocketService *service, * @address: A D-Bus address. * @flags: Flags from the #GDBusServerFlags enumeration. * @guid: A D-Bus GUID. + * @observer: A #GDBusAuthObserver or %NULL. * @cancellable: A #GCancellable or %NULL. * @error: Return location for server or %NULL. * @@ -326,6 +386,9 @@ on_run (GSocketService *service, * Connect to the #GDBusServer::new-connection signal to handle * incoming connections. * + * The returned #GDBusServer isn't active - you have to start it with + * g_dbus_server_start(). + * * This is a synchronous failable constructor. See * g_dbus_server_new() for the asynchronous version. * @@ -336,6 +399,7 @@ GDBusServer * g_dbus_server_new_sync (const gchar *address, GDBusServerFlags flags, const gchar *guid, + GDBusAuthObserver *observer, GCancellable *cancellable, GError **error) { @@ -351,12 +415,12 @@ g_dbus_server_new_sync (const gchar *address, "address", address, "flags", flags, "guid", guid, + "authentication-observer", observer, NULL); if (server != NULL) { /* Right now we don't have any transport not using the listener... */ g_assert (server->priv->is_using_listener); - g_socket_service_start (G_SOCKET_SERVICE (server->priv->listener)); g_signal_connect (G_SOCKET_SERVICE (server->priv->listener), "run", G_CALLBACK (on_run), @@ -383,6 +447,77 @@ g_dbus_server_get_client_address (GDBusServer *server) return server->priv->client_address; } +/** + * g_dbus_server_get_guid: + * @server: A #GDBusServer. + * + * Gets the GUID for @server. + * + * Returns: A D-Bus GUID. Do not free this string, it is owned by @server. + */ +const gchar * +g_dbus_server_get_guid (GDBusServer *server) +{ + g_return_val_if_fail (G_IS_DBUS_SERVER (server), NULL); + return server->priv->guid; +} + +/** + * g_dbus_server_get_flags: + * @server: A #GDBusServer. + * + * Gets the flags for @server. + * + * Returns: A set of flags from the #GDBusServerFlags enumeration. + */ +GDBusServerFlags +g_dbus_server_get_flags (GDBusServer *server) +{ + g_return_val_if_fail (G_IS_DBUS_SERVER (server), G_DBUS_SERVER_FLAGS_NONE); + return server->priv->flags; +} + +/** + * g_dbus_server_is_active: + * @server: A #GDBusServer. + * + * Gets whether @server is active. + * + * Returns: %TRUE if server is active, %FALSE otherwise. + */ +gboolean +g_dbus_server_is_active (GDBusServer *server) +{ + g_return_val_if_fail (G_IS_DBUS_SERVER (server), G_DBUS_SERVER_FLAGS_NONE); + return server->priv->active; +} + +void +g_dbus_server_start (GDBusServer *server) +{ + g_return_if_fail (G_IS_DBUS_SERVER (server)); + if (server->priv->active) + return; + /* Right now we don't have any transport not using the listener... */ + g_assert (server->priv->is_using_listener); + g_socket_service_start (G_SOCKET_SERVICE (server->priv->listener)); + server->priv->active = TRUE; + g_object_notify (G_OBJECT (server), "active"); +} + +void +g_dbus_server_stop (GDBusServer *server) +{ + g_return_if_fail (G_IS_DBUS_SERVER (server)); + if (!server->priv->active) + return; + /* Right now we don't have any transport not using the listener... */ + g_assert (server->priv->is_using_listener); + g_socket_service_stop (G_SOCKET_SERVICE (server->priv->listener)); + server->priv->active = FALSE; + g_object_notify (G_OBJECT (server), "active"); +} + /* ---------------------------------------------------------------------------------------------------- */ #ifdef G_OS_UNIX @@ -738,6 +873,7 @@ on_run (GSocketService *service, connection = g_dbus_connection_new_sync (G_IO_STREAM (socket_connection), server->priv->guid, connection_flags, + server->priv->authentication_observer, NULL, /* GCancellable */ NULL); /* GError */ if (connection == NULL) diff --git a/gdbus/gdbusserver.h b/gdbus/gdbusserver.h index 18b9e26..03516a1 100644 --- a/gdbus/gdbusserver.h +++ b/gdbus/gdbusserver.h @@ -82,13 +82,19 @@ struct _GDBusServerClass void (*_g_reserved8) (void); }; -GType g_dbus_server_get_type (void) G_GNUC_CONST; -GDBusServer *g_dbus_server_new_sync (const gchar *address, - GDBusServerFlags flags, - const gchar *guid, - GCancellable *cancellable, - GError **error); -const gchar *g_dbus_server_get_client_address (GDBusServer *server); +GType g_dbus_server_get_type (void) G_GNUC_CONST; +GDBusServer *g_dbus_server_new_sync (const gchar *address, + GDBusServerFlags flags, + const gchar *guid, + GDBusAuthObserver *observer, + GCancellable *cancellable, + GError **error); +const gchar *g_dbus_server_get_client_address (GDBusServer *server); +const gchar *g_dbus_server_get_guid (GDBusServer *server); +GDBusServerFlags g_dbus_server_get_flags (GDBusServer *server); +void g_dbus_server_start (GDBusServer *server); +void g_dbus_server_stop (GDBusServer *server); +gboolean g_dbus_server_is_active (GDBusServer *server); G_END_DECLS diff --git a/gdbus/gdbustypes.h b/gdbus/gdbustypes.h index 738954f..c077500 100644 --- a/gdbus/gdbustypes.h +++ b/gdbus/gdbustypes.h @@ -31,6 +31,9 @@ G_BEGIN_DECLS +typedef struct _GCredentials GCredentials; +typedef struct _GUnixCredentialsMessage GUnixCredentialsMessage; + typedef struct _GDBusMessage GDBusMessage; typedef struct _GDBusConnection GDBusConnection; typedef struct _GMessageBusConnection GMessageBusConnection; @@ -38,6 +41,8 @@ typedef struct _GDBusProxy GDBusProxy; typedef struct _GDBusMethodInvocation GDBusMethodInvocation; typedef struct _GDBusServer GDBusServer; +typedef struct _GDBusAuthObserver GDBusAuthObserver; + typedef struct _GDBusErrorEntry GDBusErrorEntry; typedef struct _GDBusInterfaceVTable GDBusInterfaceVTable; diff --git a/gdbus/gunixcredentialsmessage.c b/gdbus/gunixcredentialsmessage.c new file mode 100644 index 0000000..6af8c29 --- /dev/null +++ b/gdbus/gunixcredentialsmessage.c @@ -0,0 +1,341 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2010 Red Hat, Inc. + * Copyright (C) 2009 Codethink Limited + * + * This program 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 licence or (at + * your option) any later version. + * + * See the included COPYING file for more information. + * + * Authors: David Zeuthen <davidz@redhat.com> + */ + +/** + * SECTION: gunixcredentialsmessage + * @title: GUnixCredentialsMessage + * @short_description: A GSocketControlMessage containing credentials + * @see_also: #GUnixConnection, #GSocketControlMessage + * + * This #GSocketControlMessage contains a #GCredentials instance. It + * may be sent using g_socket_send_message() and received using + * g_socket_receive_message() over UNIX sockets (ie: sockets in the + * %G_SOCKET_ADDRESS_UNIX family). + * + * For an easier way to send and receive credentials over + * stream-oriented UNIX sockets, see g_unix_connection_send_credentials() and + * g_unix_connection_receive_credentials(). + **/ + +#include "config.h" + +#include <glib/gi18n.h> + +/* ---------------------------------------------------------------------------------------------------- */ +#ifdef __linux__ + +#define _GNU_SOURCE +#define __USE_GNU +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#include <fcntl.h> +#define G_UNIX_CREDENTIALS_MESSAGE_SUPPORTED 1 + +#else +/* TODO: please add support for your UNIX flavor */ +#define G_UNIX_CREDENTIALS_MESSAGE_SUPPORTED 0 +#endif + +/* ---------------------------------------------------------------------------------------------------- */ + +#include <string.h> +#include <errno.h> + +#include "gunixcredentialsmessage.h" +#include "gcredentials.h" + +struct _GUnixCredentialsMessagePrivate +{ + GCredentials *credentials; +}; + +enum +{ + PROP_0, + PROP_CREDENTIALS +}; + +G_DEFINE_TYPE (GUnixCredentialsMessage, g_unix_credentials_message, G_TYPE_SOCKET_CONTROL_MESSAGE); + +static gsize +g_unix_credentials_message_get_size (GSocketControlMessage *message) +{ +#ifdef __linux__ + return sizeof (struct ucred); +#else + return 0; +#endif +} + +static int +g_unix_credentials_message_get_level (GSocketControlMessage *message) +{ + return SOL_SOCKET; +} + +static int +g_unix_credentials_message_get_msg_type (GSocketControlMessage *message) +{ +#ifdef __linux__ + return SCM_CREDENTIALS; +#else + return 0; +#endif +} + +static GSocketControlMessage * +g_unix_credentials_message_deserialize (gint level, + gint type, + gsize size, + gpointer data) +{ + GSocketControlMessage *message; + + message = NULL; + +#ifdef __linux__ + { + GCredentials *credentials; + struct ucred *ucred; + + if (level != SOL_SOCKET || type != SCM_CREDENTIALS) + goto out; + + if (size != sizeof (struct ucred)) + { + g_warning ("Expected a struct ucred (%" G_GSIZE_FORMAT " bytes) but " + "got %" G_GSIZE_FORMAT " bytes of data", + sizeof (struct ucred), + size); + goto out; + } + + ucred = data; + + credentials = g_credentials_new (); + g_credentials_set_unix_user (credentials, ucred->uid); + g_credentials_set_unix_group (credentials, ucred->gid); + g_credentials_set_unix_process (credentials, ucred->pid); + message = g_unix_credentials_message_new_with_credentials (credentials); + g_object_unref (credentials); + out: + ; + } +#endif + + return message; +} + +static void +g_unix_credentials_message_serialize (GSocketControlMessage *_message, + gpointer data) +{ + GUnixCredentialsMessage *message = G_UNIX_CREDENTIALS_MESSAGE (_message); +#ifdef __linux__ + { + struct ucred *ucred = data; + ucred->uid = g_credentials_get_unix_user (message->priv->credentials); + ucred->gid = g_credentials_get_unix_group (message->priv->credentials); + ucred->pid = g_credentials_get_unix_process (message->priv->credentials); + } +#endif +} + +static void +g_unix_credentials_message_finalize (GObject *object) +{ + GUnixCredentialsMessage *message = G_UNIX_CREDENTIALS_MESSAGE (object); + + if (message->priv->credentials != NULL) + g_object_unref (message->priv->credentials); + + if (G_OBJECT_CLASS (g_unix_credentials_message_parent_class)->finalize != NULL) + G_OBJECT_CLASS (g_unix_credentials_message_parent_class)->finalize (object); +} + +static void +g_unix_credentials_message_init (GUnixCredentialsMessage *message) +{ + message->priv = G_TYPE_INSTANCE_GET_PRIVATE (message, + G_TYPE_UNIX_CREDENTIALS_MESSAGE, + GUnixCredentialsMessagePrivate); +} + +static void +g_unix_credentials_message_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GUnixCredentialsMessage *message = G_UNIX_CREDENTIALS_MESSAGE (object); + + switch (prop_id) + { + case PROP_CREDENTIALS: + g_value_set_object (value, message->priv->credentials); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +g_unix_credentials_message_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GUnixCredentialsMessage *message = G_UNIX_CREDENTIALS_MESSAGE (object); + + switch (prop_id) + { + case PROP_CREDENTIALS: + message->priv->credentials = g_value_dup_object (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +g_unix_credentials_message_constructed (GObject *object) +{ + GUnixCredentialsMessage *message = G_UNIX_CREDENTIALS_MESSAGE (object); + + if (message->priv->credentials == NULL) + message->priv->credentials = g_credentials_new_for_process (); + + if (G_OBJECT_CLASS (g_unix_credentials_message_parent_class)->constructed != NULL) + G_OBJECT_CLASS (g_unix_credentials_message_parent_class)->constructed (object); +} + +static void +g_unix_credentials_message_class_init (GUnixCredentialsMessageClass *class) +{ + GSocketControlMessageClass *scm_class; + GObjectClass *gobject_class; + + g_type_class_add_private (class, sizeof (GUnixCredentialsMessagePrivate)); + + gobject_class = G_OBJECT_CLASS (class); + gobject_class->get_property = g_unix_credentials_message_get_property; + gobject_class->set_property = g_unix_credentials_message_set_property; + gobject_class->finalize = g_unix_credentials_message_finalize; + gobject_class->constructed = g_unix_credentials_message_constructed; + + scm_class = G_SOCKET_CONTROL_MESSAGE_CLASS (class); + scm_class->get_size = g_unix_credentials_message_get_size; + scm_class->get_level = g_unix_credentials_message_get_level; + scm_class->get_type = g_unix_credentials_message_get_msg_type; + scm_class->serialize = g_unix_credentials_message_serialize; + scm_class->deserialize = g_unix_credentials_message_deserialize; + + /** + * GUnixCredentialsMessage:credentials: + * + * The credentials stored in the message. + */ + g_object_class_install_property (gobject_class, + PROP_CREDENTIALS, + g_param_spec_object ("credentials", + _("Credentials"), + _("The credentials stored in the message"), + 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)); + +} + +/* ---------------------------------------------------------------------------------------------------- */ + +/** + * g_unix_credentials_message_is_supported: + * + * Checks if passing a #GCredential on a #GSocket is supported on this platform. + * + * Returns: %TRUE if supported, %FALSE otherwise + * + * Since: 2.26 + */ +gboolean +g_unix_credentials_message_is_supported (void) +{ + return G_UNIX_CREDENTIALS_MESSAGE_SUPPORTED; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +/** + * g_unix_credentials_message_new: + * + * Creates a new #GUnixCredentialsMessage with credentials matching the current processes. + * + * Returns: a new #GUnixCredentialsMessage + * + * Since: 2.26 + */ +GSocketControlMessage * +g_unix_credentials_message_new (void) +{ + g_return_val_if_fail (g_unix_credentials_message_is_supported (), NULL); + return g_object_new (G_TYPE_UNIX_CREDENTIALS_MESSAGE, + NULL); +} + +/** + * g_unix_credentials_message_new: + * @credentials: A #GCredentials object. + * + * Creates a new #GUnixCredentialsMessage holding @credentials. + * + * Returns: a new #GUnixCredentialsMessage + * + * Since: 2.26 + */ +GSocketControlMessage * +g_unix_credentials_message_new_with_credentials (GCredentials *credentials) +{ + g_return_val_if_fail (G_IS_CREDENTIALS (credentials), NULL); + g_return_val_if_fail (g_unix_credentials_message_is_supported (), NULL); + return g_object_new (G_TYPE_UNIX_CREDENTIALS_MESSAGE, + "credentials", credentials, + NULL); +} + +/** + * g_unix_credentials_message_get_credentials: + * @message: A #GUnixCredentialsMessage. + * + * Gets the credentials stored in @message. + * + * Returns: A #GCredentials instance. Do not free, it is owned by @message. + */ +GCredentials * +g_unix_credentials_message_get_credentials (GUnixCredentialsMessage *message) +{ + g_return_val_if_fail (G_IS_UNIX_CREDENTIALS_MESSAGE (message), NULL); + return message->priv->credentials; +} + diff --git a/gdbus/gunixcredentialsmessage.h b/gdbus/gunixcredentialsmessage.h new file mode 100644 index 0000000..f5c2d70 --- /dev/null +++ b/gdbus/gunixcredentialsmessage.h @@ -0,0 +1,67 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2010 Red Hat, Inc. + * Copyright (C) 2009 Codethink Limited + * + * This program 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 licence 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. + * + * Authors: David Zeuthen <davidz@redhat.com> + */ + +#ifndef __G_UNIX_CREDENTIALS_MESSAGE_H__ +#define __G_UNIX_CREDENTIALS_MESSAGE_H__ + +#include <gdbus/gdbustypes.h> + +G_BEGIN_DECLS + +#define G_TYPE_UNIX_CREDENTIALS_MESSAGE (g_unix_credentials_message_get_type ()) +#define G_UNIX_CREDENTIALS_MESSAGE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_UNIX_CREDENTIALS_MESSAGE, GUnixCredentialsMessage)) +#define G_UNIX_CREDENTIALS_MESSAGE_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), G_TYPE_UNIX_CREDENTIALS_MESSAGE, GUnixCredentialsMessageClass)) +#define G_IS_UNIX_CREDENTIALS_MESSAGE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_UNIX_CREDENTIALS_MESSAGE)) +#define G_IS_UNIX_CREDENTIALS_MESSAGE_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), G_TYPE_UNIX_CREDENTIALS_MESSAGE)) +#define G_UNIX_CREDENTIALS_MESSAGE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_UNIX_CREDENTIALS_MESSAGE, GUnixCredentialsMessageClass)) + +typedef struct _GUnixCredentialsMessagePrivate GUnixCredentialsMessagePrivate; +typedef struct _GUnixCredentialsMessageClass GUnixCredentialsMessageClass; + +struct _GUnixCredentialsMessageClass +{ + GSocketControlMessageClass parent_class; + + /*< private >*/ + + /* Padding for future expansion */ + void (*_g_reserved1) (void); + void (*_g_reserved2) (void); +}; + +struct _GUnixCredentialsMessage +{ + GSocketControlMessage parent_instance; + GUnixCredentialsMessagePrivate *priv; +}; + +GType g_unix_credentials_message_get_type (void) G_GNUC_CONST; +GSocketControlMessage *g_unix_credentials_message_new (void); +GSocketControlMessage *g_unix_credentials_message_new_with_credentials (GCredentials *credentials); +GCredentials *g_unix_credentials_message_get_credentials (GUnixCredentialsMessage *message); + +gboolean g_unix_credentials_message_is_supported (void); + +G_END_DECLS + +#endif /* __G_UNIX_CREDENTIALS_MESSAGE_H__ */ diff --git a/gdbus/tests/addresses.c b/gdbus/tests/addresses.c index 37cd049..ae123d9 100644 --- a/gdbus/tests/addresses.c +++ b/gdbus/tests/addresses.c @@ -54,14 +54,11 @@ test_nonce_tcp_address (void) g_assert (g_dbus_is_supported_address ("nonce-tcp:host=localhost,port=42,noncefile=/foo/bar,family=ipv6", NULL)); g_assert (g_dbus_is_supported_address ("nonce-tcp:host=localhost,port=42,noncefile=/foo/bar,family=ipv4", NULL)); - g_assert (!g_dbus_is_supported_address ("nonce-tcp:host=localhost,port=42", NULL)); g_assert (!g_dbus_is_supported_address ("nonce-tcp:host=localhost,port=42,noncefile=/foo/bar,family=blah", NULL)); g_assert (!g_dbus_is_supported_address ("nonce-tcp:host=localhost,port=420000,noncefile=/foo/bar,family=ipv4", NULL)); g_assert (!g_dbus_is_supported_address ("nonce-tcp:host=,port=x42,noncefile=/foo/bar,family=ipv4", NULL)); g_assert (!g_dbus_is_supported_address ("nonce-tcp:host=,port=42x,noncefile=/foo/bar,family=ipv4", NULL)); g_assert (!g_dbus_is_supported_address ("nonce-tcp:host=,port=420000,noncefile=/foo/bar,family=ipv4", NULL)); - g_assert (!g_dbus_is_supported_address ("nonce-tcp:port=42,noncefile=/foo/bar", NULL)); - g_assert (!g_dbus_is_supported_address ("nonce-tcp:host=localhost,noncefile=/foo/bar", NULL)); } int diff --git a/gdbus/tests/peer.c b/gdbus/tests/peer.c index 84c7f80..084d809 100644 --- a/gdbus/tests/peer.c +++ b/gdbus/tests/peer.c @@ -33,13 +33,17 @@ #include "tests.h" -static gchar *test_address = NULL; -static gchar *test_guid = NULL; -static GMainLoop *loop = NULL; +#ifdef G_OS_UNIX +static gboolean is_unix = TRUE; +#else +static gboolean is_unix = FALSE; +#endif +static gchar *test_guid = NULL; static GMainLoop *service_loop = NULL; -static GSocketService *service = NULL; +static GDBusServer *server = NULL; +static GMainLoop *loop = NULL; /* ---------------------------------------------------------------------------------------------------- */ /* Test that peer-to-peer connections work */ @@ -249,6 +253,107 @@ on_proxy_signal_received (GDBusProxy *proxy, /* ---------------------------------------------------------------------------------------------------- */ static gboolean +on_deny_authenticated_peer (GDBusAuthObserver *observer, + GIOStream *stream, + GCredentials *credentials, + gpointer user_data) +{ + PeerData *data = user_data; + gboolean deny_peer; + + data->num_connection_attempts++; + + deny_peer = FALSE; + if (!data->accept_connection) + { + deny_peer = TRUE; + g_main_loop_quit (loop); + } + + return deny_peer; +} + +/* Runs in thread we created GDBusServer in (since we didn't pass G_DBUS_SERVER_FLAGS_RUN_IN_THREAD) */ +static void +on_new_connection (GDBusServer *server, + GDBusConnection *connection, + gpointer user_data) +{ + PeerData *data = user_data; + GError *error; + guint reg_id; + + //g_print ("Client connected.\n" + // "Negotiated capabilities: unix-fd-passing=%d\n", + // g_dbus_connection_get_capabilities (connection) & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING); + + g_ptr_array_add (data->current_connections, g_object_ref (connection)); + + /* export object on the newly established connection */ + error = NULL; + reg_id = g_dbus_connection_register_object (connection, + "/org/gtk/GDBus/PeerTestObject", + "org.gtk.GDBus.PeerTestInterface", + &test_interface_introspection_data, + &test_interface_vtable, + data, + NULL, /* GDestroyNotify for data */ + &error); + g_assert_no_error (error); + g_assert (reg_id > 0); + + g_main_loop_quit (loop); +} + +static gpointer +service_thread_func (gpointer user_data) +{ + PeerData *data = user_data; + GMainContext *service_context; + GDBusAuthObserver *observer; + GError *error; + + service_context = g_main_context_new (); + g_main_context_push_thread_default (service_context); + + error = NULL; + observer = g_dbus_auth_observer_new (); + server = g_dbus_server_new_sync (is_unix ? "unix:tmpdir=/tmp/gdbus-test-" : "nonce-tcp:", + G_DBUS_SERVER_FLAGS_NONE, + test_guid, + observer, + NULL, /* cancellable */ + &error); + g_assert_no_error (error); + + g_signal_connect (server, + "new-connection", + G_CALLBACK (on_new_connection), + data); + g_signal_connect (observer, + "deny-authenticated-peer", + G_CALLBACK (on_deny_authenticated_peer), + data); + g_object_unref (observer); + + g_dbus_server_start (server); + + service_loop = g_main_loop_new (service_context, FALSE); + g_main_loop_run (service_loop); + + g_main_context_pop_thread_default (service_context); + + g_main_loop_unref (service_loop); + g_main_context_unref (service_context); + + /* test code specifically unrefs the server - see below */ + g_assert (server == NULL); + + return NULL; +} + +#if 0 +static gboolean on_incoming_connection (GSocketService *service, GSocketConnection *socket_connection, GObject *source_object, @@ -341,6 +446,7 @@ service_thread_func (gpointer data) g_free (socket_path); return NULL; } +#endif /* ---------------------------------------------------------------------------------------------------- */ @@ -404,7 +510,6 @@ on_do_disconnect_in_idle (gpointer data) static void test_peer (void) { - gchar *dbus_address; GDBusConnection *c; GDBusConnection *c2; GDBusProxy *proxy; @@ -415,43 +520,43 @@ test_peer (void) const gchar *s; GThread *service_thread; - dbus_address = g_strdup_printf ("unix:path=/tmp/gdbus-test-pid-%d", getpid ()); - memset (&data, '\0', sizeof (PeerData)); data.current_connections = g_ptr_array_new_with_free_func (g_object_unref); /* first try to connect when there is no server */ error = NULL; - c = g_dbus_connection_new_for_address_sync (dbus_address, + c = g_dbus_connection_new_for_address_sync (is_unix ? "unix:path=/tmp/gdbus-test-does-not-exist-pid" : + /* NOTE: Even if something is listening on port 12345 the connection + * will fail because the nonce file doesn't exist */ + "nonce-tcp:host=localhost,port=12345,noncefile=this-does-not-exist-gdbus", G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT, NULL, /* cancellable */ &error); - g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND); + _g_assert_error_domain (error, G_IO_ERROR); g_assert (!g_dbus_error_is_remote_error (error)); g_clear_error (&error); g_assert (c == NULL); - /* bring up a server - need this running in a different thread to avoid deadlocks */ - service_loop = NULL; + /* bring up a server - we run the server in a different thread to avoid deadlocks */ error = NULL; service_thread = g_thread_create (service_thread_func, &data, TRUE, &error); - g_assert_no_error (error); while (service_loop == NULL) g_thread_yield (); + g_assert (server != NULL); /* bring up a connection and accept it */ data.accept_connection = TRUE; error = NULL; - c = g_dbus_connection_new_for_address_sync (dbus_address, + c = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (server), G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT, NULL, /* cancellable */ &error); g_assert_no_error (error); g_assert (c != NULL); - while (data.num_connection_attempts < 1) + while (data.current_connections->len < 1) g_main_loop_run (loop); g_assert_cmpint (data.current_connections->len, ==, 1); g_assert_cmpint (data.num_connection_attempts, ==, 1); @@ -566,11 +671,11 @@ test_peer (void) #endif /* G_OS_UNIX */ - /* bring up a connection - don't accept it - this should fail. + /* bring up a connection - don't accept it - this should fail */ data.accept_connection = FALSE; error = NULL; - c2 = g_dbus_connection_new_for_address_sync (dbus_address, + c2 = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (server), G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT, NULL, /* cancellable */ &error); @@ -585,7 +690,7 @@ test_peer (void) */ error = NULL; data.accept_connection = TRUE; - c2 = g_dbus_connection_new_for_address_sync (dbus_address, + c2 = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (server), G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT, NULL, /* cancellable */ &error); @@ -617,8 +722,11 @@ test_peer (void) * This won't bring down the established connections - check that c is still connected * by invoking a method */ - g_socket_service_stop (service); - g_object_unref (service); + //g_socket_service_stop (service); + //g_object_unref (service); + g_dbus_server_stop (server); + g_object_unref (server); + server = NULL; error = NULL; result = g_dbus_proxy_invoke_method_sync (proxy, @@ -648,7 +756,6 @@ test_peer (void) g_object_unref (c); g_ptr_array_unref (data.current_connections); - g_free (dbus_address); g_object_unref (proxy); g_main_loop_quit (service_loop); @@ -667,8 +774,6 @@ main (int argc, g_thread_init (NULL); g_test_init (&argc, &argv, NULL); - - test_address = g_strdup_printf ("unix:path=/tmp/gdbus-test-pid-%d", getpid ()); test_guid = g_dbus_generate_guid (); /* all the tests rely on a shared main loop */ @@ -678,8 +783,8 @@ main (int argc, ret = g_test_run(); - g_free (test_address); g_main_loop_unref (loop); + g_free (test_guid); return ret; } |