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>
This commit is contained in:
Simon McVittie 2013-08-22 18:21:58 +01:00
parent 46af309cf5
commit 4b63567c02
3 changed files with 306 additions and 0 deletions

View file

@ -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>
@ -1523,6 +1524,80 @@ bus_driver_handle_get_connection_selinux_security_context (DBusConnection *conne
return FALSE;
}
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,
@ -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 }
};

View file

@ -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&lt;STRING,VARIANT&gt; 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&lt;STRING,VARIANT&gt;</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>

View file

@ -39,6 +39,7 @@
#else
# include <signal.h>
# include <unistd.h>
# include <sys/types.h>
#endif
typedef struct {
@ -309,6 +310,131 @@ test_echo (Fixture *f,
count, elapsed);
}
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 ();
}