]> git.ipfire.org Git - thirdparty/dbus.git/commitdiff
sysdeps: Add accessor for a list of transient service directories
authorSimon McVittie <simon.mcvittie@collabora.co.uk>
Mon, 13 Feb 2017 19:57:03 +0000 (19:57 +0000)
committerSimon McVittie <simon.mcvittie@collabora.co.uk>
Tue, 21 Feb 2017 13:23:37 +0000 (13:23 +0000)
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>
dbus/dbus-sysdeps-util-unix.c
dbus/dbus-sysdeps-util-win.c
dbus/dbus-sysdeps.h

index d9e8c4fc6f41be09a0d8792877c005942696bffd..5d08c0ba49be87475a624a0edcd15f268f76fabe 100644 (file)
@@ -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,9 +1189,162 @@ _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
index eb860f4d9483af02cc4b2379d12fbc41c2e94401..923fe3c5061313fc682c479d064b93f4f1742f91 100644 (file)
@@ -1479,6 +1479,21 @@ _dbus_replace_install_prefix (DBusString *path)
 #define DBUS_STANDARD_SESSION_SERVICEDIR "/dbus-1/services"
 #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
index 543ce57f5ffa54e67f7254c27cdbeb025b338765..5ed4c45ed9044bef8e02ecfdbf7f7cf8388c0811 100644 (file)
@@ -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);