Blame SOURCES/dbus-1.10.24-dbus-launch-chdir.patch

fa9106
From dc2074588d3e7b5a216cb8c0b82094157c3cf773 Mon Sep 17 00:00:00 2001
fa9106
From: David King <dking@redhat.com>
fa9106
Date: Mon, 25 Jun 2018 14:46:14 -0400
fa9106
Subject: [PATCH] daemon: use HOME as the working directory
fa9106
fa9106
Session buses started as part of a systemd --user session are launched
fa9106
with the current working directory being the home directory of the user.
fa9106
Applications which are launched via dbus activation inherit the working
fa9106
directory from the session bus dbus-daemon.
fa9106
fa9106
When dbus-launch is used to start dbus-daemon, as is commonly the case
fa9106
with a session manager such as gnome-session, this leads to applications
fa9106
having a default working directory of "/", which is undesirable (as an
fa9106
example, the default directory in a GTK+ save dialog becomes "/").
fa9106
fa9106
As an improvement, make dbus-launch use the value of the environment
fa9106
variable HOME, if it is set, as the current working directory.
fa9106
fa9106
Signed-off-by: David King <dking@redhat.com>
fa9106
Bug: https://bugs.freedesktop.org/show_bug.cgi?id=106987
fa9106
Bug-RedHat: https://bugzilla.redhat.com/show_bug.cgi?id=1470310
fa9106
---
fa9106
 bus/bus.c                     |  9 +++++++++
fa9106
 dbus/dbus-sysdeps-util-unix.c |  8 +++++---
fa9106
 dbus/dbus-sysdeps-util-win.c  |  2 ++
fa9106
 dbus/dbus-sysdeps.h           |  1 +
fa9106
 doc/dbus-launch.1.xml.in      |  4 ++++
fa9106
 tools/dbus-launch.c           | 22 ++++++++++++++--------
fa9106
 6 files changed, 35 insertions(+), 11 deletions(-)
