summaryrefslogtreecommitdiffstats
path: root/dbus/dbus-sysdeps-unix.c
diff options
context:
space:
mode:
Diffstat (limited to 'dbus/dbus-sysdeps-unix.c')
-rw-r--r--dbus/dbus-sysdeps-unix.c332
1 files changed, 230 insertions, 102 deletions
diff --git a/dbus/dbus-sysdeps-unix.c b/dbus/dbus-sysdeps-unix.c
index 42aa9674..f0f1e706 100644
--- a/dbus/dbus-sysdeps-unix.c
+++ b/dbus/dbus-sysdeps-unix.c
@@ -18,7 +18,7 @@
*
* 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
*
*/
@@ -1373,9 +1373,9 @@ write_credentials_byte (int server_fd,
int bytes_written;
char buf[1] = { '\0' };
#if defined(HAVE_CMSGCRED)
- struct {
+ union {
struct cmsghdr hdr;
- struct cmsgcred cred;
+ char cred[CMSG_SPACE (sizeof (struct cmsgcred))];
} cmsg;
struct iovec iov;
struct msghdr msg;
@@ -1386,10 +1386,10 @@ write_credentials_byte (int server_fd,
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
- msg.msg_control = &cmsg;
- msg.msg_controllen = sizeof (cmsg);
+ msg.msg_control = (caddr_t) &cmsg;
+ msg.msg_controllen = CMSG_SPACE (sizeof (struct cmsgcred));
_DBUS_ZERO(cmsg);
- cmsg.hdr.cmsg_len = sizeof (cmsg);
+ cmsg.hdr.cmsg_len = CMSG_LEN (sizeof (struct cmsgcred));
cmsg.hdr.cmsg_level = SOL_SOCKET;
cmsg.hdr.cmsg_type = SCM_CREDS;
#endif
@@ -1461,13 +1461,10 @@ _dbus_read_credentials_socket (int client_fd,
dbus_pid_t pid_read;
int bytes_read;
- uid_read = DBUS_UID_UNSET;
- pid_read = DBUS_PID_UNSET;
-
#ifdef HAVE_CMSGCRED
- struct {
+ union {
struct cmsghdr hdr;
- struct cmsgcred cred;
+ char cred[CMSG_SPACE (sizeof (struct cmsgcred))];
} cmsg;
#elif defined(LOCAL_CREDS)
@@ -1477,6 +1474,9 @@ _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
@@ -1504,8 +1504,8 @@ _dbus_read_credentials_socket (int client_fd,
#if defined(HAVE_CMSGCRED) || defined(LOCAL_CREDS)
_DBUS_ZERO(cmsg);
- msg.msg_control = &cmsg;
- msg.msg_controllen = sizeof (cmsg);
+ msg.msg_control = (caddr_t) &cmsg;
+ msg.msg_controllen = CMSG_SPACE (sizeof (struct cmsgcred));
#endif
again:
@@ -1543,7 +1543,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");
@@ -1570,8 +1571,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);
+ 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;
@@ -1945,8 +1949,10 @@ fill_user_info (DBusUserInfo *info,
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)
{
@@ -1958,7 +1964,25 @@ fill_user_info (DBusUserInfo *info,
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);
@@ -1971,14 +1995,22 @@ fill_user_info (DBusUserInfo *info,
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;
+ }
}
}
@@ -3235,83 +3267,73 @@ _dbus_get_tmpdir(void)
}
/**
- * 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;
-
- _dbus_assert (i == _DBUS_N_ELEMENTS (argv));
+ /* 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 (address);
+ orig_len = _dbus_string_get_length (result);
#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;
}
@@ -3319,10 +3341,10 @@ _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;
}
@@ -3340,7 +3362,7 @@ _dbus_get_autolaunch_address (DBusString *address,
_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 */
@@ -3348,7 +3370,7 @@ _dbus_get_autolaunch_address (DBusString *address,
if (dup2 (fd, 0) == -1)
_exit (1);
- if (dup2 (address_pipe[WRITE_END], 1) == -1)
+ if (dup2 (result_pipe[WRITE_END], 1) == -1)
_exit (1);
if (dup2 (errors_pipe[WRITE_END], 2) == -1)
_exit (1);
@@ -3363,25 +3385,39 @@ _dbus_get_autolaunch_address (DBusString *address,
for (i = 3; i < maxfds; i++)
close (i);
- 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
{
- ret = _dbus_read (address_pipe[READ_END], address, 1024);
+ ret = _dbus_read (result_pipe[READ_END], result, 1024);
}
while (ret > 0);
@@ -3394,47 +3430,108 @@ _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);
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;
+}
+
+/**
+ * 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 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 (DBusString *address,
+ DBusError *error)
+{
+ static char *argv[6];
+ int i;
+ DBusString uuid;
+ dbus_bool_t retval;
+
+ _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;
+
+ _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;
}
@@ -3470,6 +3567,37 @@ _dbus_read_local_machine_uuid (DBusGUID *machine_id,
#define DBUS_UNIX_STANDARD_SESSION_SERVICEDIR "/dbus-1/services"
#define DBUS_UNIX_STANDARD_SYSTEM_SERVICEDIR "/dbus-1/system-services"
+/**
+ * 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_lookup_session_address (dbus_bool_t *supported,
+ DBusString *address,
+ DBusError *error)
+{
+ /* 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;
+}
/**
* Returns the standard directories for a session bus to look for service