Merge branch 'dbus-security-glib-2-60' into 'glib-2-60'

Backport !909 “D-Bus auth mechanism improvements” to glib-2-60

See merge request GNOME/glib!910
This commit is contained in:
Philip Withnall 2019-06-11 10:21:46 +00:00
commit 23a6173e4e
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 * signals you are interested in. Note that new signals may be added
* in the future * in the future
* *
* ## Controlling Authentication # {#auth-observer} * ## Controlling Authentication Mechanisms
* *
* For example, if you only want to allow D-Bus connections from * By default, a #GDBusServer or server-side #GDBusConnection will allow
* processes owned by the same uid as the server, you would use a * any authentication mechanism to be used. If you only
* signal handler like the following: * 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" --> * |[<!-- language="C" -->
* static gboolean * static gboolean

View File

@ -1534,7 +1534,7 @@ on_authorize_authenticated_peer (GDBusAuthObserver *observer,
GCredentials *credentials, GCredentials *credentials,
gpointer user_data) gpointer user_data)
{ {
gboolean authorized = TRUE; gboolean authorized = FALSE;
if (credentials != NULL) if (credentials != NULL)
{ {
@ -1544,6 +1544,14 @@ on_authorize_authenticated_peer (GDBusAuthObserver *observer,
authorized = g_credentials_is_same_user (credentials, own_credentials, NULL); authorized = g_credentials_is_same_user (credentials, own_credentials, NULL);
g_object_unref (own_credentials); 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; return authorized;
} }

View File

@ -72,6 +72,11 @@
* *
* An example of peer-to-peer communication with G-DBus can be found * 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). * 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 * Once constructed, you can use g_dbus_server_get_client_address() to
* get a D-Bus address string that clients can use to connect. * 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 * Connect to the #GDBusServer::new-connection signal to handle
* incoming connections. * incoming connections.
* *

View File

@ -5748,6 +5748,13 @@ g_socket_receive_message (GSocket *socket,
* the %G_IO_ERROR_NOT_SUPPORTED error. On Linux this is implemented * the %G_IO_ERROR_NOT_SUPPORTED error. On Linux this is implemented
* by reading the %SO_PEERCRED option on the underlying socket. * 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 * Other ways to obtain credentials from a foreign peer includes the
* #GUnixCredentialsMessage type and * #GUnixCredentialsMessage type and
* g_unix_connection_send_credentials() / * 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 * byte to the stream, as this is required for credentials passing to
* work on some implementations. * 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 * Other ways to exchange credentials with a foreign peer includes the
* #GUnixCredentialsMessage type and g_socket_get_credentials() function. * #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 * single byte from the stream, as this is required for credentials
* passing to work on some implementations. * 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 * Other ways to exchange credentials with a foreign peer includes the
* #GUnixCredentialsMessage type and g_socket_get_credentials() function. * #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 int
main (int argc, char *argv[]) main (int argc, char *argv[])
{ {
@ -221,6 +289,7 @@ main (int argc, char *argv[])
if (opt_server) if (opt_server)
{ {
GDBusAuthObserver *observer;
GDBusServer *server; GDBusServer *server;
gchar *guid; gchar *guid;
GMainLoop *loop; GMainLoop *loop;
@ -232,14 +301,20 @@ main (int argc, char *argv[])
if (opt_allow_anonymous) if (opt_allow_anonymous)
server_flags |= G_DBUS_SERVER_FLAGS_AUTHENTICATION_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; error = NULL;
server = g_dbus_server_new_sync (opt_address, server = g_dbus_server_new_sync (opt_address,
server_flags, server_flags,
guid, guid,
NULL, /* GDBusAuthObserver */ observer,
NULL, /* GCancellable */ NULL, /* GCancellable */
&error); &error);
g_dbus_server_start (server); g_dbus_server_start (server);
g_object_unref (observer);
g_free (guid); g_free (guid);
if (server == NULL) if (server == NULL)