diff options
author | Simon McVittie <simon.mcvittie@collabora.co.uk> | 2013-08-22 18:21:58 +0100 |
---|---|---|
committer | Simon McVittie <simon.mcvittie@collabora.co.uk> | 2013-08-22 18:21:58 +0100 |
commit | 4b63567c02022cc3a5dc2f4ef03c7bd344766b43 (patch) | |
tree | bd40c7484c520b71e4addad9824ff7f47a11561d | |
parent | 46af309cf5e3f4a0a8c773461b65a7bacb9e87e0 (diff) |
GetConnectionCredentials: add
The initial set of credentials is just UnixUserID and ProcessID.
The rest can follow when someone is sufficiently interested to actually
test them.
Bug: https://bugs.freedesktop.org/show_bug.cgi?id=54445
Reviewed-by: Ralf Habacker <ralf.habacker@freenet.de>
[rename a function that Ralf found unclear -smcv]
Signed-off-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
-rw-r--r-- | bus/driver.c | 77 | ||||
-rw-r--r-- | doc/dbus-specification.xml | 102 | ||||
-rw-r--r-- | test/dbus-daemon.c | 127 |
3 files changed, 306 insertions, 0 deletions
diff --git a/bus/driver.c b/bus/driver.c index 01e56fb9..23197e43 100644 --- a/bus/driver.c +++ b/bus/driver.c @@ -33,6 +33,7 @@ #include "stats.h" #include "utils.h" +#include <dbus/dbus-asv-util.h> #include <dbus/dbus-string.h> #include <dbus/dbus-internals.h> #include <dbus/dbus-message.h> @@ -1524,6 +1525,80 @@ bus_driver_handle_get_connection_selinux_security_context (DBusConnection *conne } static dbus_bool_t +bus_driver_handle_get_connection_credentials (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) +{ + DBusConnection *conn; + DBusMessage *reply; + DBusMessageIter reply_iter; + DBusMessageIter array_iter; + unsigned long ulong_val; + const char *service; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + reply = NULL; + + conn = bus_driver_get_conn_helper (connection, message, "credentials", + &service, error); + + if (conn == NULL) + goto failed; + + reply = _dbus_asv_new_method_return (message, &reply_iter, &array_iter); + if (reply == NULL) + goto oom; + + /* we can't represent > 32-bit pids; if your system needs them, please + * add ProcessID64 to the spec or something */ + if (dbus_connection_get_unix_process_id (conn, &ulong_val) && + ulong_val <= _DBUS_UINT32_MAX) + { + if (!_dbus_asv_add_uint32 (&array_iter, "ProcessID", ulong_val)) + goto oom; + } + + /* we can't represent > 32-bit uids; if your system needs them, please + * add UnixUserID64 to the spec or something */ + if (dbus_connection_get_unix_user (conn, &ulong_val) && + ulong_val <= _DBUS_UINT32_MAX) + { + if (!_dbus_asv_add_uint32 (&array_iter, "UnixUserID", ulong_val)) + goto oom; + } + + if (!_dbus_asv_close (&reply_iter, &array_iter)) + goto oom; + + if (! bus_transaction_send_from_driver (transaction, connection, reply)) + { + /* this time we don't want to close the iterator again, so just + * get rid of the message */ + dbus_message_unref (reply); + reply = NULL; + goto oom; + } + + return TRUE; + + oom: + BUS_SET_OOM (error); + + failed: + _DBUS_ASSERT_ERROR_IS_SET (error); + + if (reply) + { + _dbus_asv_abandon (&reply_iter, &array_iter); + dbus_message_unref (reply); + } + + return FALSE; +} + +static dbus_bool_t bus_driver_handle_reload_config (DBusConnection *connection, BusTransaction *transaction, DBusMessage *message, @@ -1703,6 +1778,8 @@ static const MessageHandler dbus_message_handlers[] = { "", DBUS_TYPE_STRING_AS_STRING, bus_driver_handle_get_id }, + { "GetConnectionCredentials", "s", "a{sv}", + bus_driver_handle_get_connection_credentials }, { NULL, NULL, NULL, NULL } }; diff --git a/doc/dbus-specification.xml b/doc/dbus-specification.xml index 324dfd43..f5d8a348 100644 --- a/doc/dbus-specification.xml +++ b/doc/dbus-specification.xml @@ -5579,6 +5579,108 @@ </para> </sect3> + <sect3 id="bus-messages-get-connection-credentials"> + <title><literal>org.freedesktop.DBus.GetConnectionCredentials</literal></title> + <para> + As a method: + <programlisting> + DICT<STRING,VARIANT> GetConnectionCredentials (in STRING bus_name) + </programlisting> + Message arguments: + <informaltable> + <tgroup cols="3"> + <thead> + <row> + <entry>Argument</entry> + <entry>Type</entry> + <entry>Description</entry> + </row> + </thead> + <tbody> + <row> + <entry>0</entry> + <entry>STRING</entry> + <entry>Unique or well-known bus name of the connection to + query, such as <literal>:12.34</literal> or + <literal>com.example.tea</literal></entry> + </row> + </tbody> + </tgroup> + </informaltable> + Reply arguments: + <informaltable> + <tgroup cols="3"> + <thead> + <row> + <entry>Argument</entry> + <entry>Type</entry> + <entry>Description</entry> + </row> + </thead> + <tbody> + <row> + <entry>0</entry> + <entry>DICT<STRING,VARIANT></entry> + <entry>Credentials</entry> + </row> + </tbody> + </tgroup> + </informaltable> + </para> + + <para> + Returns as many credentials as possible for the process connected to + the server. If unable to determine certain credentials (for instance, + because the process is not on the same machine as the bus daemon, + or because this version of the bus daemon does not support a + particular security framework), or if the values of those credentials + cannot be represented as documented here, then those credentials + are omitted. + </para> + + <para> + Keys in the returned dictionary not containing "." are defined + by this specification. Bus daemon implementors supporting + credentials frameworks not mentioned in this document should either + contribute patches to this specification, or use keys containing + "." and starting with a reversed domain name. + <informaltable> + <tgroup cols="3"> + <thead> + <row> + <entry>Key</entry> + <entry>Value type</entry> + <entry>Value</entry> + </row> + </thead> + <tbody> + <row> + <entry>UnixUserID</entry> + <entry>UINT32</entry> + <entry>The numeric Unix user ID, as defined by POSIX</entry> + </row> + <row> + <entry>ProcessID</entry> + <entry>UINT32</entry> + <entry>The numeric process ID, on platforms that have + this concept. On Unix, this is the process ID defined by + POSIX.</entry> + </row> + </tbody> + </tgroup> + </informaltable> + </para> + + <para> + This method was added in D-Bus 1.7 to reduce the round-trips + required to list a process's credentials. In older versions, calling + this method will fail: applications should recover by using the + separate methods such as + <xref linkend="bus-messages-get-connection-unix-user"/> + instead. + </para> + </sect3> + <sect3 id="bus-messages-add-match"> <title><literal>org.freedesktop.DBus.AddMatch</literal></title> <para> diff --git a/test/dbus-daemon.c b/test/dbus-daemon.c index cc871530..69b6791e 100644 --- a/test/dbus-daemon.c +++ b/test/dbus-daemon.c @@ -39,6 +39,7 @@ #else # include <signal.h> # include <unistd.h> +# include <sys/types.h> #endif typedef struct { @@ -310,6 +311,131 @@ test_echo (Fixture *f, } static void +pending_call_store_reply (DBusPendingCall *pc, + void *data) +{ + DBusMessage **message_p = data; + + *message_p = dbus_pending_call_steal_reply (pc); + g_assert (*message_p != NULL); +} + +static void +test_creds (Fixture *f, + gconstpointer context) +{ + const char *unique = dbus_bus_get_unique_name (f->left_conn); + DBusMessage *m = dbus_message_new_method_call (DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "GetConnectionCredentials"); + DBusPendingCall *pc; + DBusMessageIter args_iter; + DBusMessageIter arr_iter; + DBusMessageIter pair_iter; + DBusMessageIter var_iter; + enum { + SEEN_UNIX_USER = 1, + SEEN_PID = 2, + SEEN_WINDOWS_SID = 4 + } seen = 0; + + if (m == NULL) + g_error ("OOM"); + + if (!dbus_message_append_args (m, + DBUS_TYPE_STRING, &unique, + DBUS_TYPE_INVALID)) + g_error ("OOM"); + + if (!dbus_connection_send_with_reply (f->left_conn, m, &pc, + DBUS_TIMEOUT_USE_DEFAULT) || + pc == NULL) + g_error ("OOM"); + + dbus_message_unref (m); + m = NULL; + + if (dbus_pending_call_get_completed (pc)) + pending_call_store_reply (pc, &m); + else if (!dbus_pending_call_set_notify (pc, pending_call_store_reply, + &m, NULL)) + g_error ("OOM"); + + while (m == NULL) + g_main_context_iteration (NULL, TRUE); + + g_assert_cmpstr (dbus_message_get_signature (m), ==, "a{sv}"); + + dbus_message_iter_init (m, &args_iter); + g_assert_cmpuint (dbus_message_iter_get_arg_type (&args_iter), ==, + DBUS_TYPE_ARRAY); + g_assert_cmpuint (dbus_message_iter_get_element_type (&args_iter), ==, + DBUS_TYPE_DICT_ENTRY); + dbus_message_iter_recurse (&args_iter, &arr_iter); + + while (dbus_message_iter_get_arg_type (&arr_iter) != DBUS_TYPE_INVALID) + { + const char *name; + + dbus_message_iter_recurse (&arr_iter, &pair_iter); + g_assert_cmpuint (dbus_message_iter_get_arg_type (&pair_iter), ==, + DBUS_TYPE_STRING); + dbus_message_iter_get_basic (&pair_iter, &name); + dbus_message_iter_next (&pair_iter); + g_assert_cmpuint (dbus_message_iter_get_arg_type (&pair_iter), ==, + DBUS_TYPE_VARIANT); + dbus_message_iter_recurse (&pair_iter, &var_iter); + + if (g_strcmp0 (name, "UnixUserID") == 0) + { +#ifdef G_OS_UNIX + guint32 u32; + + g_assert (!(seen & SEEN_UNIX_USER)); + g_assert_cmpuint (dbus_message_iter_get_arg_type (&var_iter), ==, + DBUS_TYPE_UINT32); + dbus_message_iter_get_basic (&var_iter, &u32); + g_message ("%s of this process is %u", name, u32); + g_assert_cmpuint (u32, ==, geteuid ()); + seen |= SEEN_UNIX_USER; +#else + g_assert_not_reached (); +#endif + } + else if (g_strcmp0 (name, "ProcessID") == 0) + { + guint32 u32; + + g_assert (!(seen & SEEN_PID)); + g_assert_cmpuint (dbus_message_iter_get_arg_type (&var_iter), ==, + DBUS_TYPE_UINT32); + dbus_message_iter_get_basic (&var_iter, &u32); + g_message ("%s of this process is %u", name, u32); +#ifdef G_OS_UNIX + g_assert_cmpuint (u32, ==, getpid ()); +#elif defined(G_OS_WIN32) + g_assert_cmpuint (u32, ==, GetCurrentProcessId ()); +#else + g_assert_not_reached (); +#endif + seen |= SEEN_PID; + } + + dbus_message_iter_next (&arr_iter); + } + +#ifdef G_OS_UNIX + g_assert (seen & SEEN_UNIX_USER); + g_assert (seen & SEEN_PID); +#endif + +#ifdef G_OS_WIN32 + /* FIXME: when implemented: + g_assert (seen & SEEN_WINDOWS_SID); + */ +#endif +} + +static void teardown (Fixture *f, gconstpointer context G_GNUC_UNUSED) { @@ -363,6 +489,7 @@ main (int argc, g_test_add ("/echo/session", Fixture, NULL, setup, test_echo, teardown); g_test_add ("/echo/limited", Fixture, &limited_config, setup, test_echo, teardown); + g_test_add ("/creds", Fixture, NULL, setup, test_creds, teardown); return g_test_run (); } |