fa9106
fa9106
diff --git a/bus/bus.c b/bus/bus.c
fa9106
index f788e677..da2b2c1f 100644
fa9106
--- a/bus/bus.c
fa9106
+++ b/bus/bus.c
fa9106
@@ -870,63 +870,72 @@ bus_context_new (const DBusString *config_file,
fa9106
 
fa9106
   context->matchmaker = bus_matchmaker_new ();
fa9106
   if (context->matchmaker == NULL)
fa9106
     {
fa9106
       BUS_SET_OOM (error);
fa9106
       goto failed;
fa9106
     }
fa9106
 
fa9106
   /* check user before we fork */
fa9106
   if (context->user != NULL)
fa9106
     {
fa9106
       if (!_dbus_verify_daemon_user (context->user))
fa9106
         {
fa9106
           dbus_set_error (error, DBUS_ERROR_FAILED,
fa9106
                           "Could not get UID and GID for username \"%s\"",
fa9106
                           context->user);
fa9106
           goto failed;
fa9106
         }
fa9106
     }
fa9106
 
fa9106
   /* Now become a daemon if appropriate and write out pid file in any case */
fa9106
   {
fa9106
     DBusString u;
fa9106
 
fa9106
     if (context->pidfile)
fa9106
       _dbus_string_init_const (&u, context->pidfile);
fa9106
 
fa9106
     if (((flags & BUS_CONTEXT_FLAG_FORK_NEVER) == 0 && context->fork) ||
fa9106
         (flags & BUS_CONTEXT_FLAG_FORK_ALWAYS))
fa9106
       {
fa9106
+        const char *working_dir = NULL;
fa9106
+
fa9106
         _dbus_verbose ("Forking and becoming daemon\n");
fa9106
 
fa9106
+        if (context->type != NULL && strcmp (context->type, "session") == 0)
fa9106
+          working_dir = _dbus_getenv ("HOME");
fa9106
+
fa9106
+        if (working_dir == NULL)
fa9106
+          working_dir = "/";
fa9106
+
fa9106
         if (!_dbus_become_daemon (context->pidfile ? &u : NULL,
fa9106
+                                  working_dir,
fa9106
                                   print_pid_pipe,
fa9106
                                   error,
fa9106
                                   context->keep_umask))
fa9106
           {
fa9106
             _DBUS_ASSERT_ERROR_IS_SET (error);
fa9106
             goto failed;
fa9106
           }
fa9106
       }
fa9106
     else
fa9106
       {
fa9106
         _dbus_verbose ("Fork not requested\n");
fa9106
 
fa9106
         /* Need to write PID file and to PID pipe for ourselves,
fa9106
          * not for the child process. This is a no-op if the pidfile
fa9106
          * is NULL and print_pid_pipe is NULL.
fa9106
          */
fa9106
         if (!_dbus_write_pid_to_file_and_pipe (context->pidfile ? &u : NULL,
fa9106
                                                print_pid_pipe,
fa9106
                                                _dbus_getpid (),
fa9106
                                                error))
fa9106
           {
fa9106
             _DBUS_ASSERT_ERROR_IS_SET (error);
fa9106
             goto failed;
fa9106
           }
fa9106
       }
fa9106
   }
fa9106
 
fa9106
   if (print_pid_pipe && _dbus_pipe_is_valid (print_pid_pipe) &&
fa9106
       !_dbus_pipe_is_stdout_or_stderr (print_pid_pipe))
fa9106
     _dbus_pipe_close (print_pid_pipe, NULL);
fa9106
diff --git a/dbus/dbus-sysdeps-util-unix.c b/dbus/dbus-sysdeps-util-unix.c
fa9106
index 9b724cc9..30bb1441 100644
fa9106
--- a/dbus/dbus-sysdeps-util-unix.c
fa9106
+++ b/dbus/dbus-sysdeps-util-unix.c
fa9106
@@ -49,82 +49,84 @@
fa9106
 #include <sys/socket.h>
fa9106
 #include <dirent.h>
fa9106
 #include <sys/un.h>
fa9106
 
fa9106
 #ifdef HAVE_SYSLOG_H
fa9106
 #include <syslog.h>
fa9106
 #endif
fa9106
 
fa9106
 #ifdef HAVE_SYS_SYSLIMITS_H
fa9106
 #include <sys/syslimits.h>
fa9106
 #endif
fa9106
 
fa9106
 #ifdef HAVE_SYSTEMD
fa9106
 #include <systemd/sd-daemon.h>
fa9106
 #endif
fa9106
 
fa9106
 #ifndef O_BINARY
fa9106
 #define O_BINARY 0
fa9106
 #endif
fa9106
 
fa9106
 /**
fa9106
  * @addtogroup DBusInternalsUtils
fa9106
  * @{
fa9106
  */
fa9106
 
fa9106
 
fa9106
 /**
fa9106
  * Does the chdir, fork, setsid, etc. to become a daemon process.
fa9106
  *
fa9106
  * @param pidfile #NULL, or pidfile to create
fa9106
+ * @param working_dir directory to chdir to
fa9106
  * @param print_pid_pipe pipe to print daemon's pid to, or -1 for none
fa9106
  * @param error return location for errors
fa9106
  * @param keep_umask #TRUE to keep the original umask
fa9106
  * @returns #FALSE on failure
fa9106
  */
fa9106
 dbus_bool_t
fa9106
 _dbus_become_daemon (const DBusString *pidfile,
fa9106
+                     const char       *working_dir,
fa9106
                      DBusPipe         *print_pid_pipe,
fa9106
                      DBusError        *error,
fa9106
                      dbus_bool_t       keep_umask)
fa9106
 {
fa9106
   const char *s;
fa9106
   pid_t child_pid;
fa9106
   int dev_null_fd;
fa9106
 
fa9106
   _dbus_verbose ("Becoming a daemon...\n");
fa9106
 
fa9106
-  _dbus_verbose ("chdir to /\n");
fa9106
-  if (chdir ("/") < 0)
fa9106
+  _dbus_verbose ("chdir to %s\n", working_dir);
fa9106
+  if (chdir (working_dir) < 0)
fa9106
     {
fa9106
       dbus_set_error (error, DBUS_ERROR_FAILED,
fa9106
-                      "Could not chdir() to root directory");
fa9106
+                      "Could not chdir() to working directory (%s)", working_dir);
fa9106
       return FALSE;
fa9106
     }
fa9106
 
fa9106
   _dbus_verbose ("forking...\n");
fa9106
   switch ((child_pid = fork ()))
fa9106
     {
fa9106
     case -1:
fa9106
       _dbus_verbose ("fork failed\n");
fa9106
       dbus_set_error (error, _dbus_error_from_errno (errno),
fa9106
                       "Failed to fork daemon: %s", _dbus_strerror (errno));
fa9106
       return FALSE;
fa9106
       break;
fa9106
 
fa9106
     case 0:
fa9106
       _dbus_verbose ("in child, closing std file descriptors\n");
fa9106
 
fa9106
       /* silently ignore failures here, if someone
fa9106
        * doesn't have /dev/null we may as well try
fa9106
        * to continue anyhow
fa9106
        */
fa9106
       
fa9106
       dev_null_fd = open ("/dev/null", O_RDWR);
fa9106
       if (dev_null_fd >= 0)
fa9106
         {
fa9106
           dup2 (dev_null_fd, 0);
fa9106
           dup2 (dev_null_fd, 1);
fa9106
           
fa9106
           s = _dbus_getenv ("DBUS_DEBUG_OUTPUT");
fa9106
           if (s == NULL || *s == '\0')
fa9106
             dup2 (dev_null_fd, 2);
fa9106
diff --git a/dbus/dbus-sysdeps-util-win.c b/dbus/dbus-sysdeps-util-win.c
fa9106
index 3b754dbf..bfc1cb90 100644
fa9106
--- a/dbus/dbus-sysdeps-util-win.c
fa9106
+++ b/dbus/dbus-sysdeps-util-win.c
fa9106
@@ -27,67 +27,69 @@
fa9106
 #define STRSAFE_NO_DEPRECATE
fa9106
 
fa9106
 #include "dbus-sysdeps.h"
fa9106
 #include "dbus-internals.h"
fa9106
 #include "dbus-protocol.h"
fa9106
 #include "dbus-string.h"
fa9106
 #include "dbus-sysdeps.h"
fa9106
 #include "dbus-sysdeps-win.h"
fa9106
 #include "dbus-sockets-win.h"
fa9106
 #include "dbus-memory.h"
fa9106
 #include "dbus-pipe.h"
fa9106
 
fa9106
 #include <stdio.h>
fa9106
 #include <stdlib.h>
fa9106
 #if HAVE_ERRNO_H
fa9106
 #include <errno.h>
fa9106
 #endif
fa9106
 #include <winsock2.h>   // WSA error codes
fa9106
 
fa9106
 #ifndef DBUS_WINCE
fa9106
 #include <io.h>
fa9106
 #include <lm.h>
fa9106
 #include <sys/stat.h>
fa9106
 #endif
fa9106
 
fa9106
 
fa9106
 /**
fa9106
  * Does the chdir, fork, setsid, etc. to become a daemon process.
fa9106
  *
fa9106
  * @param pidfile #NULL, or pidfile to create
fa9106
+ * @param working_dir directory to chdir to
fa9106
  * @param print_pid_pipe file descriptor to print daemon's pid to, or -1 for none
fa9106
  * @param error return location for errors
fa9106
  * @param keep_umask #TRUE to keep the original umask
fa9106
  * @returns #FALSE on failure
fa9106
  */
fa9106
 dbus_bool_t
fa9106
 _dbus_become_daemon (const DBusString *pidfile,
fa9106
+                     const char       *working_dir,
fa9106
                      DBusPipe         *print_pid_pipe,
fa9106
                      DBusError        *error,
fa9106
                      dbus_bool_t       keep_umask)
fa9106
 {
fa9106
   dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED,
fa9106
                   "Cannot daemonize on Windows");
fa9106
   return FALSE;
fa9106
 }
fa9106
 
fa9106
 /**
fa9106
  * Creates a file containing the process ID.
fa9106
  *
fa9106
  * @param filename the filename to write to
fa9106
  * @param pid our process ID
fa9106
  * @param error return location for errors
fa9106
  * @returns #FALSE on failure
fa9106
  */
fa9106
 static dbus_bool_t
fa9106
 _dbus_write_pid_file (const DBusString *filename,
fa9106
                       unsigned long     pid,
fa9106
                       DBusError        *error)
fa9106
 {
fa9106
   const char *cfilename;
fa9106
   HANDLE hnd;
fa9106
   char pidstr[20];
fa9106
   int total;
fa9106
   int bytes_to_write;
fa9106
 
fa9106
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
fa9106
 
fa9106
diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h
fa9106
index 0ee45c97..e569b545 100644
fa9106
--- a/dbus/dbus-sysdeps.h
fa9106
+++ b/dbus/dbus-sysdeps.h
fa9106
@@ -498,60 +498,61 @@ int _dbus_printf_string_upper_bound (const char *format,
fa9106
                                      va_list args);
fa9106
 
fa9106
 
fa9106
 /**
fa9106
  * Portable struct with stat() results
fa9106
  */
fa9106
 typedef struct
fa9106
 {
fa9106
   unsigned long mode;  /**< File mode */
fa9106
   unsigned long nlink; /**< Number of hard links */
fa9106
   dbus_uid_t    uid;   /**< User owning file */
fa9106
   dbus_gid_t    gid;   /**< Group owning file */
fa9106
   unsigned long size;  /**< Size of file */
fa9106
   unsigned long atime; /**< Access time */
fa9106
   unsigned long mtime; /**< Modify time */
fa9106
   unsigned long ctime; /**< Creation time */
fa9106
 } DBusStat;
fa9106
 
fa9106
 dbus_bool_t _dbus_stat             (const DBusString *filename,
fa9106
                                     DBusStat         *statbuf,
fa9106
                                     DBusError        *error);
fa9106
 DBUS_PRIVATE_EXPORT
fa9106
 dbus_bool_t _dbus_socketpair (DBusSocket       *fd1,
fa9106
                               DBusSocket       *fd2,
fa9106
                               dbus_bool_t       blocking,
fa9106
                               DBusError        *error);
fa9106
 
fa9106
 void        _dbus_print_backtrace  (void);
fa9106
 
fa9106
 dbus_bool_t _dbus_become_daemon   (const DBusString *pidfile,
fa9106
+                                   const char       *working_dir,
fa9106
                                    DBusPipe         *print_pid_pipe,
fa9106
                                    DBusError        *error,
fa9106
                                    dbus_bool_t       keep_umask);
fa9106
 
fa9106
 dbus_bool_t _dbus_verify_daemon_user    (const char *user);
fa9106
 dbus_bool_t _dbus_change_to_daemon_user (const char *user,
fa9106
                                          DBusError  *error);
fa9106
 
fa9106
 dbus_bool_t _dbus_write_pid_to_file_and_pipe (const DBusString *pidfile,
fa9106
                                               DBusPipe         *print_pid_pipe,
fa9106
                                               dbus_pid_t        pid_to_write,
fa9106
                                               DBusError        *error);
fa9106
 
fa9106
 dbus_bool_t _dbus_command_for_pid (unsigned long  pid,
fa9106
                                    DBusString    *str,
fa9106
                                    int            max_len,
fa9106
                                    DBusError     *error);
fa9106
 
fa9106
 /** A UNIX signal handler */
fa9106
 typedef void (* DBusSignalHandler) (int sig);
fa9106
 
fa9106
 void _dbus_set_signal_handler (int               sig,
fa9106
                                DBusSignalHandler handler);
fa9106
 
fa9106
 dbus_bool_t _dbus_user_at_console (const char *username,
fa9106
                                    DBusError  *error);
fa9106
 
fa9106
 void _dbus_init_system_log (dbus_bool_t is_daemon);
fa9106
 
fa9106
 typedef enum {
fa9106
diff --git a/doc/dbus-launch.1.xml.in b/doc/dbus-launch.1.xml.in
fa9106
index 5135d9ca..606c65be 100644
fa9106
--- a/doc/dbus-launch.1.xml.in
fa9106
+++ b/doc/dbus-launch.1.xml.in
fa9106
@@ -23,60 +23,64 @@
fa9106
   <command>dbus-launch</command>
fa9106
     <arg choice='opt'>--version </arg>
fa9106
     <arg choice='opt'>--help </arg>
fa9106
     <arg choice='opt'>--sh-syntax </arg>
fa9106
     <arg choice='opt'>--csh-syntax </arg>
fa9106
     <arg choice='opt'>--auto-syntax </arg>
fa9106
     <arg choice='opt'>--binary-syntax </arg>
fa9106
     <arg choice='opt'>--close-stderr </arg>
fa9106
     <arg choice='opt'>--exit-with-session </arg>
fa9106
     <arg choice='opt'>--autolaunch=<replaceable>MACHINEID</replaceable></arg>
fa9106
     <arg choice='opt'>--config-file=<replaceable>FILENAME</replaceable></arg>
fa9106
     <arg choice='opt'><replaceable>PROGRAM</replaceable></arg>
fa9106
     <arg choice='opt' rep='repeat'><replaceable>ARGS</replaceable></arg>
fa9106
     <sbr/>
fa9106
 </cmdsynopsis>
fa9106
 </refsynopsisdiv>
fa9106
 
fa9106
 
fa9106
 <refsect1 id='description'><title>DESCRIPTION</title>
fa9106
 <para>The <command>dbus-launch</command> command is used to start a session bus
fa9106
 instance of <emphasis remap='I'>dbus-daemon</emphasis> from a shell script.
fa9106
 It would normally be called from a user's login
fa9106
 scripts. Unlike the daemon itself, <command>dbus-launch</command> exits, so
fa9106
 backticks or the $() construct can be used to read information from
fa9106
 <command>dbus-launch</command>.</para>
fa9106
 
fa9106
 <para>With no arguments, <command>dbus-launch</command> will launch a session bus
fa9106
 instance and print the address and PID of that instance to standard
fa9106
 output.</para>
fa9106
 
fa9106
+<para>If the environment variable HOME is set, it is used as the current
fa9106
+working directory. Otherwise, the root directory (<filename>/</filename>) is
fa9106
+used.</para>
fa9106
+
fa9106
 <para>You may specify a program to be run; in this case, <command>dbus-launch</command>
fa9106
 will launch a session bus instance, set the appropriate environment
fa9106
 variables so the specified program can find the bus, and then execute the
fa9106
 specified program, with the specified arguments.  See below for
fa9106
 examples.</para>
fa9106
 
fa9106
 <para>If you launch a program, <command>dbus-launch</command> will not print the
fa9106
 information about the new bus to standard output.</para>
fa9106
 
fa9106
 <para>When <command>dbus-launch</command> prints bus information to standard output, by
fa9106
 default it is in a simple key-value pairs format. However, you may
fa9106
 request several alternate syntaxes using the --sh-syntax, --csh-syntax,
fa9106
 --binary-syntax, or
fa9106
 --auto-syntax options. Several of these cause <command>dbus-launch</command> to emit shell code
fa9106
 to set up the environment.</para>
fa9106
 
fa9106
 <para>With the --auto-syntax option, <command>dbus-launch</command> looks at the value
fa9106
 of the SHELL environment variable to determine which shell syntax
fa9106
 should be used.  If SHELL ends in "csh", then csh-compatible code is
fa9106
 emitted; otherwise Bourne shell code is emitted.  Instead of passing
fa9106
 --auto-syntax, you may explicitly specify a particular one by using
fa9106
 --sh-syntax for Bourne syntax, or --csh-syntax for csh syntax.
fa9106
 In scripts, it's more robust to avoid --auto-syntax and you hopefully
fa9106
 know which shell your script is written in.</para>
fa9106
 
fa9106
 
fa9106
 <para>See <ulink url='http://www.freedesktop.org/software/dbus/'>http://www.freedesktop.org/software/dbus/</ulink> for more information
fa9106
 about D-Bus. See also the man page for <emphasis remap='I'>dbus-daemon</emphasis>.</para>
fa9106
 
fa9106
 </refsect1>
fa9106
diff --git a/tools/dbus-launch.c b/tools/dbus-launch.c
fa9106
index 80e4a241..a956684c 100644
fa9106
--- a/tools/dbus-launch.c
fa9106
+++ b/tools/dbus-launch.c
fa9106
@@ -592,71 +592,77 @@ kill_bus_when_session_ends (void)
fa9106
                   /* This shouldn't happen I don't think; to avoid
fa9106
                    * spinning on the fd forever we exit.
fa9106
                    */
fa9106
                   fprintf (stderr, "dbus-launch: error reading from stdin: %s\n",
fa9106
                            strerror (errno));
fa9106
                   kill_bus_and_exit (0);
fa9106
                 }
fa9106
             }
fa9106
           else if (FD_ISSET (tty_fd, &err_set))
fa9106
             {
fa9106
               verbose ("TTY has error condition\n");
fa9106
               
fa9106
               kill_bus_and_exit (0);
fa9106
             }
fa9106
         }
fa9106
     }
