[daemon-fix] Changed the way of make bus address when the address is not given
[platform/upstream/dbus.git] / dbus / dbus-sysdeps-unix.c
index 29d234a..1cb4a58 100644 (file)
@@ -1,11 +1,11 @@
 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 /* dbus-sysdeps-unix.c Wrappers around UNIX system/libc features (internal to D-Bus implementation)
- * 
+ *
  * Copyright (C) 2002, 2003, 2006  Red Hat, Inc.
  * Copyright (C) 2003 CodeFactory AB
  *
  * Licensed under the Academic Free License version 2.1
- * 
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
 
-#define _GNU_SOURCE 
+#include <config.h>
 
 #include "dbus-internals.h"
 #include "dbus-sysdeps.h"
@@ -34,6 +34,7 @@
 #include "dbus-userdb.h"
 #include "dbus-list.h"
 #include "dbus-credentials.h"
+#include "dbus-nonce.h"
 
 #include <sys/types.h>
 #include <stdlib.h>
@@ -54,6 +55,7 @@
 #include <netinet/in.h>
 #include <netdb.h>
 #include <grp.h>
+#include <arpa/inet.h>
 
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
 #ifdef HAVE_GETPEERUCRED
 #include <ucred.h>
 #endif
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
 
 #ifdef HAVE_ADT
 #include <bsm/adt.h>
 #endif
 
+#include "sd-daemon.h"
+
+#if !DBUS_USE_SYNC
+#include <pthread.h>
+#endif
+
 #ifndef O_BINARY
 #define O_BINARY 0
 #endif
 #define socklen_t int
 #endif
 
+#if defined (__sun) || defined (__sun__)
+/*
+ * CMS_SPACE etc. definitions for Solaris < 10, based on
+ *   http://mailman.videolan.org/pipermail/vlc-devel/2006-May/024402.html
+ * via
+ *   http://wiki.opencsw.org/porting-faq#toc10
+ *
+ * These are only redefined for Solaris, for now: if your OS needs these too,
+ * please file a bug. (Or preferably, improve your OS so they're not needed.)
+ */
+
+# ifndef CMSG_ALIGN
+#   ifdef __sun__
+#     define CMSG_ALIGN(len) _CMSG_DATA_ALIGN (len)
+#   else
+      /* aligning to sizeof (long) is assumed to be portable (fd.o#40235) */
+#     define CMSG_ALIGN(len) (((len) + sizeof (long) - 1) & \
+                              ~(sizeof (long) - 1))
+#   endif
+# endif
+
+# ifndef CMSG_SPACE
+#   define CMSG_SPACE(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + \
+                            CMSG_ALIGN (len))
+# endif
+
+# ifndef CMSG_LEN
+#   define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len))
+# endif
+
+#endif /* Solaris */
+
 static dbus_bool_t
 _dbus_open_socket (int              *fd_p,
                    int               domain,
@@ -94,9 +137,28 @@ _dbus_open_socket (int              *fd_p,
                    int               protocol,
                    DBusError        *error)
 {
-  *fd_p = socket (domain, type, protocol);
+#ifdef SOCK_CLOEXEC
+  dbus_bool_t cloexec_done;
+
+  *fd_p = socket (domain, type | SOCK_CLOEXEC, protocol);
+  cloexec_done = *fd_p >= 0;
+
+  /* Check if kernel seems to be too old to know SOCK_CLOEXEC */
+  if (*fd_p < 0 && errno == EINVAL)
+#endif
+    {
+      *fd_p = socket (domain, type, protocol);
+    }
+
   if (*fd_p >= 0)
     {
+#ifdef SOCK_CLOEXEC
+      if (!cloexec_done)
+#endif
+        {
+          _dbus_fd_set_close_on_exec(*fd_p);
+        }
+
       _dbus_verbose ("socket fd %d opened\n", *fd_p);
       return TRUE;
     }
@@ -110,21 +172,17 @@ _dbus_open_socket (int              *fd_p,
     }
 }
 
-dbus_bool_t
-_dbus_open_tcp_socket (int              *fd,
-                       DBusError        *error)
-{
-  return _dbus_open_socket(fd, AF_INET, SOCK_STREAM, 0, error);
-}
-
 /**
  * Opens a UNIX domain socket (as in the socket() call).
  * Does not bind the socket.
+ *
+ * This will set FD_CLOEXEC for the socket returned
+ *
  * @param fd return location for socket descriptor
  * @param error return location for an error
  * @returns #FALSE if error is set
  */
-dbus_bool_t
+static dbus_bool_t
 _dbus_open_unix_socket (int              *fd,
                         DBusError        *error)
 {
@@ -139,7 +197,7 @@ _dbus_open_unix_socket (int              *fd,
  * @param error return location for an error
  * @returns #FALSE if error is set
  */
-dbus_bool_t 
+dbus_bool_t
 _dbus_close_socket (int               fd,
                     DBusError        *error)
 {
@@ -179,64 +237,265 @@ _dbus_write_socket (int               fd,
                     int               start,
                     int               len)
 {
+#if HAVE_DECL_MSG_NOSIGNAL
+  const char *data;
+  int bytes_written;
+
+  data = _dbus_string_get_const_data_len (buffer, start, len);
+
+ again:
+
+  bytes_written = send (fd, data, len, MSG_NOSIGNAL);
+
+  if (bytes_written < 0 && errno == EINTR)
+    goto again;
+
+  return bytes_written;
+
+#else
   return _dbus_write (fd, buffer, start, len);
+#endif
 }
 
 /**
- * write data to a pipe.
+ * Like _dbus_read_socket() but also tries to read unix fds from the
+ * socket. When there are more fds to read than space in the array
+ * passed this function will fail with ENOSPC.
  *
- * @param pipe the pipe instance
- * @param buffer the buffer to write data from
- * @param start the first byte in the buffer to write
- * @param len the number of bytes to try to write
- * @param error error return
- * @returns the number of bytes written or -1 on error
+ * @param fd the socket
+ * @param buffer string to append data to
+ * @param count max amount of data to read
+ * @param fds array to place read file descriptors in
+ * @param n_fds on input space in fds array, on output how many fds actually got read
+ * @returns number of bytes appended to string
  */
 int
-_dbus_pipe_write (DBusPipe         *pipe,
-                  const DBusString *buffer,
-                  int               start,
-                  int               len,
-                  DBusError        *error)
-{
-  int written;
-  
-  written = _dbus_write (pipe->fd_or_handle, buffer, start, len);
-  if (written < 0)
+_dbus_read_socket_with_unix_fds (int               fd,
+                                 DBusString       *buffer,
+                                 int               count,
+                                 int              *fds,
+                                 int              *n_fds) {
+#ifndef HAVE_UNIX_FD_PASSING
+  int r;
+
+  if ((r = _dbus_read_socket(fd, buffer, count)) < 0)
+    return r;
+
+  *n_fds = 0;
+  return r;
+
+#else
+  int bytes_read;
+  int start;
+  struct msghdr m;
+  struct iovec iov;
+
+  _dbus_assert (count >= 0);
+  _dbus_assert (*n_fds >= 0);
+
+  start = _dbus_string_get_length (buffer);
+
+  if (!_dbus_string_lengthen (buffer, count))
     {
-      dbus_set_error (error, DBUS_ERROR_FAILED,
-                      "Writing to pipe: %s\n",
-                      _dbus_strerror (errno));
+      errno = ENOMEM;
+      return -1;
+    }
+
+  _DBUS_ZERO(iov);
+  iov.iov_base = _dbus_string_get_data_len (buffer, start, count);
+  iov.iov_len = count;
+
+  _DBUS_ZERO(m);
+  m.msg_iov = &iov;
+  m.msg_iovlen = 1;
+
+  /* Hmm, we have no clue how long the control data will actually be
+     that is queued for us. The least we can do is assume that the
+     caller knows. Hence let's make space for the number of fds that
+     we shall read at max plus the cmsg header. */
+  m.msg_controllen = CMSG_SPACE(*n_fds * sizeof(int));
+
+  /* It's probably safe to assume that systems with SCM_RIGHTS also
+     know alloca() */
+  m.msg_control = alloca(m.msg_controllen);
+  memset(m.msg_control, 0, m.msg_controllen);
+
+ again:
+
+  bytes_read = recvmsg(fd, &m, 0
+#ifdef MSG_CMSG_CLOEXEC
+                       |MSG_CMSG_CLOEXEC
+#endif
+                       );
+
+  if (bytes_read < 0)
+    {
+      if (errno == EINTR)
+        goto again;
+      else
+        {
+          /* put length back (note that this doesn't actually realloc anything) */
+          _dbus_string_set_length (buffer, start);
+          return -1;
+        }
+    }
+  else
+    {
+      struct cmsghdr *cm;
+      dbus_bool_t found = FALSE;
+
+      if (m.msg_flags & MSG_CTRUNC)
+        {
+          /* Hmm, apparently the control data was truncated. The bad
+             thing is that we might have completely lost a couple of fds
+             without chance to recover them. Hence let's treat this as a
+             serious error. */
+
+          errno = ENOSPC;
+          _dbus_string_set_length (buffer, start);
+          return -1;
+        }
+
+      for (cm = CMSG_FIRSTHDR(&m); cm; cm = CMSG_NXTHDR(&m, cm))
+        if (cm->cmsg_level == SOL_SOCKET && cm->cmsg_type == SCM_RIGHTS)
+          {
+            unsigned i;
+
+            _dbus_assert(cm->cmsg_len <= CMSG_LEN(*n_fds * sizeof(int)));
+            *n_fds = (cm->cmsg_len - CMSG_LEN(0)) / sizeof(int);
+
+            memcpy(fds, CMSG_DATA(cm), *n_fds * sizeof(int));
+            found = TRUE;
+
+            /* Linux doesn't tell us whether MSG_CMSG_CLOEXEC actually
+               worked, hence we need to go through this list and set
+               CLOEXEC everywhere in any case */
+            for (i = 0; i < *n_fds; i++)
+              _dbus_fd_set_close_on_exec(fds[i]);
+
+            break;
+          }
+
+      if (!found)
+        *n_fds = 0;
+
+      /* put length back (doesn't actually realloc) */
+      _dbus_string_set_length (buffer, start + bytes_read);
+
+#if 0
+      if (bytes_read > 0)
+        _dbus_verbose_bytes_of_string (buffer, start, bytes_read);
+#endif
+
+      return bytes_read;
     }
-  return written;
+#endif
 }
 
-/**
- * close a pipe.
- *
- * @param pipe the pipe instance
- * @param error return location for an error
- * @returns #FALSE if error is set
- */
 int
-_dbus_pipe_close  (DBusPipe         *pipe,
-                   DBusError        *error)
-{
-  if (_dbus_close (pipe->fd_or_handle, error) < 0)
+_dbus_write_socket_with_unix_fds(int               fd,
+                                 const DBusString *buffer,
+                                 int               start,
+                                 int               len,
+                                 const int        *fds,
+                                 int               n_fds) {
+
+#ifndef HAVE_UNIX_FD_PASSING
+
+  if (n_fds > 0) {
+    errno = ENOTSUP;
+    return -1;
+  }
+
+  return _dbus_write_socket(fd, buffer, start, len);
+#else
+  return _dbus_write_socket_with_unix_fds_two(fd, buffer, start, len, NULL, 0, 0, fds, n_fds);
+#endif
+}
+
+int
+_dbus_write_socket_with_unix_fds_two(int               fd,
+                                     const DBusString *buffer1,
+                                     int               start1,
+                                     int               len1,
+                                     const DBusString *buffer2,
+                                     int               start2,
+                                     int               len2,
+                                     const int        *fds,
+                                     int               n_fds) {
+
+#ifndef HAVE_UNIX_FD_PASSING
+
+  if (n_fds > 0) {
+    errno = ENOTSUP;
+    return -1;
+  }
+
+  return _dbus_write_socket_two(fd,
+                                buffer1, start1, len1,
+                                buffer2, start2, len2);
+#else
+
+  struct msghdr m;
+  struct cmsghdr *cm;
+  struct iovec iov[2];
+  int bytes_written;
+
+  _dbus_assert (len1 >= 0);
+  _dbus_assert (len2 >= 0);
+  _dbus_assert (n_fds >= 0);
+
+  _DBUS_ZERO(iov);
+  iov[0].iov_base = (char*) _dbus_string_get_const_data_len (buffer1, start1, len1);
+  iov[0].iov_len = len1;
+
+  if (buffer2)
     {
-      return -1;
+      iov[1].iov_base = (char*) _dbus_string_get_const_data_len (buffer2, start2, len2);
+      iov[1].iov_len = len2;
     }
-  else
+
+  _DBUS_ZERO(m);
+  m.msg_iov = iov;
+  m.msg_iovlen = buffer2 ? 2 : 1;
+
+  if (n_fds > 0)
     {
-      _dbus_pipe_invalidate (pipe);
-      return 0;
+      m.msg_controllen = CMSG_SPACE(n_fds * sizeof(int));
+      m.msg_control = alloca(m.msg_controllen);
+      memset(m.msg_control, 0, m.msg_controllen);
+
+      cm = CMSG_FIRSTHDR(&m);
+      cm->cmsg_level = SOL_SOCKET;
+      cm->cmsg_type = SCM_RIGHTS;
+      cm->cmsg_len = CMSG_LEN(n_fds * sizeof(int));
+      memcpy(CMSG_DATA(cm), fds, n_fds * sizeof(int));
     }
+
+ again:
+
+  bytes_written = sendmsg (fd, &m, 0
+#if HAVE_DECL_MSG_NOSIGNAL
+                           |MSG_NOSIGNAL
+#endif
+                           );
+
+  if (bytes_written < 0 && errno == EINTR)
+    goto again;
+
+#if 0
+  if (bytes_written > 0)
+    _dbus_verbose_bytes_of_string (buffer, start, bytes_written);
+#endif
+
+  return bytes_written;
+#endif
 }
 
 /**
  * Like _dbus_write_two() but only works on sockets and is thus
  * available on Windows.
- * 
+ *
  * @param fd the file descriptor
  * @param buffer1 first buffer
  * @param start1 first byte to write in first buffer
@@ -255,10 +514,59 @@ _dbus_write_socket_two (int               fd,
                         int               start2,
                         int               len2)
 {
+#if HAVE_DECL_MSG_NOSIGNAL
+  struct iovec vectors[2];
+  const char *data1;
+  const char *data2;
+  int bytes_written;
+  struct msghdr m;
+
+  _dbus_assert (buffer1 != NULL);
+  _dbus_assert (start1 >= 0);
+  _dbus_assert (start2 >= 0);
+  _dbus_assert (len1 >= 0);
+  _dbus_assert (len2 >= 0);
+
+  data1 = _dbus_string_get_const_data_len (buffer1, start1, len1);
+
+  if (buffer2 != NULL)
+    data2 = _dbus_string_get_const_data_len (buffer2, start2, len2);
+  else
+    {
+      data2 = NULL;
+      start2 = 0;
+      len2 = 0;
+    }
+
+  vectors[0].iov_base = (char*) data1;
+  vectors[0].iov_len = len1;
+  vectors[1].iov_base = (char*) data2;
+  vectors[1].iov_len = len2;
+
+  _DBUS_ZERO(m);
+  m.msg_iov = vectors;
+  m.msg_iovlen = data2 ? 2 : 1;
+
+ again:
+
+  bytes_written = sendmsg (fd, &m, MSG_NOSIGNAL);
+
+  if (bytes_written < 0 && errno == EINTR)
+    goto again;
+
+  return bytes_written;
+
+#else
   return _dbus_write_two (fd, buffer1, start1, len1,
                           buffer2, start2, len2);
+#endif
 }
 
+dbus_bool_t
+_dbus_socket_is_invalid (int fd)
+{
+    return fd < 0 ? TRUE : FALSE;
+}
 
 /**
  * Thin wrapper around the read() system call that appends
@@ -270,7 +578,7 @@ _dbus_write_socket_two (int               fd,
  *
  * Unlike _dbus_read_socket(), _dbus_read() is not available
  * on Windows.
- * 
+ *
  * @param fd the file descriptor to read from
  * @param buffer the buffer to append data to
  * @param count the amount of data to read
@@ -286,7 +594,7 @@ _dbus_read (int               fd,
   char *data;
 
   _dbus_assert (count >= 0);
-  
+
   start = _dbus_string_get_length (buffer);
 
   if (!_dbus_string_lengthen (buffer, count))
@@ -298,7 +606,7 @@ _dbus_read (int               fd,
   data = _dbus_string_get_data_len (buffer, start, count);
 
  again:
-  
+
   bytes_read = read (fd, data, count);
 
   if (bytes_read < 0)
@@ -321,7 +629,7 @@ _dbus_read (int               fd,
       if (bytes_read > 0)
         _dbus_verbose_bytes_of_string (buffer, start, bytes_read);
 #endif
-      
+
       return bytes_read;
     }
 }
@@ -329,7 +637,7 @@ _dbus_read (int               fd,
 /**
  * Thin wrapper around the write() system call that writes a part of a
  * DBusString and handles EINTR for you.
- * 
+ *
  * @param fd the file descriptor to write
  * @param buffer the buffer to write data from
  * @param start the first byte in the buffer to write
@@ -344,9 +652,9 @@ _dbus_write (int               fd,
 {
   const char *data;
   int bytes_written;
-  
+
   data = _dbus_string_get_const_data_len (buffer, start, len);
-  
+
  again:
 
   bytes_written = write (fd, data, len);
@@ -358,7 +666,7 @@ _dbus_write (int               fd,
   if (bytes_written > 0)
     _dbus_verbose_bytes_of_string (buffer, start, bytes_written);
 #endif
-  
+
   return bytes_written;
 }
 
@@ -396,7 +704,7 @@ _dbus_write_two (int               fd,
   _dbus_assert (start2 >= 0);
   _dbus_assert (len1 >= 0);
   _dbus_assert (len2 >= 0);
-  
+
 #ifdef HAVE_WRITEV
   {
     struct iovec vectors[2];
@@ -414,40 +722,40 @@ _dbus_write_two (int               fd,
         start2 = 0;
         len2 = 0;
       }
-   
+
     vectors[0].iov_base = (char*) data1;
     vectors[0].iov_len = len1;
     vectors[1].iov_base = (char*) data2;
     vectors[1].iov_len = len2;
 
   again:
-   
+
     bytes_written = writev (fd,
                             vectors,
                             data2 ? 2 : 1);
 
     if (bytes_written < 0 && errno == EINTR)
       goto again;
-   
+
     return bytes_written;
   }
 #else /* HAVE_WRITEV */
   {
     int ret1;
-    
+
     ret1 = _dbus_write (fd, buffer1, start1, len1);
     if (ret1 == len1 && buffer2 != NULL)
       {
         ret2 = _dbus_write (fd, buffer2, start2, len2);
         if (ret2 < 0)
           ret2 = 0; /* we can't report an error as the first write was OK */
-       
+
         return ret1 + ret2;
       }
     else
       return ret1;
   }
-#endif /* !HAVE_WRITEV */   
+#endif /* !HAVE_WRITEV */
 }
 
 #define _DBUS_MAX_SUN_PATH_LENGTH 99
@@ -469,11 +777,13 @@ _dbus_write_two (int               fd,
  * Creates a socket and connects it to the UNIX domain socket at the
  * given path.  The connection fd is returned, and is set up as
  * nonblocking.
- * 
+ *
  * Uses abstract sockets instead of filesystem-linked sockets if
  * requested (it's possible only on Linux; see "man 7 unix" on Linux).
  * On non-Linux abstract socket usage always fails.
  *
+ * This will set FD_CLOEXEC for the socket returned.
+ *
  * @param path the path to UNIX domain socket
  * @param abstract #TRUE to use abstract namespace
  * @param error return location for error code
@@ -486,14 +796,14 @@ _dbus_connect_unix_socket (const char     *path,
 {
   int fd;
   size_t path_len;
-  struct sockaddr_un addr;  
+  struct sockaddr_un addr;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
   _dbus_verbose ("connecting to unix socket %s abstract=%d\n",
                  path, abstract);
-  
-  
+
+
   if (!_dbus_open_unix_socket (&fd, error))
     {
       _DBUS_ASSERT_ERROR_IS_SET(error);
@@ -518,7 +828,7 @@ _dbus_connect_unix_socket (const char     *path,
           _dbus_close (fd, NULL);
           return -1;
        }
-       
+
       strncpy (&addr.sun_path[1], path, path_len);
       /* _dbus_verbose_bytes (addr.sun_path, sizeof (addr.sun_path)); */
 #else /* HAVE_ABSTRACT_SOCKETS */
@@ -540,27 +850,23 @@ _dbus_connect_unix_socket (const char     *path,
 
       strncpy (addr.sun_path, path, path_len);
     }
-  
+
   if (connect (fd, (struct sockaddr*) &addr, _DBUS_STRUCT_OFFSET (struct sockaddr_un, sun_path) + path_len) < 0)
-    {      
+    {
       dbus_set_error (error,
                       _dbus_error_from_errno (errno),
                       "Failed to connect to socket %s: %s",
                       path, _dbus_strerror (errno));
 
       _dbus_close (fd, NULL);
-      fd = -1;
-      
       return -1;
     }
 
   if (!_dbus_set_fd_nonblocking (fd, error))
     {
       _DBUS_ASSERT_ERROR_IS_SET (error);
-      
-      _dbus_close (fd, NULL);
-      fd = -1;
 
+      _dbus_close (fd, NULL);
       return -1;
     }
 
@@ -568,37 +874,127 @@ _dbus_connect_unix_socket (const char     *path,
 }
 
 /**
- * Enables or disables the reception of credentials on the given socket during
- * the next message transmission.  This is only effective if the #LOCAL_CREDS
- * system feature exists, in which case the other side of the connection does
- * not have to do anything special to send the credentials.
+ * Creates a UNIX domain socket and connects it to the specified
+ * process to execute.
  *
- * @param fd socket on which to change the #LOCAL_CREDS flag.
- * @param on whether to enable or disable the #LOCAL_CREDS flag.
+ * This will set FD_CLOEXEC for the socket returned.
+ *
+ * @param path the path to the executable
+ * @param argv the argument list for the process to execute.
+ * argv[0] typically is identical to the path of the executable
+ * @param error return location for error code
+ * @returns connection file descriptor or -1 on error
  */
-static dbus_bool_t
-_dbus_set_local_creds (int fd, dbus_bool_t on)
+int
+_dbus_connect_exec (const char     *path,
+                    char *const    argv[],
+                    DBusError      *error)
 {
-  dbus_bool_t retval = TRUE;
+  int fds[2];
+  pid_t pid;
 
-#if defined(HAVE_CMSGCRED)
-  /* NOOP just to make sure only one codepath is used 
-   *      and to prefer CMSGCRED
-   */
-#elif defined(LOCAL_CREDS) 
-  int val = on ? 1 : 0;
-  if (setsockopt (fd, 0, LOCAL_CREDS, &val, sizeof (val)) < 0)
+  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+  _dbus_verbose ("connecting to process %s\n", path);
+
+  if (socketpair (AF_UNIX, SOCK_STREAM
+#ifdef SOCK_CLOEXEC
+                  |SOCK_CLOEXEC
+#endif
+                  , 0, fds) < 0)
     {
-      _dbus_verbose ("Unable to set LOCAL_CREDS socket option on fd %d\n", fd);
-      retval = FALSE;
+      dbus_set_error (error,
+                      _dbus_error_from_errno (errno),
+                      "Failed to create socket pair: %s",
+                      _dbus_strerror (errno));
+      return -1;
     }
-  else
-    _dbus_verbose ("LOCAL_CREDS %s for further messages on fd %d\n",
-                   on ? "enabled" : "disabled", fd);
-#endif
 
-  return retval;
-}
+  _dbus_fd_set_close_on_exec (fds[0]);
+  _dbus_fd_set_close_on_exec (fds[1]);
+
+  pid = fork ();
+  if (pid < 0)
+    {
+      dbus_set_error (error,
+                      _dbus_error_from_errno (errno),
+                      "Failed to fork() to call %s: %s",
+                      path, _dbus_strerror (errno));
+      close (fds[0]);
+      close (fds[1]);
+      return -1;
+    }
+
+  if (pid == 0)
+    {
+      /* child */
+      close (fds[0]);
+
+      dup2 (fds[1], STDIN_FILENO);
+      dup2 (fds[1], STDOUT_FILENO);
+
+      if (fds[1] != STDIN_FILENO &&
+          fds[1] != STDOUT_FILENO)
+        close (fds[1]);
+
+      /* Inherit STDERR and the controlling terminal from the
+         parent */
+
+      _dbus_close_all ();
+
+      execvp (path, argv);
+
+      fprintf (stderr, "Failed to execute process %s: %s\n", path, _dbus_strerror (errno));
+
+      _exit(1);
+    }
+
+  /* parent */
+  close (fds[1]);
+
+  if (!_dbus_set_fd_nonblocking (fds[0], error))
+    {
+      _DBUS_ASSERT_ERROR_IS_SET (error);
+
+      close (fds[0]);
+      return -1;
+    }
+
+  return fds[0];
+}
+
+/**
+ * Enables or disables the reception of credentials on the given socket during
+ * the next message transmission.  This is only effective if the #LOCAL_CREDS
+ * system feature exists, in which case the other side of the connection does
+ * not have to do anything special to send the credentials.
+ *
+ * @param fd socket on which to change the #LOCAL_CREDS flag.
+ * @param on whether to enable or disable the #LOCAL_CREDS flag.
+ */
+static dbus_bool_t
+_dbus_set_local_creds (int fd, dbus_bool_t on)
+{
+  dbus_bool_t retval = TRUE;
+
+#if defined(HAVE_CMSGCRED)
+  /* NOOP just to make sure only one codepath is used
+   *      and to prefer CMSGCRED
+   */
+#elif defined(LOCAL_CREDS)
+  int val = on ? 1 : 0;
+  if (setsockopt (fd, 0, LOCAL_CREDS, &val, sizeof (val)) < 0)
+    {
+      _dbus_verbose ("Unable to set LOCAL_CREDS socket option on fd %d\n", fd);
+      retval = FALSE;
+    }
+  else
+    _dbus_verbose ("LOCAL_CREDS %s for further messages on fd %d\n",
+                   on ? "enabled" : "disabled", fd);
+#endif
+
+  return retval;
+}
 
 /**
  * Creates a socket and binds it to the given path,
@@ -610,6 +1006,8 @@ _dbus_set_local_creds (int fd, dbus_bool_t on)
  * see "man 7 unix" on Linux).
  * On non-Linux abstract socket usage always fails.
  *
+ * This will set FD_CLOEXEC for the socket returned
+ *
  * @param path the socket name
  * @param abstract #TRUE to use abstract namespace
  * @param error return location for errors
@@ -623,12 +1021,13 @@ _dbus_listen_unix_socket (const char     *path,
   int listen_fd;
   struct sockaddr_un addr;
   size_t path_len;
+  unsigned int reuseaddr;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
   _dbus_verbose ("listening on unix socket %s abstract=%d\n",
                  path, abstract);
-  
+
   if (!_dbus_open_unix_socket (&listen_fd, error))
     {
       _DBUS_ASSERT_ERROR_IS_SET(error);
@@ -639,7 +1038,7 @@ _dbus_listen_unix_socket (const char     *path,
   _DBUS_ZERO (addr);
   addr.sun_family = AF_UNIX;
   path_len = strlen (path);
-  
+
   if (abstract)
     {
 #ifdef HAVE_ABSTRACT_SOCKETS
@@ -656,7 +1055,7 @@ _dbus_listen_unix_socket (const char     *path,
           _dbus_close (listen_fd, NULL);
           return -1;
        }
-      
+
       strncpy (&addr.sun_path[1], path, path_len);
       /* _dbus_verbose_bytes (addr.sun_path, sizeof (addr.sun_path)); */
 #else /* HAVE_ABSTRACT_SOCKETS */
@@ -693,10 +1092,17 @@ _dbus_listen_unix_socket (const char     *path,
           _dbus_close (listen_fd, NULL);
           return -1;
        }
-       
+
       strncpy (addr.sun_path, path, path_len);
     }
-  
+
+  reuseaddr = 1;
+  if (setsockopt  (listen_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr))==-1)
+    {
+      _dbus_warn ("Failed to set socket option\"%s\": %s",
+                  path, _dbus_strerror (errno));
+    }
+
   if (bind (listen_fd, (struct sockaddr*) &addr, _DBUS_STRUCT_OFFSET (struct sockaddr_un, sun_path) + path_len) < 0)
     {
       dbus_set_error (error, _dbus_error_from_errno (errno),
@@ -730,22 +1136,123 @@ _dbus_listen_unix_socket (const char     *path,
       _dbus_close (listen_fd, NULL);
       return -1;
     }
-  
+
   /* Try opening up the permissions, but if we can't, just go ahead
    * and continue, maybe it will be good enough.
    */
   if (!abstract && chmod (path, 0777) < 0)
     _dbus_warn ("Could not set mode 0777 on socket %s\n",
                 path);
-  
+
   return listen_fd;
 }
 
 /**
- * Creates a socket and connects to a socket at the given host 
+ * Acquires one or more sockets passed in from systemd. The sockets
+ * are set to be nonblocking.
+ *
+ * This will set FD_CLOEXEC for the sockets returned.
+ *
+ * @param fds the file descriptors
+ * @param error return location for errors
+ * @returns the number of file descriptors
+ */
+int
+_dbus_listen_systemd_sockets (int       **fds,
+                              DBusError *error)
+{
+  int r, n;
+  unsigned fd;
+  int *new_fds;
+
+  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+  n = sd_listen_fds (TRUE);
+  if (n < 0)
+    {
+      dbus_set_error (error, _dbus_error_from_errno (-n),
+                      "Failed to acquire systemd socket: %s",
+                      _dbus_strerror (-n));
+      return -1;
+    }
+
+  if (n <= 0)
+    {
+      dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
+                      "No socket received.");
+      return -1;
+    }
+
+  for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++)
+    {
+      r = sd_is_socket (fd, AF_UNSPEC, SOCK_STREAM, 1);
+      if (r < 0)
+        {
+          dbus_set_error (error, _dbus_error_from_errno (-r),
+                          "Failed to verify systemd socket type: %s",
+                          _dbus_strerror (-r));
+          return -1;
+        }
+
+      if (!r)
+        {
+          dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
+                          "Passed socket has wrong type.");
+          return -1;
+        }
+    }
+
+  /* OK, the file descriptors are all good, so let's take posession of
+     them then. */
+
+  new_fds = dbus_new (int, n);
+  if (!new_fds)
+    {
+      dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
+                      "Failed to allocate file handle array.");
+      goto fail;
+    }
+
+  for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++)
+    {
+      if (!_dbus_set_local_creds (fd, TRUE))
+        {
+          dbus_set_error (error, _dbus_error_from_errno (errno),
+                          "Failed to enable LOCAL_CREDS on systemd socket: %s",
+                          _dbus_strerror (errno));
+          goto fail;
+        }
+
+      if (!_dbus_set_fd_nonblocking (fd, error))
+        {
+          _DBUS_ASSERT_ERROR_IS_SET (error);
+          goto fail;
+        }
+
+      new_fds[fd - SD_LISTEN_FDS_START] = fd;
+    }
+
+  *fds = new_fds;
+  return n;
+
+ fail:
+
+  for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++)
+    {
+      _dbus_close (fd, NULL);
+    }
+
+  dbus_free (new_fds);
+  return -1;
+}
+
+/**
+ * Creates a socket and connects to a socket at the given host
  * and port. The connection fd is returned, and is set up as
  * nonblocking.
  *
+ * This will set FD_CLOEXEC for the socket returned
+ *
  * @param host the host name to connect to
  * @param port the port to connect to
  * @param family the address family to listen on, NULL for all
@@ -758,19 +1265,21 @@ _dbus_connect_tcp_socket (const char     *host,
                           const char     *family,
                           DBusError      *error)
 {
+    return _dbus_connect_tcp_socket_with_nonce (host, port, family, (const char*)NULL, error);
+}
+
+int
+_dbus_connect_tcp_socket_with_nonce (const char     *host,
+                                     const char     *port,
+                                     const char     *family,
+                                     const char     *noncefile,
+                                     DBusError      *error)
+{
   int saved_errno = 0;
   int fd = -1, res;
   struct addrinfo hints;
   struct addrinfo *ai, *tmp;
 
-  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-
-  if (!_dbus_open_tcp_socket (&fd, error))
-    {
-      _DBUS_ASSERT_ERROR_IS_SET(error);
-      return -1;
-    }
-
   _DBUS_ASSERT_ERROR_IS_CLEAR(error);
 
   _DBUS_ZERO (hints);
@@ -798,7 +1307,6 @@ _dbus_connect_tcp_socket (const char     *host,
                       _dbus_error_from_errno (errno),
                       "Failed to lookup host/port: \"%s:%s\": %s (%d)",
                       host, port, gai_strerror(res), res);
-      _dbus_close (fd, NULL);
       return -1;
     }
 
@@ -835,12 +1343,24 @@ _dbus_connect_tcp_socket (const char     *host,
       return -1;
     }
 
+  if (noncefile != NULL)
+    {
+      DBusString noncefileStr;
+      dbus_bool_t ret;
+      _dbus_string_init_const (&noncefileStr, noncefile);
+      ret = _dbus_send_nonce (fd, &noncefileStr, error);
+      _dbus_string_free (&noncefileStr);
 
-  if (!_dbus_set_fd_nonblocking (fd, error))
+      if (!ret)
     {
       _dbus_close (fd, NULL);
-      fd = -1;
+          return -1;
+        }
+    }
 
+  if (!_dbus_set_fd_nonblocking (fd, error))
+    {
+      _dbus_close (fd, NULL);
       return -1;
     }
 
@@ -853,6 +1373,8 @@ _dbus_connect_tcp_socket (const char     *host,
  * a random free port is used and returned in the port parameter.
  * If inaddr_any is specified, the hostname is ignored.
  *
+ * This will set FD_CLOEXEC for the socket returned
+ *
  * @param host the host name to listen on
  * @param port the port to listen on, if zero a free port will be used
  * @param family the address family to listen on, NULL for all
@@ -873,6 +1395,7 @@ _dbus_listen_tcp_socket (const char     *host,
   int nlisten_fd = 0, *listen_fd = NULL, res, i;
   struct addrinfo hints;
   struct addrinfo *ai, *tmp;
+  unsigned int reuseaddr;
 
   *fds_p = NULL;
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
@@ -898,13 +1421,14 @@ _dbus_listen_tcp_socket (const char     *host,
   hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE;
 
  redo_lookup_with_port:
+  ai = NULL;
   if ((res = getaddrinfo(host, port, &hints, &ai)) != 0 || !ai)
     {
       dbus_set_error (error,
                       _dbus_error_from_errno (errno),
                       "Failed to lookup host/port: \"%s:%s\": %s (%d)",
                       host ? host : "*", port, gai_strerror(res), res);
-      return -1;
+      goto failed;
     }
 
   tmp = ai;
@@ -918,6 +1442,13 @@ _dbus_listen_tcp_socket (const char     *host,
         }
       _DBUS_ASSERT_ERROR_IS_CLEAR(error);
 
+      reuseaddr = 1;
+      if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr))==-1)
+        {
+          _dbus_warn ("Failed to set socket option \"%s:%s\": %s",
+                      host ? host : "*", port, _dbus_strerror (errno));
+        }
+
       if (bind (fd, (struct sockaddr*) tmp->ai_addr, tmp->ai_addrlen) < 0)
         {
           saved_errno = errno;
@@ -968,16 +1499,18 @@ _dbus_listen_tcp_socket (const char     *host,
              to use the same port */
           if (!port || !strcmp(port, "0"))
             {
+              int result;
               struct sockaddr_storage addr;
               socklen_t addrlen;
               char portbuf[50];
 
               addrlen = sizeof(addr);
-              getsockname(fd, (struct sockaddr*) &addr, &addrlen);
+              result = getsockname(fd, (struct sockaddr*) &addr, &addrlen);
 
-              if ((res = getnameinfo((struct sockaddr*)&addr, addrlen, NULL, 0,
-                                     portbuf, sizeof(portbuf),
-                                     NI_NUMERICHOST)) != 0)
+              if (result == -1 ||
+                  (res = getnameinfo ((struct sockaddr*)&addr, addrlen, NULL, 0,
+                                      portbuf, sizeof(portbuf),
+                                      NI_NUMERICHOST)) != 0)
                 {
                   dbus_set_error (error, _dbus_error_from_errno (errno),
                                   "Failed to resolve port \"%s:%s\": %s (%s)",
@@ -1016,7 +1549,7 @@ _dbus_listen_tcp_socket (const char     *host,
       dbus_set_error (error, _dbus_error_from_errno (errno),
                       "Failed to bind socket \"%s:%s\": %s",
                       host ? host : "*", port, _dbus_strerror (errno));
-      return -1;
+      goto failed;
     }
 
   for (i = 0 ; i < nlisten_fd ; i++)
@@ -1046,36 +1579,44 @@ write_credentials_byte (int             server_fd,
 {
   int bytes_written;
   char buf[1] = { '\0' };
-#if defined(HAVE_CMSGCRED) 
-  struct {
+#if defined(HAVE_CMSGCRED)
+  union {
          struct cmsghdr hdr;
-         struct cmsgcred cred;
+         char cred[CMSG_SPACE (sizeof (struct cmsgcred))];
   } cmsg;
   struct iovec iov;
   struct msghdr msg;
   iov.iov_base = buf;
   iov.iov_len = 1;
 
-  memset (&msg, 0, sizeof (msg));
+  _DBUS_ZERO(msg);
   msg.msg_iov = &iov;
   msg.msg_iovlen = 1;
 
-  msg.msg_control = &cmsg;
-  msg.msg_controllen = sizeof (cmsg);
-  memset (&cmsg, 0, sizeof (cmsg));
-  cmsg.hdr.cmsg_len = sizeof (cmsg);
+  msg.msg_control = (caddr_t) &cmsg;
+  msg.msg_controllen = CMSG_SPACE (sizeof (struct cmsgcred));
+  _DBUS_ZERO(cmsg);
+  cmsg.hdr.cmsg_len = CMSG_LEN (sizeof (struct cmsgcred));
   cmsg.hdr.cmsg_level = SOL_SOCKET;
   cmsg.hdr.cmsg_type = SCM_CREDS;
 #endif
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-  
+
  again:
 
-#if defined(HAVE_CMSGCRED) 
-  bytes_written = sendmsg (server_fd, &msg, 0);
+#if defined(HAVE_CMSGCRED)
+  bytes_written = sendmsg (server_fd, &msg, 0
+#if HAVE_DECL_MSG_NOSIGNAL
+                           |MSG_NOSIGNAL
+#endif
+                           );
 #else
-  bytes_written = write (server_fd, buf, 1);
+  bytes_written = send (server_fd, buf, 1, 0
+#if HAVE_DECL_MSG_NOSIGNAL
+                        |MSG_NOSIGNAL
+#endif
+                        );
 #endif
 
   if (bytes_written < 0 && errno == EINTR)
@@ -1112,7 +1653,7 @@ write_credentials_byte (int             server_fd,
  * we got valid credentials. On some systems, such as Linux,
  * reading/writing the byte isn't actually required, but we do it
  * anyway just to avoid multiple codepaths.
- * 
+ *
  * Fails if no byte is available, so you must select() first.
  *
  * The point of the byte is that on some systems we have to
@@ -1134,14 +1675,11 @@ _dbus_read_credentials_socket  (int              client_fd,
   dbus_uid_t uid_read;
   dbus_pid_t pid_read;
   int bytes_read;
-  
-  uid_read = DBUS_UID_UNSET;
-  pid_read = DBUS_PID_UNSET;
-  
-#ifdef HAVE_CMSGCRED 
-  struct {
+
+#ifdef HAVE_CMSGCRED
+  union {
     struct cmsghdr hdr;
-    struct cmsgcred cred;
+    char cred[CMSG_SPACE (sizeof (struct cmsgcred))];
   } cmsg;
 
 #elif defined(LOCAL_CREDS)
@@ -1151,8 +1689,11 @@ _dbus_read_credentials_socket  (int              client_fd,
   } cmsg;
 #endif
 
+  uid_read = DBUS_UID_UNSET;
+  pid_read = DBUS_PID_UNSET;
+
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-  
+
   /* The POSIX spec certainly doesn't promise this, but
    * we need these assertions to fail as soon as we're wrong about
    * it so we can do the porting fixups
@@ -1172,14 +1713,14 @@ _dbus_read_credentials_socket  (int              client_fd,
   iov.iov_base = &buf;
   iov.iov_len = 1;
 
-  memset (&msg, 0, sizeof (msg));
+  _DBUS_ZERO(msg);
   msg.msg_iov = &iov;
   msg.msg_iovlen = 1;
 
 #if defined(HAVE_CMSGCRED) || defined(LOCAL_CREDS)
-  memset (&cmsg, 0, sizeof (cmsg));
-  msg.msg_control = &cmsg;
-  msg.msg_controllen = sizeof (cmsg);
+  _DBUS_ZERO(cmsg);
+  msg.msg_control = (caddr_t) &cmsg;
+  msg.msg_controllen = CMSG_SPACE (sizeof (struct cmsgcred));
 #endif
 
  again:
@@ -1194,7 +1735,7 @@ _dbus_read_credentials_socket  (int              client_fd,
        * normally only call read_credentials if the socket was ready
        * for reading
        */
-      
+
       dbus_set_error (error, _dbus_error_from_errno (errno),
                       "Failed to read credentials byte: %s",
                       _dbus_strerror (errno));
@@ -1217,7 +1758,8 @@ _dbus_read_credentials_socket  (int              client_fd,
     }
 
 #if defined(HAVE_CMSGCRED) || defined(LOCAL_CREDS)
-  if (cmsg.hdr.cmsg_len < sizeof (cmsg) || cmsg.hdr.cmsg_type != SCM_CREDS)
+  if (cmsg.hdr.cmsg_len < CMSG_LEN (sizeof (struct cmsgcred))
+                 || cmsg.hdr.cmsg_type != SCM_CREDS)
     {
       dbus_set_error (error, DBUS_ERROR_FAILED,
                       "Message from recvmsg() was not SCM_CREDS");
@@ -1229,9 +1771,13 @@ _dbus_read_credentials_socket  (int              client_fd,
 
   {
 #ifdef SO_PEERCRED
-    struct ucred cr;   
+#ifdef __OpenBSD__
+    struct sockpeercred cr;
+#else
+    struct ucred cr;
+#endif
     int cr_len = sizeof (cr);
-    
+
     if (getsockopt (client_fd, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len) == 0 &&
        cr_len == sizeof (cr))
       {
@@ -1244,8 +1790,11 @@ _dbus_read_credentials_socket  (int              client_fd,
                       cr_len, (int) sizeof (cr), _dbus_strerror (errno));
       }
 #elif defined(HAVE_CMSGCRED)
-    pid_read = cmsg.cred.cmcred_pid;
-    uid_read = cmsg.cred.cmcred_euid;
+    struct cmsgcred *cred;
+
+    cred = (struct cmsgcred *) CMSG_DATA (&cmsg.hdr);
+    pid_read = cred->cmcred_pid;
+    uid_read = cred->cmcred_euid;
 #elif defined(LOCAL_CREDS)
     pid_read = DBUS_PID_UNSET;
     uid_read = cmsg.cred.sc_uid;
@@ -1278,9 +1827,9 @@ _dbus_read_credentials_socket  (int              client_fd,
           {
             _dbus_verbose ("Failed to adt_start_session(): %s\n", _dbus_strerror (errno));
           }
-        else 
+        else
           {
-            if (adt_set_from_ucred (adth, ucred, ADT_NEW)) 
+            if (adt_set_from_ucred (adth, ucred, ADT_NEW))
               {
                 _dbus_verbose ("Failed to adt_set_from_ucred(): %s\n", _dbus_strerror (errno));
               }
@@ -1321,7 +1870,7 @@ _dbus_read_credentials_socket  (int              client_fd,
 
   if (pid_read != DBUS_PID_UNSET)
     {
-      if (!_dbus_credentials_add_unix_pid (credentials, pid_read))
+      if (!_dbus_credentials_add_pid (credentials, pid_read))
         {
           _DBUS_SET_OOM (error);
           return FALSE;
@@ -1336,7 +1885,7 @@ _dbus_read_credentials_socket  (int              client_fd,
           return FALSE;
         }
     }
-  
+
   return TRUE;
 }
 
@@ -1362,7 +1911,7 @@ _dbus_send_credentials_socket  (int              server_fd,
                                 DBusError       *error)
 {
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-  
+
   if (write_credentials_byte (server_fd, error))
     return TRUE;
   else
@@ -1373,6 +1922,8 @@ _dbus_send_credentials_socket  (int              server_fd,
  * Accepts a connection on a listening socket.
  * Handles EINTR for you.
  *
+ * This will enable FD_CLOEXEC for the returned socket.
+ *
  * @param listen_fd the listen file descriptor
  * @returns the connection fd of the client, or -1 on error
  */
@@ -1382,12 +1933,25 @@ _dbus_accept  (int listen_fd)
   int client_fd;
   struct sockaddr addr;
   socklen_t addrlen;
+#ifdef HAVE_ACCEPT4
+  dbus_bool_t cloexec_done;
+#endif
 
   addrlen = sizeof (addr);
-  
+
  retry:
-  client_fd = accept (listen_fd, &addr, &addrlen);
-  
+
+#ifdef HAVE_ACCEPT4
+  /* We assume that if accept4 is available SOCK_CLOEXEC is too */
+  client_fd = accept4 (listen_fd, &addr, &addrlen, SOCK_CLOEXEC);
+  cloexec_done = client_fd >= 0;
+
+  if (client_fd < 0 && errno == ENOSYS)
+#endif
+    {
+      client_fd = accept (listen_fd, &addr, &addrlen);
+    }
+
   if (client_fd < 0)
     {
       if (errno == EINTR)
@@ -1395,13 +1959,20 @@ _dbus_accept  (int listen_fd)
     }
 
   _dbus_verbose ("client fd %d accepted\n", client_fd);
-  
+
+#ifdef HAVE_ACCEPT4
+  if (!cloexec_done)
+#endif
+    {
+      _dbus_fd_set_close_on_exec(client_fd);
+    }
+
   return client_fd;
 }
 
 /**
- * Checks to make sure the given directory is 
- * private to the user 
+ * Checks to make sure the given directory is
+ * private to the user
  *
  * @param dir the name of the directory
  * @param error error return
@@ -1412,19 +1983,19 @@ _dbus_check_dir_is_private_to_user (DBusString *dir, DBusError *error)
 {
   const char *directory;
   struct stat sb;
-       
+
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-    
+
   directory = _dbus_string_get_const_data (dir);
-       
+
   if (stat (directory, &sb) < 0)
     {
       dbus_set_error (error, _dbus_error_from_errno (errno),
                       "%s", _dbus_strerror (errno));
-   
+
       return FALSE;
     }
-    
+
   if ((S_IROTH & sb.st_mode) || (S_IWOTH & sb.st_mode) ||
       (S_IRGRP & sb.st_mode) || (S_IWGRP & sb.st_mode))
     {
@@ -1432,7 +2003,7 @@ _dbus_check_dir_is_private_to_user (DBusString *dir, DBusError *error)
                      "%s directory is not private to the user", directory);
       return FALSE;
     }
-    
+
   return TRUE;
 }
 
@@ -1443,12 +2014,12 @@ fill_user_info_from_passwd (struct passwd *p,
 {
   _dbus_assert (p->pw_name != NULL);
   _dbus_assert (p->pw_dir != NULL);
-  
+
   info->uid = p->pw_uid;
   info->primary_gid = p->pw_gid;
   info->username = _dbus_strdup (p->pw_name);
   info->homedir = _dbus_strdup (p->pw_dir);
-  
+
   if (info->username == NULL ||
       info->homedir == NULL)
     {
@@ -1466,7 +2037,7 @@ fill_user_info (DBusUserInfo       *info,
                 DBusError          *error)
 {
   const char *username_c;
-  
+
   /* exactly one of username/uid provided */
   _dbus_assert (username != NULL || uid != DBUS_UID_UNSET);
   _dbus_assert (username == NULL || uid == DBUS_UID_UNSET);
@@ -1477,7 +2048,7 @@ fill_user_info (DBusUserInfo       *info,
   info->n_group_ids = 0;
   info->username = NULL;
   info->homedir = NULL;
-  
+
   if (username != NULL)
     username_c = _dbus_string_get_const_data (username);
   else
@@ -1487,7 +2058,7 @@ fill_user_info (DBusUserInfo       *info,
    * are always symmetrical, if not we have to add more configure
    * checks
    */
-  
+
 #if defined (HAVE_POSIX_GETPWNAM_R) || defined (HAVE_NONPOSIX_GETPWNAM_R)
   {
     struct passwd *p;
@@ -1591,46 +2162,74 @@ fill_user_info (DBusUserInfo       *info,
 
   /* Fill this in so we can use it to get groups */
   username_c = info->username;
-  
+
 #ifdef HAVE_GETGROUPLIST
   {
     gid_t *buf;
     int buf_count;
     int i;
-    
-    buf_count = 17;
+    int initial_buf_count;
+
+    initial_buf_count = 17;
+    buf_count = initial_buf_count;
     buf = dbus_new (gid_t, buf_count);
     if (buf == NULL)
       {
         dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
         goto failed;
       }
-    
+
     if (getgrouplist (username_c,
                       info->primary_gid,
                       buf, &buf_count) < 0)
       {
-        gid_t *new = dbus_realloc (buf, buf_count * sizeof (buf[0]));
+        gid_t *new;
+        /* Presumed cause of negative return code: buf has insufficient
+           entries to hold the entire group list. The Linux behavior in this
+           case is to pass back the actual number of groups in buf_count, but
+           on Mac OS X 10.5, buf_count is unhelpfully left alone.
+           So as a hack, try to help out a bit by guessing a larger
+           number of groups, within reason.. might still fail, of course,
+           but we can at least print a more informative message.  I looked up
+           the "right way" to do this by downloading Apple's own source code
+           for the "id" command, and it turns out that they use an
+           undocumented library function getgrouplist_2 (!) which is not
+           declared in any header in /usr/include (!!). That did not seem
+           like the way to go here.
+        */
+        if (buf_count == initial_buf_count)
+          {
+            buf_count *= 16; /* Retry with an arbitrarily scaled-up array */
+          }
+        new = dbus_realloc (buf, buf_count * sizeof (buf[0]));
         if (new == NULL)
           {
             dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
             dbus_free (buf);
             goto failed;
           }
-        
+
         buf = new;
 
         errno = 0;
         if (getgrouplist (username_c, info->primary_gid, buf, &buf_count) < 0)
           {
-            dbus_set_error (error,
-                            _dbus_error_from_errno (errno),
-                            "Failed to get groups for username \"%s\" primary GID "
-                            DBUS_GID_FORMAT ": %s\n",
-                            username_c, info->primary_gid,
-                            _dbus_strerror (errno));
-            dbus_free (buf);
-            goto failed;
+            if (errno == 0)
+              {
+                _dbus_warn ("It appears that username \"%s\" is in more than %d groups.\nProceeding with just the first %d groups.",
+                            username_c, buf_count, buf_count);
+              }
+            else
+              {
+                dbus_set_error (error,
+                                _dbus_error_from_errno (errno),
+                                "Failed to get groups for username \"%s\" primary GID "
+                                DBUS_GID_FORMAT ": %s\n",
+                                username_c, info->primary_gid,
+                                _dbus_strerror (errno));
+                dbus_free (buf);
+                goto failed;
+              }
           }
       }
 
@@ -1641,12 +2240,12 @@ fill_user_info (DBusUserInfo       *info,
         dbus_free (buf);
         goto failed;
       }
-    
+
     for (i = 0; i < buf_count; ++i)
       info->group_ids[i] = buf[i];
 
     info->n_group_ids = buf_count;
-    
+
     dbus_free (buf);
   }
 #else  /* HAVE_GETGROUPLIST */
@@ -1666,9 +2265,9 @@ fill_user_info (DBusUserInfo       *info,
 #endif /* HAVE_GETGROUPLIST */
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-  
+
   return TRUE;
-  
+
  failed:
   _DBUS_ASSERT_ERROR_IS_SET (error);
   return FALSE;
@@ -1726,7 +2325,7 @@ _dbus_credentials_add_from_current_process (DBusCredentials *credentials)
   _dbus_assert (sizeof (uid_t) <= sizeof (dbus_uid_t));
   _dbus_assert (sizeof (gid_t) <= sizeof (dbus_gid_t));
 
-  if (!_dbus_credentials_add_unix_pid(credentials, _dbus_getpid()))
+  if (!_dbus_credentials_add_pid(credentials, _dbus_getpid()))
     return FALSE;
   if (!_dbus_credentials_add_unix_uid(credentials, _dbus_geteuid()))
     return FALSE;
@@ -1741,7 +2340,7 @@ _dbus_credentials_add_from_current_process (DBusCredentials *credentials)
  * is required, that is done in dbus-auth.c. The username here
  * need not be anything human-readable, it can be the machine-readable
  * form i.e. a user id.
- * 
+ *
  * @param str the string to append to
  * @returns #FALSE on no memory
  */
@@ -1783,7 +2382,7 @@ _dbus_geteuid (void)
 /**
  * The only reason this is separate from _dbus_getpid() is to allow it
  * on Windows for logging but not for other purposes.
- * 
+ *
  * @returns process ID to put in log messages
  */
 unsigned long
@@ -1805,7 +2404,7 @@ _dbus_parse_uid (const DBusString      *uid_str,
 {
   int end;
   long val;
-  
+
   if (_dbus_string_get_length (uid_str) == 0)
     {
       _dbus_verbose ("UID string was zero length\n");
@@ -1820,7 +2419,7 @@ _dbus_parse_uid (const DBusString      *uid_str,
       _dbus_verbose ("could not parse string as a UID\n");
       return FALSE;
     }
-  
+
   if (end != _dbus_string_get_length (uid_str))
     {
       _dbus_verbose ("string contained trailing stuff after UID\n");
@@ -1832,23 +2431,13 @@ _dbus_parse_uid (const DBusString      *uid_str,
   return TRUE;
 }
 
-
-_DBUS_DEFINE_GLOBAL_LOCK (atomic);
-
-#if DBUS_USE_ATOMIC_INT_486_COND
-/* Taken from CVS version 1.7 of glibc's sysdeps/i386/i486/atomicity.h */
-/* Since the asm stuff here is gcc-specific we go ahead and use "inline" also */
-static inline dbus_int32_t
-atomic_exchange_and_add (DBusAtomic            *atomic,
-                         volatile dbus_int32_t  val)
-{
-  register dbus_int32_t result;
-
-  __asm__ __volatile__ ("lock; xaddl %0,%1"
-                        : "=r" (result), "=m" (atomic->value)
-                       : "0" (val), "m" (atomic->value));
-  return result;
-}
+#if !DBUS_USE_SYNC
+/* To be thread-safe by default on platforms that don't necessarily have
+ * atomic operations (notably Debian armel, which is armv4t), we must
+ * use a mutex that can be initialized statically, like this.
+ * GLib >= 2.32 uses a similar system.
+ */
+static pthread_mutex_t atomic_mutex = PTHREAD_MUTEX_INITIALIZER;
 #endif
 
 /**
@@ -1856,20 +2445,20 @@ atomic_exchange_and_add (DBusAtomic            *atomic,
  *
  * @param atomic pointer to the integer to increment
  * @returns the value before incrementing
- *
- * @todo implement arch-specific faster atomic ops
  */
 dbus_int32_t
 _dbus_atomic_inc (DBusAtomic *atomic)
 {
-#if DBUS_USE_ATOMIC_INT_486_COND
-  return atomic_exchange_and_add (atomic, 1);
+#if DBUS_USE_SYNC
+  return __sync_add_and_fetch(&atomic->value, 1)-1;
 #else
   dbus_int32_t res;
-  _DBUS_LOCK (atomic);
+
+  pthread_mutex_lock (&atomic_mutex);
   res = atomic->value;
   atomic->value += 1;
-  _DBUS_UNLOCK (atomic);
+  pthread_mutex_unlock (&atomic_mutex);
+
   return res;
 #endif
 }
@@ -1879,35 +2468,47 @@ _dbus_atomic_inc (DBusAtomic *atomic)
  *
  * @param atomic pointer to the integer to decrement
  * @returns the value before decrementing
- *
- * @todo implement arch-specific faster atomic ops
  */
 dbus_int32_t
 _dbus_atomic_dec (DBusAtomic *atomic)
 {
-#if DBUS_USE_ATOMIC_INT_486_COND
-  return atomic_exchange_and_add (atomic, -1);
+#if DBUS_USE_SYNC
+  return __sync_sub_and_fetch(&atomic->value, 1)+1;
 #else
   dbus_int32_t res;
-  
-  _DBUS_LOCK (atomic);
+
+  pthread_mutex_lock (&atomic_mutex);
   res = atomic->value;
   atomic->value -= 1;
-  _DBUS_UNLOCK (atomic);
+  pthread_mutex_unlock (&atomic_mutex);
+
   return res;
 #endif
 }
 
-#ifdef DBUS_BUILD_TESTS
-/** Gets our GID
- * @returns process GID
+/**
+ * Atomically get the value of an integer. It may change at any time
+ * thereafter, so this is mostly only useful for assertions.
+ *
+ * @param atomic pointer to the integer to get
+ * @returns the value at this moment
  */
-dbus_gid_t
-_dbus_getgid (void)
+dbus_int32_t
+_dbus_atomic_get (DBusAtomic *atomic)
 {
-  return getgid ();
-}
+#if DBUS_USE_SYNC
+  __sync_synchronize ();
+  return atomic->value;
+#else
+  dbus_int32_t res;
+
+  pthread_mutex_lock (&atomic_mutex);
+  res = atomic->value;
+  pthread_mutex_unlock (&atomic_mutex);
+
+  return res;
 #endif
+}
 
 /**
  * Wrapper for poll().
@@ -1942,7 +2543,7 @@ _dbus_poll (DBusPollFD *fds,
       _DBUS_STRUCT_OFFSET (struct pollfd, revents))
     {
       return poll ((struct pollfd*) fds,
-                   n_fds, 
+                   n_fds,
                    timeout_milliseconds);
     }
   else
@@ -1960,7 +2561,7 @@ _dbus_poll (DBusPollFD *fds,
   int i;
   struct timeval tv;
   int ready;
-  
+
   FD_ZERO (&read_set);
   FD_ZERO (&write_set);
   FD_ZERO (&err_set);
@@ -1979,7 +2580,7 @@ _dbus_poll (DBusPollFD *fds,
 
       max_fd = MAX (max_fd, fdp->fd);
     }
-    
+
   tv.tv_sec = timeout_milliseconds / 1000;
   tv.tv_usec = (timeout_milliseconds % 1000) * 1000;
 
@@ -2010,15 +2611,25 @@ _dbus_poll (DBusPollFD *fds,
 }
 
 /**
- * Get current time, as in gettimeofday().
+ * Get current time, as in gettimeofday(). Use the monotonic clock if
+ * available, to avoid problems when the system time changes.
  *
  * @param tv_sec return location for number of seconds
- * @param tv_usec return location for number of microseconds (thousandths)
+ * @param tv_usec return location for number of microseconds
  */
 void
-_dbus_get_current_time (long *tv_sec,
-                        long *tv_usec)
+_dbus_get_monotonic_time (long *tv_sec,
+                          long *tv_usec)
 {
+#ifdef HAVE_MONOTONIC_CLOCK
+  struct timespec ts;
+  clock_gettime (CLOCK_MONOTONIC, &ts);
+
+  if (tv_sec)
+    *tv_sec = ts.tv_sec;
+  if (tv_usec)
+    *tv_usec = ts.tv_nsec / 1000;
+#else
   struct timeval t;
 
   gettimeofday (&t, NULL);
@@ -2027,365 +2638,28 @@ _dbus_get_current_time (long *tv_sec,
     *tv_sec = t.tv_sec;
   if (tv_usec)
     *tv_usec = t.tv_usec;
+#endif
 }
 
 /**
- * Appends the contents of the given file to the string,
- * returning error code. At the moment, won't open a file
- * more than a megabyte in size.
+ * Get current time, as in gettimeofday(). Never uses the monotonic
+ * clock.
  *
- * @param str the string to append to
- * @param filename filename to load
- * @param error place to set an error
- * @returns #FALSE if error was set
+ * @param tv_sec return location for number of seconds
+ * @param tv_usec return location for number of microseconds
  */
-dbus_bool_t
-_dbus_file_get_contents (DBusString       *str,
-                         const DBusString *filename,
-                         DBusError        *error)
-{
-  int fd;
-  struct stat sb;
-  int orig_len;
-  int total;
-  const char *filename_c;
-
-  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-  
-  filename_c = _dbus_string_get_const_data (filename);
-  
-  /* O_BINARY useful on Cygwin */
-  fd = open (filename_c, O_RDONLY | O_BINARY);
-  if (fd < 0)
-    {
-      dbus_set_error (error, _dbus_error_from_errno (errno),
-                      "Failed to open \"%s\": %s",
-                      filename_c,
-                      _dbus_strerror (errno));
-      return FALSE;
-    }
-
-  _dbus_verbose ("file fd %d opened\n", fd);
-  
-  if (fstat (fd, &sb) < 0)
-    {
-      dbus_set_error (error, _dbus_error_from_errno (errno),
-                      "Failed to stat \"%s\": %s",
-                      filename_c,
-                      _dbus_strerror (errno));
-
-      _dbus_verbose ("fstat() failed: %s",
-                     _dbus_strerror (errno));
-      
-      _dbus_close (fd, NULL);
-      
-      return FALSE;
-    }
-
-  if (sb.st_size > _DBUS_ONE_MEGABYTE)
-    {
-      dbus_set_error (error, DBUS_ERROR_FAILED,
-                      "File size %lu of \"%s\" is too large.",
-                      (unsigned long) sb.st_size, filename_c);
-      _dbus_close (fd, NULL);
-      return FALSE;
-    }
-  
-  total = 0;
-  orig_len = _dbus_string_get_length (str);
-  if (sb.st_size > 0 && S_ISREG (sb.st_mode))
-    {
-      int bytes_read;
-
-      while (total < (int) sb.st_size)
-        {
-          bytes_read = _dbus_read (fd, str,
-                                   sb.st_size - total);
-          if (bytes_read <= 0)
-            {
-              dbus_set_error (error, _dbus_error_from_errno (errno),
-                              "Error reading \"%s\": %s",
-                              filename_c,
-                              _dbus_strerror (errno));
-
-              _dbus_verbose ("read() failed: %s",
-                             _dbus_strerror (errno));
-              
-              _dbus_close (fd, NULL);
-              _dbus_string_set_length (str, orig_len);
-              return FALSE;
-            }
-          else
-            total += bytes_read;
-        }
-
-      _dbus_close (fd, NULL);
-      return TRUE;
-    }
-  else if (sb.st_size != 0)
-    {
-      _dbus_verbose ("Can only open regular files at the moment.\n");
-      dbus_set_error (error, DBUS_ERROR_FAILED,
-                      "\"%s\" is not a regular file",
-                      filename_c);
-      _dbus_close (fd, NULL);
-      return FALSE;
-    }
-  else
-    {
-      _dbus_close (fd, NULL);
-      return TRUE;
-    }
-}
-
-/**
- * Writes a string out to a file. If the file exists,
- * it will be atomically overwritten by the new data.
- *
- * @param str the string to write out
- * @param filename the file to save string to
- * @param error error to be filled in on failure
- * @returns #FALSE on failure
- */
-dbus_bool_t
-_dbus_string_save_to_file (const DBusString *str,
-                           const DBusString *filename,
-                           DBusError        *error)
-{
-  int fd;
-  int bytes_to_write;
-  const char *filename_c;
-  DBusString tmp_filename;
-  const char *tmp_filename_c;
-  int total;
-  dbus_bool_t need_unlink;
-  dbus_bool_t retval;
-
-  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-  
-  fd = -1;
-  retval = FALSE;
-  need_unlink = FALSE;
-  
-  if (!_dbus_string_init (&tmp_filename))
-    {
-      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
-      return FALSE;
-    }
-
-  if (!_dbus_string_copy (filename, 0, &tmp_filename, 0))
-    {
-      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
-      _dbus_string_free (&tmp_filename);
-      return FALSE;
-    }
-  
-  if (!_dbus_string_append (&tmp_filename, "."))
-    {
-      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
-      _dbus_string_free (&tmp_filename);
-      return FALSE;
-    }
-
-#define N_TMP_FILENAME_RANDOM_BYTES 8
-  if (!_dbus_generate_random_ascii (&tmp_filename, N_TMP_FILENAME_RANDOM_BYTES))
-    {
-      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
-      _dbus_string_free (&tmp_filename);
-      return FALSE;
-    }
-    
-  filename_c = _dbus_string_get_const_data (filename);
-  tmp_filename_c = _dbus_string_get_const_data (&tmp_filename);
-
-  fd = open (tmp_filename_c, O_WRONLY | O_BINARY | O_EXCL | O_CREAT,
-             0600);
-  if (fd < 0)
-    {
-      dbus_set_error (error, _dbus_error_from_errno (errno),
-                      "Could not create %s: %s", tmp_filename_c,
-                      _dbus_strerror (errno));
-      goto out;
-    }
-
-  _dbus_verbose ("tmp file fd %d opened\n", fd);
-  
-  need_unlink = TRUE;
-  
-  total = 0;
-  bytes_to_write = _dbus_string_get_length (str);
-
-  while (total < bytes_to_write)
-    {
-      int bytes_written;
-
-      bytes_written = _dbus_write (fd, str, total,
-                                   bytes_to_write - total);
-
-      if (bytes_written <= 0)
-        {
-          dbus_set_error (error, _dbus_error_from_errno (errno),
-                          "Could not write to %s: %s", tmp_filename_c,
-                          _dbus_strerror (errno));
-          
-          goto out;
-        }
-
-      total += bytes_written;
-    }
-
-  if (fsync(fd))
-    {
-      dbus_set_error (error, _dbus_error_from_errno (errno),
-                      "Could not synchronize file %s: %s",
-                      tmp_filename_c, _dbus_strerror (errno));
-
-      goto out;
-  }
-
-  if (!_dbus_close (fd, NULL))
-    {
-      dbus_set_error (error, _dbus_error_from_errno (errno),
-                      "Could not close file %s: %s",
-                      tmp_filename_c, _dbus_strerror (errno));
-
-      goto out;
-    }
-
-  fd = -1;
-  
-  if (rename (tmp_filename_c, filename_c) < 0)
-    {
-      dbus_set_error (error, _dbus_error_from_errno (errno),
-                      "Could not rename %s to %s: %s",
-                      tmp_filename_c, filename_c,
-                      _dbus_strerror (errno));
-
-      goto out;
-    }
-
-  need_unlink = FALSE;
-  
-  retval = TRUE;
-  
- out:
-  /* close first, then unlink, to prevent ".nfs34234235" garbage
-   * files
-   */
-
-  if (fd >= 0)
-    _dbus_close (fd, NULL);
-        
-  if (need_unlink && unlink (tmp_filename_c) < 0)
-    _dbus_verbose ("Failed to unlink temp file %s: %s\n",
-                   tmp_filename_c, _dbus_strerror (errno));
-
-  _dbus_string_free (&tmp_filename);
-
-  if (!retval)
-    _DBUS_ASSERT_ERROR_IS_SET (error);
-  
-  return retval;
-}
-
-/** Makes the file readable by every user in the system.
- *
- * @param filename the filename
- * @param error error location
- * @returns #TRUE if the file's permissions could be changed.
- */
-dbus_bool_t
-_dbus_make_file_world_readable(const DBusString *filename,
-                               DBusError *error)
-{
-  const char *filename_c;
-
-  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-
-  filename_c = _dbus_string_get_const_data (filename);
-  if (chmod (filename_c, 0644) == -1)
-    {
-      dbus_set_error (error,
-                      DBUS_ERROR_FAILED,
-                      "Could not change permissions of file %s: %s\n",
-                      filename_c,
-                      _dbus_strerror (errno));
-      return FALSE;
-    }
-  return TRUE;
-}
-
-/** Creates the given file, failing if the file already exists.
- *
- * @param filename the filename
- * @param error error location
- * @returns #TRUE if we created the file and it didn't exist
- */
-dbus_bool_t
-_dbus_create_file_exclusively (const DBusString *filename,
-                               DBusError        *error)
-{
-  int fd;
-  const char *filename_c;
-
-  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-  
-  filename_c = _dbus_string_get_const_data (filename);
-  
-  fd = open (filename_c, O_WRONLY | O_BINARY | O_EXCL | O_CREAT,
-             0600);
-  if (fd < 0)
-    {
-      dbus_set_error (error,
-                      DBUS_ERROR_FAILED,
-                      "Could not create file %s: %s\n",
-                      filename_c,
-                      _dbus_strerror (errno));
-      return FALSE;
-    }
-
-  _dbus_verbose ("exclusive file fd %d opened\n", fd);
-  
-  if (!_dbus_close (fd, NULL))
-    {
-      dbus_set_error (error,
-                      DBUS_ERROR_FAILED,
-                      "Could not close file %s: %s\n",
-                      filename_c,
-                      _dbus_strerror (errno));
-      return FALSE;
-    }
-  
-  return TRUE;
-}
-
-/**
- * Deletes the given file.
- *
- * @param filename the filename
- * @param error error location
- * 
- * @returns #TRUE if unlink() succeeded
- */
-dbus_bool_t
-_dbus_delete_file (const DBusString *filename,
-                   DBusError        *error)
+void
+_dbus_get_real_time (long *tv_sec,
+                     long *tv_usec)
 {
-  const char *filename_c;
+  struct timeval t;
 
-  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-  
-  filename_c = _dbus_string_get_const_data (filename);
+  gettimeofday (&t, NULL);
 
-  if (unlink (filename_c) < 0)
-    {
-      dbus_set_error (error, DBUS_ERROR_FAILED,
-                      "Failed to delete file %s: %s\n",
-                      filename_c, _dbus_strerror (errno));
-      return FALSE;
-    }
-  else
-    return TRUE;
+  if (tv_sec)
+    *tv_sec = t.tv_sec;
+  if (tv_usec)
+    *tv_usec = t.tv_usec;
 }
 
 /**
@@ -2403,14 +2677,14 @@ _dbus_create_directory (const DBusString *filename,
   const char *filename_c;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-  
+
   filename_c = _dbus_string_get_const_data (filename);
 
   if (mkdir (filename_c, 0700) < 0)
     {
       if (errno == EEXIST)
         return TRUE;
-      
+
       dbus_set_error (error, DBUS_ERROR_FAILED,
                       "Failed to create directory %s: %s\n",
                       filename_c, _dbus_strerror (errno));
@@ -2440,7 +2714,7 @@ _dbus_concat_dir_and_file (DBusString       *dir,
   if (_dbus_string_get_length (dir) == 0 ||
       _dbus_string_get_length (next_component) == 0)
     return TRUE;
-  
+
   dir_ends_in_slash = '/' == _dbus_string_get_byte (dir,
                                                     _dbus_string_get_length (dir) - 1);
 
@@ -2502,7 +2776,7 @@ _dbus_generate_pseudorandom_bytes (DBusString *str,
 {
   int old_len;
   char *p;
-  
+
   old_len = _dbus_string_get_length (str);
 
   if (!_dbus_string_lengthen (str, n_bytes))
@@ -2535,7 +2809,7 @@ _dbus_generate_random_bytes (DBusString *str,
    * a DBusError. So we always fall back to pseudorandom
    * if the I/O fails.
    */
-  
+
   old_len = _dbus_string_get_length (str);
   fd = -1;
 
@@ -2545,7 +2819,7 @@ _dbus_generate_random_bytes (DBusString *str,
     return _dbus_generate_pseudorandom_bytes (str, n_bytes);
 
   _dbus_verbose ("/dev/urandom fd %d opened\n", fd);
-  
+
   if (_dbus_read (fd, str, n_bytes) != n_bytes)
     {
       _dbus_close (fd, NULL);
@@ -2555,9 +2829,9 @@ _dbus_generate_random_bytes (DBusString *str,
 
   _dbus_verbose ("Read %d bytes from /dev/urandom\n",
                  n_bytes);
-  
+
   _dbus_close (fd, NULL);
-  
+
   return TRUE;
 }
 
@@ -2584,7 +2858,7 @@ const char*
 _dbus_strerror (int error_number)
 {
   const char *msg;
-  
+
   msg = strerror (error_number);
   if (msg == NULL)
     msg = "unknown";
@@ -2609,17 +2883,17 @@ _dbus_disable_sigpipe (void)
  * @param fd the file descriptor
  */
 void
-_dbus_fd_set_close_on_exec (int fd)
+_dbus_fd_set_close_on_exec (intptr_t fd)
 {
   int val;
-  
+
   val = fcntl (fd, F_GETFD, 0);
-  
+
   if (val < 0)
     return;
 
   val |= FD_CLOEXEC;
-  
+
   fcntl (fd, F_SETFD, val);
 }
 
@@ -2635,7 +2909,7 @@ _dbus_close (int        fd,
              DBusError *error)
 {
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-  
+
  again:
   if (close (fd) < 0)
     {
@@ -2651,6 +2925,49 @@ _dbus_close (int        fd,
 }
 
 /**
+ * Duplicates a file descriptor. Makes sure the fd returned is >= 3
+ * (i.e. avoids stdin/stdout/stderr). Sets O_CLOEXEC.
+ *
+ * @param fd the file descriptor to duplicate
+ * @param error address of error location.
+ * @returns duplicated file descriptor
+ * */
+int
+_dbus_dup(int        fd,
+          DBusError *error)
+{
+  int new_fd;
+
+#ifdef F_DUPFD_CLOEXEC
+  dbus_bool_t cloexec_done;
+
+  new_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
+  cloexec_done = new_fd >= 0;
+
+  if (new_fd < 0 && errno == EINVAL)
+#endif
+    {
+      new_fd = fcntl(fd, F_DUPFD, 3);
+    }
+
+  if (new_fd < 0) {
+
+    dbus_set_error (error, _dbus_error_from_errno (errno),
+                    "Could not duplicate fd %d", fd);
+    return -1;
+  }
+
+#ifdef F_DUPFD_CLOEXEC
+  if (!cloexec_done)
+#endif
+    {
+      _dbus_fd_set_close_on_exec(new_fd);
+    }
+
+  return new_fd;
+}
+
+/**
  * Sets a file descriptor to be nonblocking.
  *
  * @param fd the file descriptor.
@@ -2664,7 +2981,7 @@ _dbus_set_fd_nonblocking (int             fd,
   int val;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-  
+
   val = fcntl (fd, F_GETFL, 0);
   if (val < 0)
     {
@@ -2697,17 +3014,17 @@ _dbus_set_fd_nonblocking (int             fd,
  */
 void
 _dbus_print_backtrace (void)
-{  
+{
 #if defined (HAVE_BACKTRACE) && defined (DBUS_BUILT_R_DYNAMIC)
   void *bt[500];
   int bt_size;
   int i;
   char **syms;
-  
+
   bt_size = backtrace (bt, 500);
 
   syms = backtrace_symbols (bt, bt_size);
-  
+
   i = 0;
   while (i < bt_size)
     {
@@ -2729,11 +3046,8 @@ _dbus_print_backtrace (void)
  * Creates a full-duplex pipe (as in socketpair()).
  * Sets both ends of the pipe nonblocking.
  *
- * @todo libdbus only uses this for the debug-pipe server, so in
- * principle it could be in dbus-sysdeps-util.c, except that
- * dbus-sysdeps-util.c isn't in libdbus when tests are enabled and the
- * debug-pipe server is used.
- * 
+ * Marks both file descriptors as close-on-exec
+ *
  * @param fd1 return location for one end
  * @param fd2 return location for the other end
  * @param blocking #TRUE if pipe should be blocking
@@ -2748,36 +3062,57 @@ _dbus_full_duplex_pipe (int        *fd1,
 {
 #ifdef HAVE_SOCKETPAIR
   int fds[2];
+  int retval;
 
-  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-  
-  if (socketpair (AF_UNIX, SOCK_STREAM, 0, fds) < 0)
+#ifdef SOCK_CLOEXEC
+  dbus_bool_t cloexec_done;
+
+  retval = socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, fds);
+  cloexec_done = retval >= 0;
+
+  if (retval < 0 && errno == EINVAL)
+#endif
+    {
+      retval = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
+    }
+
+  if (retval < 0)
     {
       dbus_set_error (error, _dbus_error_from_errno (errno),
                       "Could not create full-duplex pipe");
       return FALSE;
     }
 
+  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+#ifdef SOCK_CLOEXEC
+  if (!cloexec_done)
+#endif
+    {
+      _dbus_fd_set_close_on_exec (fds[0]);
+      _dbus_fd_set_close_on_exec (fds[1]);
+    }
+
   if (!blocking &&
       (!_dbus_set_fd_nonblocking (fds[0], NULL) ||
        !_dbus_set_fd_nonblocking (fds[1], NULL)))
     {
       dbus_set_error (error, _dbus_error_from_errno (errno),
                       "Could not set full-duplex pipe nonblocking");
-      
+
       _dbus_close (fds[0], NULL);
       _dbus_close (fds[1], NULL);
-      
+
       return FALSE;
     }
-  
+
   *fd1 = fds[0];
   *fd2 = fds[1];
 
   _dbus_verbose ("full-duplex pipe %d <-> %d\n",
                  *fd1, *fd2);
-  
-  return TRUE;  
+
+  return TRUE;
 #else
   _dbus_warn ("_dbus_full_duplex_pipe() not implemented on this OS\n");
   dbus_set_error (error, DBUS_ERROR_FAILED,
@@ -2792,27 +3127,87 @@ _dbus_full_duplex_pipe (int        *fd1,
  *
  * @param format a printf-style format string
  * @param args arguments for the format string
- * @returns length of the given format string and args
+ * @returns length of the given format string and args, or -1 if no memory
  */
 int
 _dbus_printf_string_upper_bound (const char *format,
                                  va_list     args)
 {
-  char c;
-  return vsnprintf (&c, 1, format, args);
-}
+  char static_buf[1024];
+  int bufsize = sizeof (static_buf);
+  int len;
+  va_list args_copy;
 
-/**
- * Gets the temporary files directory by inspecting the environment variables 
+  DBUS_VA_COPY (args_copy, args);
+  len = vsnprintf (static_buf, bufsize, format, args_copy);
+  va_end (args_copy);
+
+  /* If vsnprintf() returned non-negative, then either the string fits in
+   * static_buf, or this OS has the POSIX and C99 behaviour where vsnprintf
+   * returns the number of characters that were needed, or this OS returns the
+   * truncated length.
+   *
+   * We ignore the possibility that snprintf might just ignore the length and
+   * overrun the buffer (64-bit Solaris 7), because that's pathological.
+   * If your libc is really that bad, come back when you have a better one. */
+  if (len == bufsize)
+    {
+      /* This could be the truncated length (Tru64 and IRIX have this bug),
+       * or the real length could be coincidentally the same. Which is it?
+       * If vsnprintf returns the truncated length, we'll go to the slow
+       * path. */
+      DBUS_VA_COPY (args_copy, args);
+
+      if (vsnprintf (static_buf, 1, format, args_copy) == 1)
+        len = -1;
+
+      va_end (args_copy);
+    }
+
+  /* If vsnprintf() returned negative, we have to do more work.
+   * HP-UX returns negative. */
+  while (len < 0)
+    {
+      char *buf;
+
+      bufsize *= 2;
+
+      buf = dbus_malloc (bufsize);
+
+      if (buf == NULL)
+        return -1;
+
+      DBUS_VA_COPY (args_copy, args);
+      len = vsnprintf (buf, bufsize, format, args_copy);
+      va_end (args_copy);
+
+      dbus_free (buf);
+
+      /* If the reported length is exactly the buffer size, round up to the
+       * next size, in case vsnprintf has been returning the truncated
+       * length */
+      if (len == bufsize)
+        len = -1;
+    }
+
+  return len;
+}
+
+/**
+ * Gets the temporary files directory by inspecting the environment variables
  * TMPDIR, TMP, and TEMP in that order. If none of those are set "/tmp" is returned
  *
- * @returns location of temp directory
+ * @returns location of temp directory, or #NULL if no memory for locking
  */
 const char*
 _dbus_get_tmpdir(void)
 {
+  /* Protected by _DBUS_LOCK_sysdeps */
   static const char* tmpdir = NULL;
 
+  if (!_DBUS_LOCK (sysdeps))
+    return NULL;
+
   if (tmpdir == NULL)
     {
       /* TMPDIR is what glibc uses, then
@@ -2834,90 +3229,82 @@ _dbus_get_tmpdir(void)
       if (tmpdir == NULL)
         tmpdir = "/tmp";
     }
-  
+
+  _DBUS_UNLOCK (sysdeps);
+
   _dbus_assert(tmpdir != NULL);
-  
+
   return tmpdir;
 }
 
+#if defined(DBUS_ENABLE_X11_AUTOLAUNCH) || defined(DBUS_ENABLE_LAUNCHD)
 /**
- * Determines the address of the session bus by querying a
- * platform-specific method.
+ * Execute a subprocess, returning up to 1024 bytes of output
+ * into @p result.
  *
- * If successful, returns #TRUE and appends the address to @p
- * address. If a failure happens, returns #FALSE and
+ * If successful, returns #TRUE and appends the output to @p
+ * result. If a failure happens, returns #FALSE and
  * sets an error in @p error.
  *
- * @param address a DBusString where the address can be stored
+ * @note It's not an error if the subprocess terminates normally
+ * without writing any data to stdout. Verify the @p result length
+ * before and after this function call to cover this case.
+ *
+ * @param progname initial path to exec (may or may not be absolute)
+ * @param path_fallback if %TRUE, search PATH for executable
+ * @param argv NULL-terminated list of arguments
+ * @param result a DBusString where the output can be append
  * @param error a DBusError to store the error in case of failure
  * @returns #TRUE on success, #FALSE if an error happened
  */
-dbus_bool_t
-_dbus_get_autolaunch_address (DBusString *address,
-                              DBusError  *error)
+static dbus_bool_t
+_read_subprocess_line_argv (const char *progpath,
+                            dbus_bool_t path_fallback,
+                            char       * const *argv,
+                            DBusString *result,
+                            DBusError  *error)
 {
-  static char *argv[6];
-  int address_pipe[2] = { -1, -1 };
+  int result_pipe[2] = { -1, -1 };
   int errors_pipe[2] = { -1, -1 };
   pid_t pid;
   int ret;
   int status;
   int orig_len;
-  int i;
-  DBusString uuid;
+
   dbus_bool_t retval;
-  
+  sigset_t new_set, old_set;
+
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
   retval = FALSE;
 
-  if (!_dbus_string_init (&uuid))
-    {
-      _DBUS_SET_OOM (error);
-      return FALSE;
-    }
-  
-  if (!_dbus_get_local_machine_uuid_encoded (&uuid))
-    {
-      _DBUS_SET_OOM (error);
-      goto out;
-    }
-  
-  i = 0;
-  argv[i] = "dbus-launch";
-  ++i;
-  argv[i] = "--autolaunch";
-  ++i;
-  argv[i] = _dbus_string_get_data (&uuid);
-  ++i;
-  argv[i] = "--binary-syntax";
-  ++i;
-  argv[i] = "--close-stderr";
-  ++i;
-  argv[i] = NULL;
-  ++i;
+  /* We need to block any existing handlers for SIGCHLD temporarily; they
+   * will cause waitpid() below to fail.
+   * https://bugs.freedesktop.org/show_bug.cgi?id=21347
+   */
+  sigemptyset (&new_set);
+  sigaddset (&new_set, SIGCHLD);
+  sigprocmask (SIG_BLOCK, &new_set, &old_set);
+
+  orig_len = _dbus_string_get_length (result);
 
-  _dbus_assert (i == _DBUS_N_ELEMENTS (argv));
-  
-  orig_len = _dbus_string_get_length (address);
-  
 #define READ_END        0
 #define WRITE_END       1
-  if (pipe (address_pipe) < 0)
+  if (pipe (result_pipe) < 0)
     {
       dbus_set_error (error, _dbus_error_from_errno (errno),
-                      "Failed to create a pipe: %s",
-                      _dbus_strerror (errno));
-      _dbus_verbose ("Failed to create a pipe to call dbus-launch: %s\n",
-                     _dbus_strerror (errno));
+                      "Failed to create a pipe to call %s: %s",
+                      progpath, _dbus_strerror (errno));
+      _dbus_verbose ("Failed to create a pipe to call %s: %s\n",
+                     progpath, _dbus_strerror (errno));
       goto out;
     }
   if (pipe (errors_pipe) < 0)
     {
       dbus_set_error (error, _dbus_error_from_errno (errno),
-                      "Failed to create a pipe: %s",
-                      _dbus_strerror (errno));
-      _dbus_verbose ("Failed to create a pipe to call dbus-launch: %s\n",
-                     _dbus_strerror (errno));
+                      "Failed to create a pipe to call %s: %s",
+                      progpath, _dbus_strerror (errno));
+      _dbus_verbose ("Failed to create a pipe to call %s: %s\n",
+                     progpath, _dbus_strerror (errno));
       goto out;
     }
 
@@ -2925,17 +3312,16 @@ _dbus_get_autolaunch_address (DBusString *address,
   if (pid < 0)
     {
       dbus_set_error (error, _dbus_error_from_errno (errno),
-                      "Failed to fork(): %s",
-                      _dbus_strerror (errno));
-      _dbus_verbose ("Failed to fork() to call dbus-launch: %s\n",
-                     _dbus_strerror (errno));
+                      "Failed to fork() to call %s: %s",
+                      progpath, _dbus_strerror (errno));
+      _dbus_verbose ("Failed to fork() to call %s: %s\n",
+                     progpath, _dbus_strerror (errno));
       goto out;
     }
 
   if (pid == 0)
     {
       /* child process */
-      int maxfds;
       int fd;
 
       fd = open ("/dev/null", O_RDWR);
@@ -2944,50 +3330,53 @@ _dbus_get_autolaunch_address (DBusString *address,
         _exit (1);
 
       _dbus_verbose ("/dev/null fd %d opened\n", fd);
-      
+
       /* set-up stdXXX */
-      close (address_pipe[READ_END]);
+      close (result_pipe[READ_END]);
       close (errors_pipe[READ_END]);
-      close (0);                /* close stdin */
-      close (1);                /* close stdout */
-      close (2);                /* close stderr */
 
-      if (dup2 (fd, 0) == -1)
+      if (dup2 (fd, 0) == -1) /* setup stdin */
         _exit (1);
-      if (dup2 (address_pipe[WRITE_END], 1) == -1)
+      if (dup2 (result_pipe[WRITE_END], 1) == -1) /* setup stdout */
         _exit (1);
-      if (dup2 (errors_pipe[WRITE_END], 2) == -1)
+      if (dup2 (errors_pipe[WRITE_END], 2) == -1) /* setup stderr */
         _exit (1);
 
-      maxfds = sysconf (_SC_OPEN_MAX);
-      /* Pick something reasonable if for some reason sysconf
-       * says unlimited.
-       */
-      if (maxfds < 0)
-        maxfds = 1024;
-      /* close all inherited fds */
-      for (i = 3; i < maxfds; i++)
-        close (i);
+      _dbus_close_all ();
 
-      execv (DBUS_BINDIR "/dbus-launch", argv);
+      sigprocmask (SIG_SETMASK, &old_set, NULL);
 
-      /* failed, try searching PATH */
-      execvp ("dbus-launch", argv);
+      /* If it looks fully-qualified, try execv first */
+      if (progpath[0] == '/')
+        {
+          execv (progpath, argv);
+          /* Ok, that failed.  Now if path_fallback is given, let's
+           * try unqualified.  This is mostly a hack to work
+           * around systems which ship dbus-launch in /usr/bin
+           * but everything else in /bin (because dbus-launch
+           * depends on X11).
+           */
+          if (path_fallback)
+            /* We must have a slash, because we checked above */
+            execvp (strrchr (progpath, '/')+1, argv);
+        }
+      else
+        execvp (progpath, argv);
 
       /* still nothing, we failed */
       _exit (1);
     }
 
   /* parent process */
-  close (address_pipe[WRITE_END]);
+  close (result_pipe[WRITE_END]);
   close (errors_pipe[WRITE_END]);
-  address_pipe[WRITE_END] = -1;
+  result_pipe[WRITE_END] = -1;
   errors_pipe[WRITE_END] = -1;
 
   ret = 0;
-  do 
+  do
     {
-      ret = _dbus_read (address_pipe[READ_END], address, 1024);
+      ret = _dbus_read (result_pipe[READ_END], result, 1024);
     }
   while (ret > 0);
 
@@ -3000,49 +3389,148 @@ _dbus_get_autolaunch_address (DBusString *address,
 
   /* We succeeded if the process exited with status 0 and
      anything was read */
-  if (!WIFEXITED (status) || WEXITSTATUS (status) != 0 ||
-      _dbus_string_get_length (address) == orig_len)
+  if (!WIFEXITED (status) || WEXITSTATUS (status) != 0 )
     {
       /* The process ended with error */
       DBusString error_message;
-      _dbus_string_init (&error_message);
+      if (!_dbus_string_init (&error_message))
+        {
+          _DBUS_SET_OOM (error);
+          goto out;
+        }
+
       ret = 0;
       do
-       {
-         ret = _dbus_read (errors_pipe[READ_END], &error_message, 1024);
-       }
+        {
+          ret = _dbus_read (errors_pipe[READ_END], &error_message, 1024);
+        }
       while (ret > 0);
 
-      _dbus_string_set_length (address, orig_len);
+      _dbus_string_set_length (result, orig_len);
       if (_dbus_string_get_length (&error_message) > 0)
-       dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED,
-                       "dbus-launch failed to autolaunch D-Bus session: %s",
-                       _dbus_string_get_data (&error_message));
+        dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED,
+                        "%s terminated abnormally with the following error: %s",
+                        progpath, _dbus_string_get_data (&error_message));
       else
-       dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED,
-                       "Failed to execute dbus-launch to autolaunch D-Bus session");
+        dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED,
+                        "%s terminated abnormally without any error message",
+                        progpath);
       goto out;
     }
 
   retval = TRUE;
-  
+
  out:
+  sigprocmask (SIG_SETMASK, &old_set, NULL);
+
   if (retval)
     _DBUS_ASSERT_ERROR_IS_CLEAR (error);
   else
     _DBUS_ASSERT_ERROR_IS_SET (error);
 
-  if (address_pipe[0] != -1)
-    close (address_pipe[0]);
-  if (address_pipe[1] != -1)
-    close (address_pipe[1]);
+  if (result_pipe[0] != -1)
+    close (result_pipe[0]);
+  if (result_pipe[1] != -1)
+    close (result_pipe[1]);
   if (errors_pipe[0] != -1)
     close (errors_pipe[0]);
   if (errors_pipe[1] != -1)
     close (errors_pipe[1]);
 
+  return retval;
+}
+#endif
+
+/**
+ * Returns the address of a new session bus.
+ *
+ * If successful, returns #TRUE and appends the address to @p
+ * address. If a failure happens, returns #FALSE and
+ * sets an error in @p error.
+ *
+ * @param scope scope of autolaunch (Windows only)
+ * @param address a DBusString where the address can be stored
+ * @param error a DBusError to store the error in case of failure
+ * @returns #TRUE on success, #FALSE if an error happened
+ */
+dbus_bool_t
+_dbus_get_autolaunch_address (const char *scope,
+                              DBusString *address,
+                              DBusError  *error)
+{
+#ifdef DBUS_ENABLE_X11_AUTOLAUNCH
+  /* Perform X11-based autolaunch. (We also support launchd-based autolaunch,
+   * but that's done elsewhere, and if it worked, this function wouldn't
+   * be called.) */
+  const char *display;
+  char *argv[6];
+  int i;
+  DBusString uuid;
+  dbus_bool_t retval;
+
+  if (_dbus_check_setuid ())
+    {
+      dbus_set_error_const (error, DBUS_ERROR_NOT_SUPPORTED,
+                            "Unable to autolaunch when setuid");
+      return FALSE;
+    }
+
+  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+  retval = FALSE;
+
+  /* fd.o #19997: if $DISPLAY isn't set to something useful, then
+   * dbus-launch-x11 is just going to fail. Rather than trying to
+   * run it, we might as well bail out early with a nice error. */
+  display = _dbus_getenv ("DISPLAY");
+
+  if (display == NULL || display[0] == '\0')
+    {
+      dbus_set_error_const (error, DBUS_ERROR_NOT_SUPPORTED,
+          "Unable to autolaunch a dbus-daemon without a $DISPLAY for X11");
+      return FALSE;
+    }
+
+  if (!_dbus_string_init (&uuid))
+    {
+      _DBUS_SET_OOM (error);
+      return FALSE;
+    }
+
+  if (!_dbus_get_local_machine_uuid_encoded (&uuid))
+    {
+      _DBUS_SET_OOM (error);
+      goto out;
+    }
+
+  i = 0;
+  argv[i] = "dbus-launch";
+  ++i;
+  argv[i] = "--autolaunch";
+  ++i;
+  argv[i] = _dbus_string_get_data (&uuid);
+  ++i;
+  argv[i] = "--binary-syntax";
+  ++i;
+  argv[i] = "--close-stderr";
+  ++i;
+  argv[i] = NULL;
+  ++i;
+
+  _dbus_assert (i == _DBUS_N_ELEMENTS (argv));
+
+  retval = _read_subprocess_line_argv (DBUS_BINDIR "/dbus-launch",
+                                       TRUE,
+                                       argv, address, error);
+
+ out:
   _dbus_string_free (&uuid);
   return retval;
+#else
+  dbus_set_error_const (error, DBUS_ERROR_NOT_SUPPORTED,
+      "Using X11 for dbus-daemon autolaunch was disabled at compile time, "
+      "set your DBUS_SESSION_BUS_ADDRESS instead");
+  return FALSE;
+#endif
 }
 
 /**
@@ -3069,191 +3557,169 @@ _dbus_read_local_machine_uuid (DBusGUID   *machine_id,
                                DBusError  *error)
 {
   DBusString filename;
+  dbus_bool_t b;
+
   _dbus_string_init_const (&filename, DBUS_MACHINE_UUID_FILE);
-  return _dbus_read_uuid_file (&filename, machine_id, create_if_not_found, error);
-}
 
-#define DBUS_UNIX_STANDARD_SESSION_SERVICEDIR "/dbus-1/services"
-#define DBUS_UNIX_STANDARD_SYSTEM_SERVICEDIR "/dbus-1/system-services"
+  b = _dbus_read_uuid_file (&filename, machine_id, create_if_not_found, error);
+  if (b)
+    return TRUE;
+
+  dbus_error_free (error);
 
+  /* Fallback to the system machine ID */
+  _dbus_string_init_const (&filename, "/etc/machine-id");
+  return _dbus_read_uuid_file (&filename, machine_id, FALSE, error);
+}
 
 /**
- * Returns the standard directories for a session bus to look for service 
- * activation files 
- *
- * On UNIX this should be the standard xdg freedesktop.org data directories:
- *
- * XDG_DATA_HOME=${XDG_DATA_HOME-$HOME/.local/share}
- * XDG_DATA_DIRS=${XDG_DATA_DIRS-/usr/local/share:/usr/share}
- *
- * and
- *
- * DBUS_DATADIR
- *
- * @param dirs the directory list we are returning
- * @returns #FALSE on OOM 
+ * quries launchd for a specific env var which holds the socket path.
+ * @param socket_path append the socket path to this DBusString
+ * @param launchd_env_var the env var to look up
+ * @param error a DBusError to store the error in case of failure
+ * @return the value of the env var
  */
-
-dbus_bool_t 
-_dbus_get_standard_session_servicedirs (DBusList **dirs)
+dbus_bool_t
+_dbus_lookup_launchd_socket (DBusString *socket_path,
+                             const char *launchd_env_var,
+                             DBusError  *error)
 {
-  const char *xdg_data_home;
-  const char *xdg_data_dirs;
-  DBusString servicedir_path;
-
-  if (!_dbus_string_init (&servicedir_path))
-    return FALSE;
-
-  xdg_data_home = _dbus_getenv ("XDG_DATA_HOME");
-  xdg_data_dirs = _dbus_getenv ("XDG_DATA_DIRS");
+#ifdef DBUS_ENABLE_LAUNCHD
+  char *argv[4];
+  int i;
 
-  if (xdg_data_dirs != NULL)
-    {
-      if (!_dbus_string_append (&servicedir_path, xdg_data_dirs))
-        goto oom;
+  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
-      if (!_dbus_string_append (&servicedir_path, ":"))
-        goto oom;
-    }
-  else
+  if (_dbus_check_setuid ())
     {
-      if (!_dbus_string_append (&servicedir_path, "/usr/local/share:/usr/share:"))
-        goto oom;
+      dbus_set_error_const (error, DBUS_ERROR_NOT_SUPPORTED,
+                            "Unable to find launchd socket when setuid");
+      return FALSE;
     }
 
-  /* 
-   * add configured datadir to defaults
-   * this may be the same as an xdg dir
-   * however the config parser should take 
-   * care of duplicates 
-   */
-  if (!_dbus_string_append (&servicedir_path, DBUS_DATADIR":"))
-        goto oom;
+  i = 0;
+  argv[i] = "launchctl";
+  ++i;
+  argv[i] = "getenv";
+  ++i;
+  argv[i] = (char*)launchd_env_var;
+  ++i;
+  argv[i] = NULL;
+  ++i;
+
+  _dbus_assert (i == _DBUS_N_ELEMENTS (argv));
 
-  if (xdg_data_home != NULL)
+  if (!_read_subprocess_line_argv(argv[0], TRUE, argv, socket_path, error))
     {
-      if (!_dbus_string_append (&servicedir_path, xdg_data_home))
-        goto oom;
+      return FALSE;
     }
-  else
-    {
-      const DBusString *homedir;
-      DBusString local_share;
-
-      if (!_dbus_homedir_from_current_process (&homedir))
-        goto oom;
-       
-      if (!_dbus_string_append (&servicedir_path, _dbus_string_get_const_data (homedir)))
-        goto oom;
 
-      _dbus_string_init_const (&local_share, "/.local/share");
-      if (!_dbus_concat_dir_and_file (&servicedir_path, &local_share))
-        goto oom;
+  /* no error, but no result either */
+  if (_dbus_string_get_length(socket_path) == 0)
+    {
+      return FALSE;
     }
 
-  if (!_dbus_split_paths_and_append (&servicedir_path, 
-                                     DBUS_UNIX_STANDARD_SESSION_SERVICEDIR, 
-                                     dirs))
-    goto oom;
-
-  _dbus_string_free (&servicedir_path);  
+  /* strip the carriage-return */
+  _dbus_string_shorten(socket_path, 1);
   return TRUE;
-
- oom:
-  _dbus_string_free (&servicedir_path);
+#else /* DBUS_ENABLE_LAUNCHD */
+  dbus_set_error(error, DBUS_ERROR_NOT_SUPPORTED,
+                "can't lookup socket from launchd; launchd support not compiled in");
   return FALSE;
+#endif
 }
 
-
-/**
- * Returns the standard directories for a system bus to look for service 
- * activation files 
- *
- * On UNIX this should be the standard xdg freedesktop.org data directories:
- *
- * XDG_DATA_DIRS=${XDG_DATA_DIRS-/usr/local/share:/usr/share}
- *
- * and
- *
- * DBUS_DATADIR
- *
- * On Windows there is no system bus and this function can return nothing.
- *
- * @param dirs the directory list we are returning
- * @returns #FALSE on OOM 
- */
-
-dbus_bool_t 
-_dbus_get_standard_system_servicedirs (DBusList **dirs)
+#ifdef DBUS_ENABLE_LAUNCHD
+static dbus_bool_t
+_dbus_lookup_session_address_launchd (DBusString *address, DBusError  *error)
 {
-  const char *xdg_data_dirs;
-  DBusString servicedir_path;
+  dbus_bool_t valid_socket;
+  DBusString socket_path;
 
-  if (!_dbus_string_init (&servicedir_path))
-    return FALSE;
+  if (_dbus_check_setuid ())
+    {
+      dbus_set_error_const (error, DBUS_ERROR_NOT_SUPPORTED,
+                            "Unable to find launchd socket when setuid");
+      return FALSE;
+    }
+
+  if (!_dbus_string_init (&socket_path))
+    {
+      _DBUS_SET_OOM (error);
+      return FALSE;
+    }
 
-  xdg_data_dirs = _dbus_getenv ("XDG_DATA_DIRS");
+  valid_socket = _dbus_lookup_launchd_socket (&socket_path, "DBUS_LAUNCHD_SESSION_BUS_SOCKET", error);
 
-  if (xdg_data_dirs != NULL)
+  if (dbus_error_is_set(error))
     {
-      if (!_dbus_string_append (&servicedir_path, xdg_data_dirs))
-        goto oom;
+      _dbus_string_free(&socket_path);
+      return FALSE;
+    }
 
-      if (!_dbus_string_append (&servicedir_path, ":"))
-        goto oom;
+  if (!valid_socket)
+    {
+      dbus_set_error(error, "no socket path",
+                "launchd did not provide a socket path, "
+                "verify that org.freedesktop.dbus-session.plist is loaded!");
+      _dbus_string_free(&socket_path);
+      return FALSE;
     }
-  else
+  if (!_dbus_string_append (address, "unix:path="))
     {
-      if (!_dbus_string_append (&servicedir_path, "/usr/local/share:/usr/share:"))
-        goto oom;
+      _DBUS_SET_OOM (error);
+      _dbus_string_free(&socket_path);
+      return FALSE;
+    }
+  if (!_dbus_string_copy (&socket_path, 0, address,
+                          _dbus_string_get_length (address)))
+    {
+      _DBUS_SET_OOM (error);
+      _dbus_string_free(&socket_path);
+      return FALSE;
     }
 
-  /* 
-   * add configured datadir to defaults
-   * this may be the same as an xdg dir
-   * however the config parser should take 
-   * care of duplicates 
-   */
-  if (!_dbus_string_append (&servicedir_path, DBUS_DATADIR":"))
-        goto oom;
-
-  if (!_dbus_split_paths_and_append (&servicedir_path, 
-                                     DBUS_UNIX_STANDARD_SYSTEM_SERVICEDIR, 
-                                     dirs))
-    goto oom;
-
-  _dbus_string_free (&servicedir_path);  
+  _dbus_string_free(&socket_path);
   return TRUE;
-
- oom:
-  _dbus_string_free (&servicedir_path);
-  return FALSE;
-}
-
-/**
- * Append the absolute path of the system.conf file
- * (there is no system bus on Windows so this can just
- * return FALSE and print a warning or something)
- * 
- * @param str the string to append to
- * @returns #FALSE if no memory
- */
-dbus_bool_t
-_dbus_append_system_config_file (DBusString *str)
-{
-  return _dbus_string_append (str, DBUS_SYSTEM_CONFIG_FILE);
 }
+#endif
 
 /**
- * Append the absolute path of the session.conf file.
- * 
- * @param str the string to append to
- * @returns #FALSE if no memory
+ * Determines the address of the session bus by querying a
+ * platform-specific method.
+ *
+ * The first parameter will be a boolean specifying whether
+ * or not a dynamic session lookup is supported on this platform.
+ *
+ * If supported is TRUE and the return value is #TRUE, the
+ * address will be  appended to @p address.
+ * If a failure happens, returns #FALSE and sets an error in
+ * @p error.
+ *
+ * If supported is FALSE, ignore the return value.
+ *
+ * @param supported returns whether this method is supported
+ * @param address a DBusString where the address can be stored
+ * @param error a DBusError to store the error in case of failure
+ * @returns #TRUE on success, #FALSE if an error happened
  */
 dbus_bool_t
-_dbus_append_session_config_file (DBusString *str)
+_dbus_lookup_session_address (dbus_bool_t *supported,
+                              DBusString  *address,
+                              DBusError   *error)
 {
-  return _dbus_string_append (str, DBUS_SESSION_CONFIG_FILE);
+#ifdef DBUS_ENABLE_LAUNCHD
+  *supported = TRUE;
+  return _dbus_lookup_session_address_launchd (address, error);
+#else
+  /* On non-Mac Unix platforms, if the session address isn't already
+   * set in DBUS_SESSION_BUS_ADDRESS environment variable, we punt and
+   * fall back to the autolaunch: global default; see
+   * init_session_address in dbus/dbus-bus.c. */
+  *supported = FALSE;
+  return TRUE;
+#endif
 }
 
 /**
@@ -3261,7 +3727,7 @@ _dbus_append_session_config_file (DBusString *str)
  * caches should be nuked. Of course any caches that need explicit reload
  * are probably broken, but c'est la vie.
  *
- * 
+ *
  */
 void
 _dbus_flush_caches (void)
@@ -3276,10 +3742,10 @@ _dbus_flush_caches (void)
  *
  * On UNIX the directory is ~/.dbus-keyrings while on Windows it should probably
  * be something else, since the dotfile convention is not normal on Windows.
- * 
+ *
  * @param directory string to append directory to
  * @param credentials credentials the directory should be for
- *  
+ *
  * @returns #FALSE on no memory
  */
 dbus_bool_t
@@ -3289,10 +3755,10 @@ _dbus_append_keyring_directory_for_credentials (DBusString      *directory,
   DBusString homedir;
   DBusString dotdir;
   dbus_uid_t uid;
-  
+
   _dbus_assert (credentials != NULL);
   _dbus_assert (!_dbus_credentials_are_anonymous (credentials));
-  
+
   if (!_dbus_string_init (&homedir))
     return FALSE;
 
@@ -3301,11 +3767,11 @@ _dbus_append_keyring_directory_for_credentials (DBusString      *directory,
 
   if (!_dbus_homedir_from_uid (uid, &homedir))
     goto failed;
-  
-#ifdef DBUS_BUILD_TESTS
+
+#ifdef DBUS_ENABLE_EMBEDDED_TESTS
   {
     const char *override;
-    
+
     override = _dbus_getenv ("DBUS_TEST_HOMEDIR");
     if (override != NULL && *override != '\0')
       {
@@ -3318,6 +3784,8 @@ _dbus_append_keyring_directory_for_credentials (DBusString      *directory,
       }
     else
       {
+        /* Not strictly thread-safe, but if we fail at thread-safety here,
+         * the worst that will happen is some extra warnings. */
         static dbus_bool_t already_warned = FALSE;
         if (!already_warned)
           {
@@ -3332,7 +3800,7 @@ _dbus_append_keyring_directory_for_credentials (DBusString      *directory,
   if (!_dbus_concat_dir_and_file (&homedir,
                                   &dotdir))
     goto failed;
-  
+
   if (!_dbus_string_copy (&homedir, 0,
                           directory, _dbus_string_get_length (directory))) {
     goto failed;
@@ -3340,12 +3808,26 @@ _dbus_append_keyring_directory_for_credentials (DBusString      *directory,
 
   _dbus_string_free (&homedir);
   return TRUE;
-  
- failed: 
+
+ failed:
   _dbus_string_free (&homedir);
   return FALSE;
 }
 
+//PENDING(kdab) docs
+dbus_bool_t
+_dbus_daemon_publish_session_bus_address (const char* addr,
+                                          const char *scope)
+{
+  return TRUE;
+}
+
+//PENDING(kdab) docs
+void
+_dbus_daemon_unpublish_session_bus_address (void)
+{
+
+}
 
 /**
  * See if errno is EAGAIN or EWOULDBLOCK (this has to be done differently
@@ -3359,4 +3841,251 @@ _dbus_get_is_errno_eagain_or_ewouldblock (void)
   return errno == EAGAIN || errno == EWOULDBLOCK;
 }
 
+/**
+ * Removes a directory; Directory must be empty
+ *
+ * @param filename directory filename
+ * @param error initialized error object
+ * @returns #TRUE on success
+ */
+dbus_bool_t
+_dbus_delete_directory (const DBusString *filename,
+                        DBusError        *error)
+{
+  const char *filename_c;
+
+  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+  filename_c = _dbus_string_get_const_data (filename);
+
+  if (rmdir (filename_c) != 0)
+    {
+      dbus_set_error (error, DBUS_ERROR_FAILED,
+                      "Failed to remove directory %s: %s\n",
+                      filename_c, _dbus_strerror (errno));
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+/**
+ *  Checks whether file descriptors may be passed via the socket
+ *
+ *  @param fd the socket
+ *  @return TRUE when fd passing over this socket is supported
+ *
+ */
+dbus_bool_t
+_dbus_socket_can_pass_unix_fd(int fd) {
+
+#ifdef SCM_RIGHTS
+  union {
+    struct sockaddr sa;
+    struct sockaddr_storage storage;
+    struct sockaddr_un un;
+  } sa_buf;
+
+  socklen_t sa_len = sizeof(sa_buf);
+
+  _DBUS_ZERO(sa_buf);
+
+  if (getsockname(fd, &sa_buf.sa, &sa_len) < 0)
+    return FALSE;
+
+  return sa_buf.sa.sa_family == AF_UNIX;
+
+#else
+  return FALSE;
+
+#endif
+}
+
+/**
+ * Closes all file descriptors except the first three (i.e. stdin,
+ * stdout, stderr).
+ */
+void
+_dbus_close_all (void)
+{
+  int maxfds, i;
+
+#ifdef __linux__
+  DIR *d;
+
+  /* On Linux we can optimize this a bit if /proc is available. If it
+     isn't available, fall back to the brute force way. */
+
+  d = opendir ("/proc/self/fd");
+  if (d)
+    {
+      for (;;)
+        {
+          struct dirent buf, *de;
+          int k, fd;
+          long l;
+          char *e = NULL;
+
+          k = readdir_r (d, &buf, &de);
+          if (k != 0 || !de)
+            break;
+
+          if (de->d_name[0] == '.')
+            continue;
+
+          errno = 0;
+          l = strtol (de->d_name, &e, 10);
+          if (errno != 0 || e == NULL || *e != '\0')
+            continue;
+
+          fd = (int) l;
+          if (fd < 3)
+            continue;
+
+          if (fd == dirfd (d))
+            continue;
+
+          close (fd);
+        }
+
+      closedir (d);
+      return;
+    }
+#endif
+
+  maxfds = sysconf (_SC_OPEN_MAX);
+
+  /* Pick something reasonable if for some reason sysconf says
+   * unlimited.
+   */
+  if (maxfds < 0)
+    maxfds = 1024;
+
+  /* close all inherited fds */
+  for (i = 3; i < maxfds; i++)
+    close (i);
+}
+
+/**
+ * **NOTE**: If you modify this function, please also consider making
+ * the corresponding change in GLib.  See
+ * glib/gutils.c:g_check_setuid().
+ *
+ * Returns TRUE if the current process was executed as setuid (or an
+ * equivalent __libc_enable_secure is available).  See:
+ * http://osdir.com/ml/linux.lfs.hardened/2007-04/msg00032.html
+ */
+dbus_bool_t
+_dbus_check_setuid (void)
+{
+  /* TODO: get __libc_enable_secure exported from glibc.
+   * See http://www.openwall.com/lists/owl-dev/2012/08/14/1
+   */
+#if 0 && defined(HAVE_LIBC_ENABLE_SECURE)
+  {
+    /* See glibc/include/unistd.h */
+    extern int __libc_enable_secure;
+    return __libc_enable_secure;
+  }
+#elif defined(HAVE_ISSETUGID)
+  /* BSD: http://www.freebsd.org/cgi/man.cgi?query=issetugid&sektion=2 */
+  return issetugid ();
+#else
+  uid_t ruid, euid, suid; /* Real, effective and saved user ID's */
+  gid_t rgid, egid, sgid; /* Real, effective and saved group ID's */
+
+  /* We call into this function from _dbus_threads_init_platform_specific()
+   * to make sure these are initialized before we start threading. */
+  static dbus_bool_t check_setuid_initialised;
+  static dbus_bool_t is_setuid;
+
+  if (_DBUS_UNLIKELY (!check_setuid_initialised))
+    {
+#ifdef HAVE_GETRESUID
+      if (getresuid (&ruid, &euid, &suid) != 0 ||
+          getresgid (&rgid, &egid, &sgid) != 0)
+#endif /* HAVE_GETRESUID */
+        {
+          suid = ruid = getuid ();
+          sgid = rgid = getgid ();
+          euid = geteuid ();
+          egid = getegid ();
+        }
+
+      check_setuid_initialised = TRUE;
+      is_setuid = (ruid != euid || ruid != suid ||
+                   rgid != egid || rgid != sgid);
+
+    }
+  return is_setuid;
+#endif
+}
+
+/**
+ * Read the address from the socket and append it to the string
+ *
+ * @param fd the socket
+ * @param address
+ * @param error return location for error code
+ */
+dbus_bool_t
+_dbus_append_address_from_socket (int         fd,
+                                  DBusString *address,
+                                  DBusError  *error)
+{
+  union {
+      struct sockaddr sa;
+      struct sockaddr_storage storage;
+      struct sockaddr_un un;
+      struct sockaddr_in ipv4;
+      struct sockaddr_in6 ipv6;
+  } socket;
+  char hostip[INET6_ADDRSTRLEN];
+  int size = sizeof (socket);
+
+  if (getsockname (fd, &socket.sa, &size))
+    goto err;
+
+  switch (socket.sa.sa_family)
+    {
+    case AF_UNIX:
+      if (socket.un.sun_path[0]=='\0')
+        {
+          if (_dbus_string_append_printf (address, "unix:abstract=%s", &(socket.un.sun_path[1])))
+            return TRUE;
+        }
+      else
+        {
+          if (_dbus_string_append_printf (address, "unix:path=%s", socket.un.sun_path))
+            return TRUE;
+        }
+      break;
+    case AF_INET:
+      if (inet_ntop (AF_INET, &socket.ipv4.sin_addr, hostip, sizeof (hostip)))
+        if (_dbus_string_append_printf (address, "tcp:family=ipv4,host=%s,port=%u",
+                   hostip, ntohs (socket.ipv4.sin_port)))
+          return TRUE;
+      break;
+#ifdef AF_INET6
+    case AF_INET6:
+      if (inet_ntop (AF_INET6, &socket.ipv6.sin6_addr, hostip, sizeof (hostip)))
+        if (_dbus_string_append_printf (address, "tcp:family=ipv6,host=%s,port=%u",
+                   hostip, ntohs (socket.ipv6.sin6_port)))
+          return TRUE;
+      break;
+#endif
+    default:
+      dbus_set_error (error,
+                      _dbus_error_from_errno (EINVAL),
+                      "Failed to read address from socket: Unknown socket type.");
+      return FALSE;
+    }
+ err:
+  dbus_set_error (error,
+                  _dbus_error_from_errno (errno),
+                  "Failed to open socket: %s",
+                  _dbus_strerror (errno));
+  return FALSE;
+}
+
 /* tests in dbus-sysdeps-util.c */