summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Zeuthen <davidz@redhat.com>2010-05-04 10:53:10 -0400
committerDavid Zeuthen <davidz@redhat.com>2010-05-04 10:53:10 -0400
commit95098a9a064312ef19ea41b7c0dad89359982c20 (patch)
tree08baa98558ab1cbe00f800b1a86b6ee5023a6cb9
parent114680658d61cddf2878af3d519d44131364b61e (diff)
Add a way of dealing with credentials
-rw-r--r--docs/reference/gdbus/gdbus-docs.xml1
-rw-r--r--docs/reference/gdbus/gdbus-standalone-sections.txt25
-rw-r--r--docs/reference/gdbus/gdbus-standalone.types2
-rw-r--r--gdbus/Makefile.am6
-rw-r--r--gdbus/example-peer.c45
-rw-r--r--gdbus/gcredentials.c409
-rw-r--r--gdbus/gcredentials.h111
-rw-r--r--gdbus/gdbus-marshal.list1
-rw-r--r--gdbus/gdbus.h3
-rw-r--r--gdbus/gdbusauth.c421
-rw-r--r--gdbus/gdbusauth.h16
-rw-r--r--gdbus/gdbusauthobserver.c216
-rw-r--r--gdbus/gdbusauthobserver.h104
-rw-r--r--gdbus/gdbusconnection.c77
-rw-r--r--gdbus/gdbusconnection.h3
-rw-r--r--gdbus/gdbusenums.h15
-rw-r--r--gdbus/gdbusprivate.c7
-rw-r--r--gdbus/gdbusserver.c146
-rw-r--r--gdbus/gdbusserver.h20
-rw-r--r--gdbus/gdbustypes.h5
-rw-r--r--gdbus/gunixcredentialsmessage.c341
-rw-r--r--gdbus/gunixcredentialsmessage.h67
-rw-r--r--gdbus/tests/addresses.c3
-rw-r--r--gdbus/tests/peer.c151
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;
}