#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>
#include "sd-daemon.h"
+#if !DBUS_USE_SYNC
+#include <pthread.h>
+#endif
+
#ifndef O_BINARY
#define O_BINARY 0
#endif
*
* This will set FD_CLOEXEC for the sockets returned.
*
- * @oaram fds the file descriptors
+ * @param fds the file descriptors
* @param error return location for errors
* @returns the number of file descriptors
*/
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;
_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;
}
#if !DBUS_USE_SYNC
-_DBUS_DEFINE_GLOBAL_LOCK (atomic);
+/* 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
/**
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
}
#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
}
#else
dbus_int32_t res;
- _DBUS_LOCK (atomic);
+ pthread_mutex_lock (&atomic_mutex);
res = atomic->value;
- _DBUS_UNLOCK (atomic);
+ pthread_mutex_unlock (&atomic_mutex);
+
return res;
#endif
}
* 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;
}
/**
+ * Get current time, as in gettimeofday(). Never uses the monotonic
+ * clock.
+ *
+ * @param tv_sec return location for number of seconds
+ * @param tv_usec return location for number of microseconds
+ */
+void
+_dbus_get_real_time (long *tv_sec,
+ long *tv_usec)
+{
+ struct timeval t;
+
+ gettimeofday (&t, NULL);
+
+ if (tv_sec)
+ *tv_sec = t.tv_sec;
+ if (tv_usec)
+ *tv_usec = t.tv_usec;
+}
+
+/**
* Creates a directory; succeeds if the directory
* is created or already existed.
*
* (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
char static_buf[1024];
int bufsize = sizeof (static_buf);
int len;
+ va_list args_copy;
- len = vsnprintf (static_buf, bufsize, format, args);
+ 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
* 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. */
- if (vsnprintf (static_buf, 1, format, args) == 1)
+ 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.
if (buf == NULL)
return -1;
- len = vsnprintf (buf, bufsize, format, args);
+ 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
return tmpdir;
}
+#if defined(DBUS_ENABLE_X11_AUTOLAUNCH) || defined(DBUS_ENABLE_LAUNCHD)
/**
* Execute a subprocess, returning up to 1024 bytes of output
* into @p result.
/* set-up stdXXX */
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 (result_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);
_dbus_close_all ();
return retval;
}
+#endif
/**
* Returns the address of a new session bus.
* 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
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;
/**
* 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_ASSERT_ERROR_IS_CLEAR (error);
+ if (_dbus_check_setuid ())
+ {
+ dbus_set_error_const (error, DBUS_ERROR_NOT_SUPPORTED,
+ "Unable to find launchd socket when setuid");
+ return FALSE;
+ }
+
i = 0;
argv[i] = "launchctl";
++i;
dbus_bool_t valid_socket;
DBusString socket_path;
+ 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);
if (!_dbus_homedir_from_uid (uid, &homedir))
goto failed;
-#ifdef DBUS_BUILD_TESTS
+#ifdef DBUS_ENABLE_EMBEDDED_TESTS
{
const char *override;
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 */
+
+ 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 */