From b6988b685f916b22e5d58df7fb9fb8f3b9f4737f Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Wed, 5 Jun 2019 10:51:30 +0100 Subject: [PATCH 1/6] Document where we expect credentials-passing to be supported This is useful information for implementors of portable software to know whether they can rely on credentials-passing. Signed-off-by: Simon McVittie --- gio/gsocket.c | 7 +++++++ gio/gunixconnection.c | 16 ++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/gio/gsocket.c b/gio/gsocket.c index d4372c544..fe869f5fb 100644 --- a/gio/gsocket.c +++ b/gio/gsocket.c @@ -5748,6 +5748,13 @@ g_socket_receive_message (GSocket *socket, * the %G_IO_ERROR_NOT_SUPPORTED error. On Linux this is implemented * by reading the %SO_PEERCRED option on the underlying socket. * + * This method can be expected to be available on the following platforms: + * + * - Linux since GLib 2.26 + * - OpenBSD since GLib 2.30 + * - Solaris, Illumos and OpenSolaris since GLib 2.40 + * - NetBSD since GLib 2.42 + * * Other ways to obtain credentials from a foreign peer includes the * #GUnixCredentialsMessage type and * g_unix_connection_send_credentials() / diff --git a/gio/gunixconnection.c b/gio/gunixconnection.c index c85ac3650..e9e2f75f0 100644 --- a/gio/gunixconnection.c +++ b/gio/gunixconnection.c @@ -300,6 +300,14 @@ gboolean g_unix_connection_create_pair (GUnixCo * byte to the stream, as this is required for credentials passing to * work on some implementations. * + * This method can be expected to be available on the following platforms: + * + * - Linux since GLib 2.26 + * - FreeBSD since GLib 2.26 + * - GNU/kFreeBSD since GLib 2.36 + * - Solaris, Illumos and OpenSolaris since GLib 2.40 + * - GNU/Hurd since GLib 2.40 + * * Other ways to exchange credentials with a foreign peer includes the * #GUnixCredentialsMessage type and g_socket_get_credentials() function. * @@ -450,6 +458,14 @@ g_unix_connection_send_credentials_finish (GUnixConnection *connection, * single byte from the stream, as this is required for credentials * passing to work on some implementations. * + * This method can be expected to be available on the following platforms: + * + * - Linux since GLib 2.26 + * - FreeBSD since GLib 2.26 + * - GNU/kFreeBSD since GLib 2.36 + * - Solaris, Illumos and OpenSolaris since GLib 2.40 + * - GNU/Hurd since GLib 2.40 + * * Other ways to exchange credentials with a foreign peer includes the * #GUnixCredentialsMessage type and g_socket_get_credentials() function. * From 1031e466cfb40e9144008350b2d7ee8932c1490b Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Wed, 5 Jun 2019 13:44:10 +0100 Subject: [PATCH 2/6] GDBusServer: Document that a GDBusAuthObserver is usually desirable Signed-off-by: Simon McVittie --- gio/gdbusauthobserver.c | 8 +++++--- gio/gdbusserver.c | 9 +++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/gio/gdbusauthobserver.c b/gio/gdbusauthobserver.c index 34758aa20..e89ff0e2e 100644 --- a/gio/gdbusauthobserver.c +++ b/gio/gdbusauthobserver.c @@ -41,9 +41,11 @@ * * ## Controlling Authentication # {#auth-observer} * - * For example, if you only want to allow D-Bus connections from - * processes owned by the same uid as the server, you would use a - * signal handler like the following: + * By default, a #GDBusServer or server-side #GDBusConnection will accept + * connections from any successfully authenticated user (but not from + * anonymous connections using the `ANONYMOUS` mechanism). If you only + * want to allow D-Bus connections from processes owned by the same uid + * as the server, you would use a signal handler like the following: * * |[ * static gboolean diff --git a/gio/gdbusserver.c b/gio/gdbusserver.c index 07757f40f..eb641a9bc 100644 --- a/gio/gdbusserver.c +++ b/gio/gdbusserver.c @@ -72,6 +72,11 @@ * * An example of peer-to-peer communication with G-DBus can be found * in [gdbus-example-peer.c](https://git.gnome.org/browse/glib/tree/gio/tests/gdbus-example-peer.c). + * + * Note that a minimal #GDBusServer will accept connections from any + * peer. In many use-cases it will be necessary to add a #GDBusAuthObserver + * that only accepts connections that have successfully authenticated + * as the same user that is running the #GDBusServer. */ /** @@ -457,6 +462,10 @@ on_run (GSocketService *service, * Once constructed, you can use g_dbus_server_get_client_address() to * get a D-Bus address string that clients can use to connect. * + * To have control over the available authentication mechanisms and + * the users that are authorized to connect, it is strongly recommended + * to provide a non-%NULL #GDBusAuthObserver. + * * Connect to the #GDBusServer::new-connection signal to handle * incoming connections. * From 6964a2a2556ff621e77b4a5e9a1c8b87f89aee4d Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Wed, 5 Jun 2019 13:47:09 +0100 Subject: [PATCH 3/6] GDBusAuthObserver: Fix mixup between authentication and authorization Authentication is about proving who I am; authorization is about whether, given the knowledge of who I am, I am allowed to do something. GDBusServer and GDBusConnection carry out authentication automatically, but rely on the library user to carry out authorization. Signed-off-by: Simon McVittie --- gio/gdbusauthobserver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gio/gdbusauthobserver.c b/gio/gdbusauthobserver.c index e89ff0e2e..2cf995f0c 100644 --- a/gio/gdbusauthobserver.c +++ b/gio/gdbusauthobserver.c @@ -39,7 +39,7 @@ * signals you are interested in. Note that new signals may be added * in the future * - * ## Controlling Authentication # {#auth-observer} + * ## Controlling Authorization # {#auth-observer} * * By default, a #GDBusServer or server-side #GDBusConnection will accept * connections from any successfully authenticated user (but not from From 27e4e387cce1766e9ba3dbf27d7e7f631e45d3a0 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Wed, 5 Jun 2019 13:48:13 +0100 Subject: [PATCH 4/6] GDBusAuthObserver: Document how to restrict authentication to EXTERNAL This is simpler and more robust than DBUS_COOKIE_SHA1, which relies on assumptions about random numbers and a secure home directory. Signed-off-by: Simon McVittie --- gio/gdbusauthobserver.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/gio/gdbusauthobserver.c b/gio/gdbusauthobserver.c index 2cf995f0c..4590ffcae 100644 --- a/gio/gdbusauthobserver.c +++ b/gio/gdbusauthobserver.c @@ -39,6 +39,30 @@ * signals you are interested in. Note that new signals may be added * in the future * + * ## Controlling Authentication Mechanisms + * + * By default, a #GDBusServer or server-side #GDBusConnection will allow + * any authentication mechanism to be used. If you only + * want to allow D-Bus connections with the `EXTERNAL` mechanism, + * which makes use of credentials passing and is the recommended + * mechanism for modern Unix platforms such as Linux and the BSD family, + * you would use a signal handler like this: + * + * |[ + * static gboolean + * on_allow_mechanism (GDBusAuthObserver *observer, + * const gchar *mechanism, + * gpointer user_data) + * { + * if (g_strcmp0 (mechanism, "EXTERNAL") == 0) + * { + * return TRUE; + * } + * + * return FALSE; + * } + * ]| + * * ## Controlling Authorization # {#auth-observer} * * By default, a #GDBusServer or server-side #GDBusConnection will accept From d2ae55fafad634ad577b25a03d5aaa8d7881a919 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Wed, 5 Jun 2019 13:53:25 +0100 Subject: [PATCH 5/6] gdbus-example-peer: Provide an example GDBusAuthObserver It's somewhat unrealistic to use a GDBusServer without a GDBusAuthObserver, because most D-Bus servers want to be like the standard session bus (the owning user can connect) rather than being like the standard system bus (all users can connect, the server is a security boundary, and many bugs are security vulnerabilities). Signed-off-by: Simon McVittie --- gio/tests/gdbus-example-peer.c | 77 +++++++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/gio/tests/gdbus-example-peer.c b/gio/tests/gdbus-example-peer.c index bf151cfcf..9d5de32a6 100755 --- a/gio/tests/gdbus-example-peer.c +++ b/gio/tests/gdbus-example-peer.c @@ -169,6 +169,74 @@ on_new_connection (GDBusServer *server, /* ---------------------------------------------------------------------------------------------------- */ +static gboolean +allow_mechanism_cb (GDBusAuthObserver *observer, + const gchar *mechanism, + G_GNUC_UNUSED gpointer user_data) +{ + /* + * In a production GDBusServer that only needs to work on modern Unix + * platforms, consider requiring EXTERNAL (credentials-passing), + * which is the recommended authentication mechanism for AF_UNIX + * sockets: + * + * if (g_strcmp0 (mechanism, "EXTERNAL") == 0) + * return TRUE; + * + * return FALSE; + * + * For this example we accept everything. + */ + + g_print ("Considering whether to accept %s authentication...\n", mechanism); + return TRUE; +} + +static gboolean +authorize_authenticated_peer_cb (GDBusAuthObserver *observer, + G_GNUC_UNUSED GIOStream *stream, + GCredentials *credentials, + G_GNUC_UNUSED gpointer user_data) +{ + gboolean authorized = FALSE; + + g_print ("Considering whether to authorize authenticated peer...\n"); + + if (credentials != NULL) + { + GCredentials *own_credentials; + gchar *credentials_string = NULL; + + credentials_string = g_credentials_to_string (credentials); + g_print ("Peer's credentials: %s\n", credentials_string); + g_free (credentials_string); + + own_credentials = g_credentials_new (); + + credentials_string = g_credentials_to_string (own_credentials); + g_print ("Server's credentials: %s\n", credentials_string); + g_free (credentials_string); + + if (g_credentials_is_same_user (credentials, own_credentials, NULL)) + authorized = TRUE; + + g_object_unref (own_credentials); + } + + if (!authorized) + { + /* In most servers you'd want to reject this, but for this example + * we allow it. */ + g_print ("A server would often not want to authorize this identity\n"); + g_print ("Authorizing it anyway for demonstration purposes\n"); + authorized = TRUE; + } + + return authorized; +} + +/* ---------------------------------------------------------------------------------------------------- */ + int main (int argc, char *argv[]) { @@ -221,6 +289,7 @@ main (int argc, char *argv[]) if (opt_server) { + GDBusAuthObserver *observer; GDBusServer *server; gchar *guid; GMainLoop *loop; @@ -232,14 +301,20 @@ main (int argc, char *argv[]) if (opt_allow_anonymous) server_flags |= G_DBUS_SERVER_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS; + observer = g_dbus_auth_observer_new (); + g_signal_connect (observer, "allow-mechanism", G_CALLBACK (allow_mechanism_cb), NULL); + g_signal_connect (observer, "authorize-authenticated-peer", G_CALLBACK (authorize_authenticated_peer_cb), NULL); + error = NULL; server = g_dbus_server_new_sync (opt_address, server_flags, guid, - NULL, /* GDBusAuthObserver */ + observer, NULL, /* GCancellable */ &error); g_dbus_server_start (server); + + g_object_unref (observer); g_free (guid); if (server == NULL) From 85c1ec0827751c1600d8eb419cb1947b56c7eb11 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Wed, 5 Jun 2019 15:00:29 +0100 Subject: [PATCH 6/6] gdbusdaemon: Only authorize anonymous users on Windows, not Unix On Unix, we expect EXTERNAL authentication to work. Signed-off-by: Simon McVittie --- gio/gdbusdaemon.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/gio/gdbusdaemon.c b/gio/gdbusdaemon.c index e6b3c1af0..d893b930a 100644 --- a/gio/gdbusdaemon.c +++ b/gio/gdbusdaemon.c @@ -1534,7 +1534,7 @@ on_authorize_authenticated_peer (GDBusAuthObserver *observer, GCredentials *credentials, gpointer user_data) { - gboolean authorized = TRUE; + gboolean authorized = FALSE; if (credentials != NULL) { @@ -1544,6 +1544,14 @@ on_authorize_authenticated_peer (GDBusAuthObserver *observer, authorized = g_credentials_is_same_user (credentials, own_credentials, NULL); g_object_unref (own_credentials); } +#ifdef G_OS_WIN32 + else + { + /* We allow ANONYMOUS authentication on Windows for now, in + * combination with the nonce-tcp transport. */ + authorized = TRUE; + } +#endif return authorized; }