Merge branch 'dbus-security-master' into 'master'

D-Bus auth mechanism improvements

See merge request GNOME/glib!909
This commit is contained in:
Philip Withnall 2019-06-11 10:30:45 +00:00
commit 155d4c66c7
6 changed files with 147 additions and 6 deletions

View File

@ -39,11 +39,37 @@
* signals you are interested in. Note that new signals may be added
* in the future
*
* ## Controlling Authentication # {#auth-observer}
* ## Controlling Authentication Mechanisms
*
* 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 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:
*
* |[<!-- language="C" -->
* 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
* 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:
*
* |[<!-- language="C" -->
* static gboolean

View File

@ -1539,7 +1539,7 @@ on_authorize_authenticated_peer (GDBusAuthObserver *observer,
GCredentials *credentials,
gpointer user_data)
{
gboolean authorized = TRUE;
gboolean authorized = FALSE;
if (credentials != NULL)
{
@ -1549,6 +1549,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;
}

View File

@ -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.
*

View File

@ -5750,6 +5750,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() /

View File

@ -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.
*

View File

@ -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)