From cc37dc857fcd7a5afb57ba6e7c2002acc73a0b5d Mon Sep 17 00:00:00 2001 From: "Jan Alexander Steffens (heftig)" Date: Sat, 14 Nov 2015 16:32:43 +0100 Subject: [PATCH] bus-driver: Support returning org.freedesktop.DBus UID and PID Attempting to call SetEnvironment on systemd causes it to inquire about the caller's connection UID and PID. If this check fails, the call is rejected. Bug: https://bugs.freedesktop.org/show_bug.cgi?id=92857 Reviewed-by: Simon McVittie [smcv: go back to DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN as the error code for failure to determine the pid] --- bus/driver.c | 170 ++++++++++++++++++++++++++++++++--------------- dbus/dbus-sysdeps-unix.h | 1 - dbus/dbus-sysdeps-win.c | 9 +++ dbus/dbus-sysdeps.h | 3 + 4 files changed, 127 insertions(+), 56 deletions(-) diff --git a/bus/driver.c b/bus/driver.c index 3234250..01fd340 100644 --- a/bus/driver.c +++ b/bus/driver.c @@ -43,6 +43,13 @@ #include #include +typedef enum +{ + BUS_DRIVER_FOUND_SELF, + BUS_DRIVER_FOUND_PEER, + BUS_DRIVER_FOUND_ERROR, +} BusDriverFound; + static inline const char * nonnull (const char *maybe_null, const char *if_null) @@ -68,11 +75,12 @@ bus_driver_get_owner_of_name (DBusConnection *connection, return bus_service_get_primary_owners_connection (serv); } -static DBusConnection * +static BusDriverFound bus_driver_get_conn_helper (DBusConnection *connection, DBusMessage *message, const char *what_we_want, const char **name_p, + DBusConnection **peer_conn_p, DBusError *error) { DBusConnection *conn; @@ -81,11 +89,17 @@ bus_driver_get_conn_helper (DBusConnection *connection, if (!dbus_message_get_args (message, error, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) - return NULL; + return BUS_DRIVER_FOUND_ERROR; _dbus_assert (name != NULL); _dbus_verbose ("asked for %s of connection %s\n", what_we_want, name); + if (name_p != NULL) + *name_p = name; + + if (strcmp (name, DBUS_SERVICE_DBUS) == 0) + return BUS_DRIVER_FOUND_SELF; + conn = bus_driver_get_owner_of_name (connection, name); if (conn == NULL) @@ -93,13 +107,13 @@ bus_driver_get_conn_helper (DBusConnection *connection, dbus_set_error (error, DBUS_ERROR_NAME_HAS_NO_OWNER, "Could not get %s of name '%s': no such name", what_we_want, name); - return NULL; + return BUS_DRIVER_FOUND_ERROR; } - if (name_p != NULL) - *name_p = name; + if (peer_conn_p != NULL) + *peer_conn_p = conn; - return conn; + return BUS_DRIVER_FOUND_PEER; } /* @@ -1602,25 +1616,31 @@ bus_driver_handle_get_connection_unix_user (DBusConnection *connection, { DBusConnection *conn; DBusMessage *reply; - unsigned long uid; + dbus_uid_t uid; dbus_uint32_t uid32; const char *service; + BusDriverFound found; _DBUS_ASSERT_ERROR_IS_CLEAR (error); reply = NULL; - conn = bus_driver_get_conn_helper (connection, message, "UID", &service, - error); - - if (conn == NULL) - goto failed; - - reply = dbus_message_new_method_return (message); - if (reply == NULL) - goto oom; + found = bus_driver_get_conn_helper (connection, message, "UID", &service, + &conn, error); + switch (found) + { + case BUS_DRIVER_FOUND_SELF: + uid = _dbus_getuid (); + break; + case BUS_DRIVER_FOUND_PEER: + if (!dbus_connection_get_unix_user (conn, &uid)) + uid = DBUS_UID_UNSET; + break; + case BUS_DRIVER_FOUND_ERROR: + goto failed; + } - if (!dbus_connection_get_unix_user (conn, &uid)) + if (uid == DBUS_UID_UNSET) { dbus_set_error (error, DBUS_ERROR_FAILED, @@ -1628,6 +1648,10 @@ bus_driver_handle_get_connection_unix_user (DBusConnection *connection, goto failed; } + reply = dbus_message_new_method_return (message); + if (reply == NULL) + goto oom; + uid32 = uid; if (! dbus_message_append_args (reply, DBUS_TYPE_UINT32, &uid32, @@ -1659,25 +1683,31 @@ bus_driver_handle_get_connection_unix_process_id (DBusConnection *connection, { DBusConnection *conn; DBusMessage *reply; - unsigned long pid; + dbus_pid_t pid; dbus_uint32_t pid32; const char *service; + BusDriverFound found; _DBUS_ASSERT_ERROR_IS_CLEAR (error); reply = NULL; - conn = bus_driver_get_conn_helper (connection, message, "PID", &service, - error); - - if (conn == NULL) - goto failed; - - reply = dbus_message_new_method_return (message); - if (reply == NULL) - goto oom; + found = bus_driver_get_conn_helper (connection, message, "PID", &service, + &conn, error); + switch (found) + { + case BUS_DRIVER_FOUND_SELF: + pid = _dbus_getpid (); + break; + case BUS_DRIVER_FOUND_PEER: + if (!dbus_connection_get_unix_process_id (conn, &pid)) + pid = DBUS_PID_UNSET; + break; + case BUS_DRIVER_FOUND_ERROR: + goto failed; + } - if (!dbus_connection_get_unix_process_id (conn, &pid)) + if (pid == DBUS_PID_UNSET) { dbus_set_error (error, DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN, @@ -1685,6 +1715,10 @@ bus_driver_handle_get_connection_unix_process_id (DBusConnection *connection, goto failed; } + reply = dbus_message_new_method_return (message); + if (reply == NULL) + goto oom; + pid32 = pid; if (! dbus_message_append_args (reply, DBUS_TYPE_UINT32, &pid32, @@ -1719,22 +1753,29 @@ bus_driver_handle_get_adt_audit_session_data (DBusConnection *connection, void *data = NULL; dbus_uint32_t data_size; const char *service; + BusDriverFound found; _DBUS_ASSERT_ERROR_IS_CLEAR (error); reply = NULL; - conn = bus_driver_get_conn_helper (connection, message, - "audit session data", &service, error); + found = bus_driver_get_conn_helper (connection, message, "audit session data", + &service, &conn, error); - if (conn == NULL) + if (found == BUS_DRIVER_FOUND_ERROR) goto failed; reply = dbus_message_new_method_return (message); if (reply == NULL) goto oom; - if (!dbus_connection_get_adt_audit_session_data (conn, &data, &data_size) || data == NULL) + /* We don't know how to find "ADT audit session data" for the bus daemon + * itself. Is that even meaningful? + * FIXME: Implement this or briefly note it makes no sense. + */ + if (found != BUS_DRIVER_FOUND_PEER || + !dbus_connection_get_adt_audit_session_data (conn, &data, &data_size) || + data == NULL) { dbus_set_error (error, DBUS_ERROR_ADT_AUDIT_DATA_UNKNOWN, @@ -1774,22 +1815,28 @@ bus_driver_handle_get_connection_selinux_security_context (DBusConnection *conne DBusMessage *reply; BusSELinuxID *context; const char *service; + BusDriverFound found; _DBUS_ASSERT_ERROR_IS_CLEAR (error); reply = NULL; - conn = bus_driver_get_conn_helper (connection, message, "security context", - &service, error); + found = bus_driver_get_conn_helper (connection, message, "security context", + &service, &conn, error); - if (conn == NULL) + if (found == BUS_DRIVER_FOUND_ERROR) goto failed; reply = dbus_message_new_method_return (message); if (reply == NULL) goto oom; - context = bus_connection_get_selinux_id (conn); + /* FIXME: Obtain the SELinux security context for the bus daemon itself */ + if (found == BUS_DRIVER_FOUND_PEER) + context = bus_connection_get_selinux_id (conn); + else + context = NULL; + if (!context) { dbus_set_error (error, @@ -1828,19 +1875,34 @@ bus_driver_handle_get_connection_credentials (DBusConnection *connection, DBusMessage *reply; DBusMessageIter reply_iter; DBusMessageIter array_iter; - unsigned long ulong_val; + unsigned long ulong_uid, ulong_pid; char *s; const char *service; + BusDriverFound found; _DBUS_ASSERT_ERROR_IS_CLEAR (error); reply = NULL; - conn = bus_driver_get_conn_helper (connection, message, "credentials", - &service, error); + found = bus_driver_get_conn_helper (connection, message, "credentials", + &service, &conn, error); - if (conn == NULL) - goto failed; + switch (found) + { + case BUS_DRIVER_FOUND_SELF: + ulong_pid = _dbus_getpid (); + ulong_uid = _dbus_getuid (); + break; + + case BUS_DRIVER_FOUND_PEER: + if (!dbus_connection_get_unix_process_id (conn, &ulong_pid)) + ulong_pid = DBUS_PID_UNSET; + if (!dbus_connection_get_unix_user (conn, &ulong_uid)) + ulong_uid = DBUS_UID_UNSET; + break; + case BUS_DRIVER_FOUND_ERROR: + goto failed; + } reply = _dbus_asv_new_method_return (message, &reply_iter, &array_iter); if (reply == NULL) @@ -1848,23 +1910,19 @@ bus_driver_handle_get_connection_credentials (DBusConnection *connection, /* 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; - } + if (ulong_pid <= _DBUS_UINT32_MAX && ulong_pid != DBUS_PID_UNSET && + !_dbus_asv_add_uint32 (&array_iter, "ProcessID", ulong_pid)) + 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 (ulong_uid <= _DBUS_UINT32_MAX && ulong_uid != DBUS_UID_UNSET && + !_dbus_asv_add_uint32 (&array_iter, "UnixUserID", ulong_uid)) + goto oom; - if (dbus_connection_get_windows_user (conn, &s)) + /* FIXME: Obtain the Windows user of the bus daemon itself */ + if (found == BUS_DRIVER_FOUND_PEER && + dbus_connection_get_windows_user (conn, &s)) { DBusString str; dbus_bool_t result; @@ -1886,7 +1944,9 @@ bus_driver_handle_get_connection_credentials (DBusConnection *connection, dbus_free (s); } - if (_dbus_connection_get_linux_security_label (conn, &s)) + /* FIXME: Obtain the security label for the bus daemon itself */ + if (found == BUS_DRIVER_FOUND_PEER && + _dbus_connection_get_linux_security_label (conn, &s)) { if (s == NULL) goto oom; diff --git a/dbus/dbus-sysdeps-unix.h b/dbus/dbus-sysdeps-unix.h index 0932129..72f3ecf 100644 --- a/dbus/dbus-sysdeps-unix.h +++ b/dbus/dbus-sysdeps-unix.h @@ -138,7 +138,6 @@ dbus_bool_t _dbus_group_info_fill_gid (DBusGroupInfo *info, DBusError *error); void _dbus_group_info_free (DBusGroupInfo *info); -dbus_uid_t _dbus_getuid (void); DBUS_PRIVATE_EXPORT dbus_uid_t _dbus_geteuid (void); diff --git a/dbus/dbus-sysdeps-win.c b/dbus/dbus-sysdeps-win.c index fb14e40..fb19580 100644 --- a/dbus/dbus-sysdeps-win.c +++ b/dbus/dbus-sysdeps-win.c @@ -2138,6 +2138,15 @@ _dbus_getpid (void) return GetCurrentProcessId (); } +/** Gets our Unix UID + * @returns on Windows, just DBUS_UID_UNSET + */ +dbus_uid_t +_dbus_getuid (void) +{ + return DBUS_UID_UNSET; +} + /** nanoseconds in a second */ #define NANOSECONDS_PER_SECOND 1000000000 /** microseconds in a second */ diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h index 79a6cc7..2f493b0 100644 --- a/dbus/dbus-sysdeps.h +++ b/dbus/dbus-sysdeps.h @@ -641,6 +641,9 @@ unsigned long _dbus_pid_for_log (void); DBUS_PRIVATE_EXPORT dbus_pid_t _dbus_getpid (void); +DBUS_PRIVATE_EXPORT +dbus_uid_t _dbus_getuid (void); + dbus_bool_t _dbus_change_to_daemon_user (const char *user, DBusError *error); -- 2.7.4