summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon McVittie <simon.mcvittie@collabora.co.uk>2017-02-13 19:57:03 +0000
committerSimon McVittie <simon.mcvittie@collabora.co.uk>2017-02-21 13:23:37 +0000
commit49b3ea6197f88e98bacf22d7c46294a21a2bdc8d (patch)
tree76b8227edf7d38f65c6c57ec28f1b421cd17508d
parentb2be1400de81c12cf6e39e0f5f48e250c9322e52 (diff)
sysdeps: Add accessor for a list of transient service directories
These directories can be used by service managers like `systemd --user` and its generators, or by session infrastructure like gnome-session, to synthesize D-Bus service files at runtime from some more canonical source of information. The intention is that this is in the XDG_RUNTIME_DIR as defined by the freedesktop.org Base Directory Specification, which is private to the user, and has a lifetime equal to the union of all the user's concurrent login sessions. This directory is provided on Linux systems that have systemd-logind and pam_systemd, on other systems with PAM that have pam-xdg-support (which has been abandoned by Ubuntu in favour of logind, but could be forked by non-systemd environments that are interested in this functionality), or any compatible reimplementation. In practice this is most likely to be useful on systems that run `dbus-daemon --session` from `systemd --user`. Bug: https://bugs.freedesktop.org/show_bug.cgi?id=99825 Reviewed-by: Philip Withnall <withnall@endlessm.com> Signed-off-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
-rw-r--r--dbus/dbus-sysdeps-util-unix.c154
-rw-r--r--dbus/dbus-sysdeps-util-win.c15
-rw-r--r--dbus/dbus-sysdeps.h2
3 files changed, 171 insertions, 0 deletions
diff --git a/dbus/dbus-sysdeps-util-unix.c b/dbus/dbus-sysdeps-util-unix.c
index d9e8c4fc..5d08c0ba 100644
--- a/dbus/dbus-sysdeps-util-unix.c
+++ b/dbus/dbus-sysdeps-util-unix.c
@@ -26,6 +26,7 @@
#include "dbus-sysdeps.h"
#include "dbus-sysdeps-unix.h"
#include "dbus-internals.h"
+#include "dbus-list.h"
#include "dbus-pipe.h"
#include "dbus-protocol.h"
#include "dbus-string.h"
@@ -1188,10 +1189,163 @@ _dbus_replace_install_prefix (DBusString *path)
return TRUE;
}
+static dbus_bool_t
+ensure_owned_directory (const char *label,
+ const DBusString *string,
+ dbus_bool_t create,
+ DBusError *error)
+{
+ const char *dir = _dbus_string_get_const_data (string);
+ struct stat buf;
+
+ if (create && !_dbus_ensure_directory (string, error))
+ return FALSE;
+
+ /*
+ * The stat()-based checks in this function are to protect against
+ * mistakes, not malice. We are working in a directory that is meant
+ * to be trusted; but if a user has used `su` or similar to escalate
+ * their privileges without correctly clearing the environment, the
+ * XDG_RUNTIME_DIR in the environment might still be the user's
+ * and not root's. We don't want to write root-owned files into that
+ * directory, so just warn and don't provide support for transient
+ * services in that case.
+ *
+ * In particular, we use stat() and not lstat() so that if we later
+ * decide to use a different directory name for transient services,
+ * we can drop in a compatibility symlink without breaking older
+ * libdbus.
+ */
+
+ if (stat (dir, &buf) != 0)
+ {
+ int saved_errno = errno;
+
+ dbus_set_error (error, _dbus_error_from_errno (saved_errno),
+ "%s \"%s\" not available: %s", label, dir,
+ _dbus_strerror (saved_errno));
+ return FALSE;
+ }
+
+ if (!S_ISDIR (buf.st_mode))
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED, "%s \"%s\" is not a directory",
+ label, dir);
+ return FALSE;
+ }
+
+ if (buf.st_uid != geteuid ())
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "%s \"%s\" is owned by uid %ld, not our uid %ld",
+ label, dir, (long) buf.st_uid, (long) geteuid ());
+ return FALSE;
+ }
+
+ /* This is just because we have the stat() results already, so we might
+ * as well check opportunistically. */
+ if ((S_IWOTH | S_IWGRP) & buf.st_mode)
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "%s \"%s\" can be written by others (mode 0%o)",
+ label, dir, buf.st_mode);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
#define DBUS_UNIX_STANDARD_SESSION_SERVICEDIR "/dbus-1/services"
#define DBUS_UNIX_STANDARD_SYSTEM_SERVICEDIR "/dbus-1/system-services"
/**
+ * Returns the standard directories for a session bus to look for
+ * transient service activation files.
+ *
+ * @param dirs the directory list we are returning
+ * @returns #FALSE on error
+ */
+dbus_bool_t
+_dbus_set_up_transient_session_servicedirs (DBusList **dirs,
+ DBusError *error)
+{
+ const char *xdg_runtime_dir;
+ DBusString services;
+ DBusString dbus1;
+ DBusString xrd;
+ dbus_bool_t ret = FALSE;
+ char *data = NULL;
+
+ if (!_dbus_string_init (&dbus1))
+ {
+ _DBUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ if (!_dbus_string_init (&services))
+ {
+ _dbus_string_free (&dbus1);
+ _DBUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ if (!_dbus_string_init (&xrd))
+ {
+ _dbus_string_free (&dbus1);
+ _dbus_string_free (&services);
+ _DBUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ xdg_runtime_dir = _dbus_getenv ("XDG_RUNTIME_DIR");
+
+ /* Not an error, we just can't have transient session services */
+ if (xdg_runtime_dir == NULL)
+ {
+ _dbus_verbose ("XDG_RUNTIME_DIR is unset: transient session services "
+ "not available here\n");
+ ret = TRUE;
+ goto out;
+ }
+
+ if (!_dbus_string_append (&xrd, xdg_runtime_dir) ||
+ !_dbus_string_append_printf (&dbus1, "%s/dbus-1",
+ xdg_runtime_dir) ||
+ !_dbus_string_append_printf (&services, "%s/dbus-1/services",
+ xdg_runtime_dir))
+ {
+ _DBUS_SET_OOM (error);
+ goto out;
+ }
+
+ if (!ensure_owned_directory ("XDG_RUNTIME_DIR", &xrd, FALSE, error) ||
+ !ensure_owned_directory ("XDG_RUNTIME_DIR subdirectory", &dbus1, TRUE,
+ error) ||
+ !ensure_owned_directory ("XDG_RUNTIME_DIR subdirectory", &services,
+ TRUE, error))
+ goto out;
+
+ if (!_dbus_string_steal_data (&services, &data) ||
+ !_dbus_list_append (dirs, data))
+ {
+ _DBUS_SET_OOM (error);
+ goto out;
+ }
+
+ _dbus_verbose ("Transient service directory is %s\n", data);
+ /* Ownership was transferred to @dirs */
+ data = NULL;
+ ret = TRUE;
+
+out:
+ _dbus_string_free (&dbus1);
+ _dbus_string_free (&services);
+ _dbus_string_free (&xrd);
+ dbus_free (data);
+ return ret;
+}
+
+/**
* Returns the standard directories for a session bus to look for service
* activation files
*
diff --git a/dbus/dbus-sysdeps-util-win.c b/dbus/dbus-sysdeps-util-win.c
index eb860f4d..923fe3c5 100644
--- a/dbus/dbus-sysdeps-util-win.c
+++ b/dbus/dbus-sysdeps-util-win.c
@@ -1480,6 +1480,21 @@ _dbus_replace_install_prefix (DBusString *path)
#define DBUS_STANDARD_SYSTEM_SERVICEDIR "/dbus-1/system-services"
/**
+ * Returns the standard directories for a session bus to look for
+ * transient service activation files. On Windows, there are none.
+ *
+ * @param dirs the directory list we are returning
+ * @returns #TRUE
+ */
+dbus_bool_t
+_dbus_set_up_transient_session_servicedirs (DBusList **dirs,
+ DBusError *error)
+{
+ /* Not an error, we just don't have transient session services on Windows */
+ return TRUE;
+}
+
+/**
* Returns the standard directories for a session bus to look for service
* activation files
*
diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h
index 543ce57f..5ed4c45e 100644
--- a/dbus/dbus-sysdeps.h
+++ b/dbus/dbus-sysdeps.h
@@ -428,6 +428,8 @@ dbus_bool_t _dbus_path_is_absolute (const DBusString *filename);
dbus_bool_t _dbus_get_standard_session_servicedirs (DBusList **dirs);
dbus_bool_t _dbus_get_standard_system_servicedirs (DBusList **dirs);
+dbus_bool_t _dbus_set_up_transient_session_servicedirs (DBusList **dirs,
+ DBusError *error);
dbus_bool_t _dbus_get_system_config_file (DBusString *str);
dbus_bool_t _dbus_get_session_config_file (DBusString *str);