fa9106
 }
fa9106
 
fa9106
 static void
fa9106
 babysit (int   exit_with_session,
fa9106
          pid_t child_pid,
fa9106
          int   read_bus_pid_fd)  /* read pid from here */
fa9106
 {
fa9106
   int ret;
fa9106
   int dev_null_fd;
fa9106
   const char *s;
fa9106
 
fa9106
   verbose ("babysitting, exit_with_session = %d, child_pid = %ld, read_bus_pid_fd = %d\n",
fa9106
            exit_with_session, (long) child_pid, read_bus_pid_fd);
fa9106
   
fa9106
-  /* We chdir ("/") since we are persistent and daemon-like, and fork
fa9106
-   * again so dbus-launch can reap the parent.  However, we don't
fa9106
-   * setsid() or close fd 0 because the idea is to remain attached
fa9106
-   * to the tty and the X server in order to kill the message bus
fa9106
-   * when the session ends.
fa9106
+  /* We chdir () since we are persistent and daemon-like, either to $HOME
fa9106
+   * to match the behaviour of a session bus started by systemd --user, or
fa9106
+   * otherwise "/". We fork again so dbus-launch can reap the parent.
fa9106
+   * However, we don't setsid() or close fd 0 because the idea is to
fa9106
+   * remain attached to the tty and the X server in order to kill the
fa9106
+   * message bus when the session ends.
fa9106
    */
fa9106
 
fa9106
-  if (chdir ("/") < 0)
fa9106
+  s = getenv ("HOME");
fa9106
+
fa9106
+  if (s == NULL || *s == '\0')
fa9106
+    s = "/";
fa9106
+
fa9106
+  if (chdir (s) < 0)
fa9106
     {
fa9106
-      fprintf (stderr, "Could not change to root directory: %s\n",
fa9106
-               strerror (errno));
fa9106
+      fprintf (stderr, "Could not change to working directory \"%s\": %s\n",
fa9106
+               s, strerror (errno));
fa9106
       exit (1);
fa9106
     }
fa9106
 
fa9106
   /* Close stdout/stderr so we don't block an "eval" or otherwise
fa9106
    * lock up. stdout is still chaining through to dbus-launch
fa9106
    * and in turn to the parent shell.
fa9106
    */
fa9106
   dev_null_fd = open ("/dev/null", O_RDWR);
fa9106
   if (dev_null_fd >= 0)
fa9106
     {
fa9106
       if (!exit_with_session)
fa9106
         dup2 (dev_null_fd, 0);
fa9106
       dup2 (dev_null_fd, 1);
fa9106
       s = getenv ("DBUS_DEBUG_OUTPUT");
fa9106
       if (s == NULL || *s == '\0')
fa9106
         dup2 (dev_null_fd, 2);
fa9106
       close (dev_null_fd);
fa9106
     }
fa9106
   else
fa9106
     {
fa9106
       fprintf (stderr, "Failed to open /dev/null: %s\n",
fa9106
                strerror (errno));
fa9106
       /* continue, why not */
fa9106
     }
fa9106
   
fa9106
   ret = fork ();
fa9106
 
fa9106
   if (ret < 0)
fa9106
     {
fa9106
       fprintf (stderr, "fork() failed in babysitter: %s\n",
fa9106
-- 
fa9106
2.17.1
fa9106